1.. _printf_behavior: 2 3==================================== 4Printf Behavior Under All Conditions 5==================================== 6 7Introduction: 8============= 9On the "defining undefined behavior" page, I said you should write down your 10decisions regarding undefined behavior in your functions. This is that document 11for my printf implementation. 12 13Unless otherwise specified, the functionality described is aligned with the ISO 14C standard and POSIX standard. If any behavior is not mentioned here, it should 15be assumed to follow the behavior described in those standards. 16 17The LLVM-libc codebase is under active development, and may change. This 18document was last updated [January 8, 2024] by [michaelrj] and may 19not be accurate after this point. 20 21The behavior of LLVM-libc's printf is heavily influenced by compile-time flags. 22Make sure to check what flags are defined before filing a bug report. It is also 23not relevant to any other libc implementation of printf, which may or may not 24share the same behavior. 25 26This document assumes familiarity with the definition of the printf function and 27is intended as a reference, not a replacement for the original standards. 28 29-------------- 30General Flags: 31-------------- 32These compile-time flags will change the behavior of LLVM-libc's printf when it 33is compiled. Combinations of flags that are incompatible will be marked. 34 35LIBC_COPT_STDIO_USE_SYSTEM_FILE 36------------------------------- 37When set, this flag changes fprintf and printf to use the FILE API from the 38system's libc, instead of LLVM-libc's internal FILE API. This is set by default 39when LLVM-libc is built in overlay mode. 40 41LIBC_COPT_PRINTF_DISABLE_INDEX_MODE 42----------------------------------- 43When set, this flag disables support for the POSIX "%n$" format, hereafter 44referred to as "index mode"; conversions using the index mode format will be 45treated as invalid. This reduces code size. 46 47LIBC_COPT_PRINTF_INDEX_ARR_LEN 48------------------------------ 49This flag takes a positive integer value, defaulting to 128. This flag 50determines the number of entries the parser's type descriptor array has. This is 51used in index mode to avoid re-parsing the format string to determine types when 52an index lower than the previously specified one is requested. This has no 53effect when index mode is disabled. 54 55LIBC_COPT_PRINTF_DISABLE_WRITE_INT 56---------------------------------- 57When set, this flag disables support for the C Standard "%n" conversion; any 58"%n" conversion will be treated as invalid. This is set by default to improve 59security. 60 61LIBC_COPT_PRINTF_DISABLE_FLOAT 62------------------------------ 63When set, this flag disables support for floating point numbers and all their 64conversions (%a, %f, %e, %g); any floating point number conversion will be 65treated as invalid. This reduces code size. 66 67LIBC_COPT_PRINTF_DISABLE_FIXED_POINT 68------------------------------------ 69When set, this flag disables support for fixed point numbers and all their 70conversions (%r, %k); any fixed point number conversion will be treated as 71invalid. This reduces code size. This has no effect if the current compiler does 72not support fixed point numbers. 73 74LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS 75---------------------------------- 76When set, this flag disables the nullptr checks in %n and %s. 77 78LIBC_COPT_PRINTF_CONV_ATLAS 79--------------------------- 80When set, this flag changes the include path for the "converter atlas" which is 81a header that includes all the files containing the conversion functions. This 82is not recommended to be set without careful consideration. 83 84LIBC_COPT_PRINTF_HEX_LONG_DOUBLE 85-------------------------------- 86When set, this flag replaces all decimal long double conversions (%Lf, %Le, %Lg) 87with hexadecimal long double conversions (%La). This will improve performance 88significantly, but may cause some tests to fail. This has no effect when float 89conversions are disabled. 90 91-------------------------------- 92Float Conversion Internal Flags: 93-------------------------------- 94The following floating point conversion flags are provided for reference, but 95are not recommended to be adjusted except by persons familiar with the Printf 96Ryu Algorithm. Additionally they have no effect when float conversions are 97disabled. 98 99LIBC_COPT_FLOAT_TO_STR_NO_SPECIALIZE_LD 100--------------------------------------- 101This flag disables the separate long double conversion implementation. It is 102not based on the Ryu algorithm, instead generating the digits by 103multiplying/dividing the written-out number by 10^9 to get blocks. It's 104significantly faster than INT_CALC, only about 10x slower than MEGA_TABLE, 105and is small in binary size. Its downside is that it always calculates all 106of the digits above the decimal point, making it slightly inefficient for %e 107calls with large exponents. This is the default. This specialization overrides 108other flags, so this flag must be set for other flags to effect the long double 109behavior. 110 111LIBC_COPT_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE 112------------------------------------------------- 113When set, the float to string decimal conversion algorithm will use a larger 114table to accelerate long double conversions. This larger table is around 5MB of 115size when compiled. 116 117LIBC_COPT_FLOAT_TO_STR_USE_DYADIC_FLOAT 118--------------------------------------- 119When set, the float to string decimal conversion algorithm will use dyadic 120floats instead of a table when performing floating point conversions. This 121results in ~50 digits of accuracy in the result, then zeroes for the remaining 122values. This may improve performance but may also cause some tests to fail. The 123flag ending in _LD is the same, but only applies to long double decimal 124conversions. 125 126LIBC_COPT_FLOAT_TO_STR_USE_INT_CALC 127----------------------------------- 128When set, the float to string decimal conversion algorithm will use wide 129integers instead of a table when performing floating point conversions. This 130gives the same results as the table, but is very slow at the extreme ends of 131the long double range. 132 133LIBC_COPT_FLOAT_TO_STR_NO_TABLE 134------------------------------- 135When set, the float to string decimal conversion algorithm will not use either 136the mega table or the normal table for any conversions. Instead it will set 137algorithmic constants to improve performance when using calculation algorithms. 138If this flag is set without any calculation algorithm flag set, an error will 139occur. 140 141-------- 142Parsing: 143-------- 144 145When printf encounters an invalid conversion specification, the entire 146conversion specification will be passed literally to the output string. 147As an example, printf("%Z") would display "%Z". 148 149If an index mode conversion is requested for index "n" and there exists a number 150in [1,n) that does not have a conversion specified in the format string, then 151the conversion for index "n" is considered invalid. 152 153If a non-index mode (also referred to as sequential mode) conversion is 154specified after an index mode conversion, the next argument will be read but the 155current index will not be incremented. From this point on, the arguments 156selected by each conversion may or may not be correct. This is considered 157dangerously undefined and may change without warning. 158 159If a conversion specification is provided an invalid type modifier, that type 160modifier will be ignored, and the default type for that conversion will be used. 161In the case of the length modifier "L" and integer conversions, it will be 162treated as if it was "ll" (lowercase LL). For this purpose the list of integer 163conversions is d, i, u, o, x, X, b, B, n. 164 165If a conversion specification ending in % has any options that consume arguments 166(e.g. "%*.*%") those arguments will be consumed as normal, but their values will 167be ignored. 168 169If a conversion specification ends in a null byte ('\0') then it shall be 170treated as an invalid conversion followed by a null byte. 171 172If a number passed as a field width or precision value is out of range for an 173int, then it will be treated as the largest value in the int range 174(e.g. "%-999999999999.999999999999s" is the same as "%-2147483647.2147483647s"). 175 176If the field width is set to INT_MIN by using the '*' form, 177e.g. printf("%*d", INT_MIN, 1), it will be treated as INT_MAX, since -INT_MIN is 178not representable as an int. 179 180If a number passed as a bit width is less than or equal to zero, the conversion 181is considered invalid. If the provided bit width is larger than the width of 182uintmax_t, it will be clamped to the width of uintmax_t. 183 184---------- 185Conversion 186---------- 187Any conversion specification that contains a flag or option that it does not 188have defined behavior for will ignore that flag or option (e.g. %.5c is the same 189as %c). 190 191If a conversion specification ends in %, then it will be treated as if it is 192"%%", ignoring all options. 193 194If a null pointer is passed to a %s conversion specification and null pointer 195checks are enabled, it will be treated as if the provided string is "null". 196 197If a null pointer is passed to a %n conversion specification and null pointer 198checks are enabled, the conversion will fail and printf will return a negative 199value. 200 201If a null pointer is passed to a %p conversion specification, the string 202"(nullptr)" will be returned instead of an integer value. 203 204The %p conversion will display any non-null pointer as if it was a uintptr value 205passed to a "%#tx" conversion, with all other options remaining the same as the 206original conversion. 207 208The %p conversion will display a null pointer as if it was the string 209"(nullptr)" passed to a "%s" conversion, with all other options remaining the 210same as the original conversion. 211 212The %r, %R, %k, and %K fixed point number format specifiers are accepted as 213defined in ISO/IEC TR 18037 (the fixed point number extension). These are 214available when the compiler is detected as having support for fixed point 215numbers and the LIBC_COPT_PRINTF_DISABLE_FIXED_POINT flag is not set. 216 217The %m conversion will behave as specified by POSIX for syslog: It takes no 218arguments, and outputs the result of strerror(errno). Additionally, to match 219existing printf behaviors, it will behave as if it is a %s string conversion for 220the purpose of all options, except for the alt form flag. If the alt form flag 221is specified, %m will instead output a string matching the macro name of the 222value of errno (e.g. "ERANGE" for errno = ERANGE), again treating it as a string 223conversion. If there is no corresponding macro, then alt form %m will print the 224value of errno as an integer with the %d format, including all options. If 225errno = 0 and alt form is specified, the conversion will be a string conversion 226on "0" for simplicity of implementation. This matches what other libcs 227implementing this feature have done. 228