diff --git a/libc/src/__support/arg_list.h b/libc/src/__support/arg_list.h --- a/libc/src/__support/arg_list.h +++ b/libc/src/__support/arg_list.h @@ -12,6 +12,7 @@ #include "src/__support/common.h" #include +#include namespace __llvm_libc { namespace internal { @@ -32,6 +33,33 @@ template LIBC_INLINE T next_var() { return va_arg(vlist, T); } }; +// Used for testing things that use an ArgList when it's impossible to know what +// the arguments should be ahead of time. An example of this would be fuzzing, +// since a function passed a random input could request unpredictable arguments. +class MockArgList { + size_t arg_counter = 0; + +public: + LIBC_INLINE MockArgList() = default; + LIBC_INLINE MockArgList(va_list) { ; } + LIBC_INLINE MockArgList(MockArgList &other) { + arg_counter = other.arg_counter; + } + LIBC_INLINE ~MockArgList() = default; + + LIBC_INLINE MockArgList &operator=(MockArgList &rhs) { + arg_counter = rhs.arg_counter; + return *this; + } + + template LIBC_INLINE T next_var() { + ++arg_counter; + return T(arg_counter); + } + + size_t read_count() const { return arg_counter; } +}; + } // namespace internal } // namespace __llvm_libc diff --git a/libc/src/stdio/printf_core/parser.h b/libc/src/stdio/printf_core/parser.h --- a/libc/src/stdio/printf_core/parser.h +++ b/libc/src/stdio/printf_core/parser.h @@ -20,24 +20,30 @@ namespace __llvm_libc { namespace printf_core { +#ifndef LIBC_COPT_MOCK_ARG_LIST +using ArgProvider = internal::ArgList; +#else // not defined LIBC_COPT_MOCK_ARG_LIST +using ArgProvider = internal::MockArgList; +#endif // LIBC_COPT_MOCK_ARG_LIST + class Parser { const char *__restrict str; size_t cur_pos = 0; - internal::ArgList args_cur; + ArgProvider args_cur; #ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE // args_start stores the start of the va_args, which is allows getting the // value of arguments that have already been passed. args_index is tracked so // that we know which argument args_cur is on. - internal::ArgList args_start; + ArgProvider args_start; size_t args_index = 1; // Defined in printf_config.h static constexpr size_t DESC_ARR_LEN = LIBC_COPT_PRINTF_INDEX_ARR_LEN; - // desc_arr stores the sizes of the variables in the ArgList. This is used in - // index mode to reduce repeated string parsing. The sizes are stored as + // desc_arr stores the sizes of the variables in the ArgProvider. This is used + // in index mode to reduce repeated string parsing. The sizes are stored as // TypeDesc objects, which store the size as well as minimal type information. // This is necessary because some systems separate the floating point and // integer values in va_args. @@ -49,10 +55,10 @@ public: #ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE - LIBC_INLINE Parser(const char *__restrict new_str, internal::ArgList &args) + LIBC_INLINE Parser(const char *__restrict new_str, ArgProvider &args) : str(new_str), args_cur(args), args_start(args) {} #else - LIBC_INLINE Parser(const char *__restrict new_str, internal::ArgList &args) + LIBC_INLINE Parser(const char *__restrict new_str, ArgProvider &args) : str(new_str), args_cur(args) {} #endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE @@ -111,7 +117,7 @@ return get_next_arg_value(); } - // the ArgList can only return the next item in the list. This function is + // the ArgProvider can only return the next item in the list. This function is // used in index mode when the item that needs to be read is not the next one. // It moves cur_args to the index requested so the the appropriate value may // be read. This may involve parsing the format string, and is in the worst