|
| 1 | +==================================== |
| 2 | +Printf Behavior Under All Conditions |
| 3 | +==================================== |
| 4 | + |
| 5 | +Introduction: |
| 6 | +============= |
| 7 | +On the "defining undefined behavior" page, I said you should write down your |
| 8 | +decisions regarding undefined behavior in your functions. This is that document |
| 9 | +for my printf implementation. |
| 10 | + |
| 11 | +Unless otherwise specified, the functionality described is aligned with the ISO |
| 12 | +C standard and POSIX standard. If any behavior is not mentioned here, it should |
| 13 | +be assumed to follow the behavior described in those standards. |
| 14 | + |
| 15 | +The LLVM-libc codebase is under active development, and may change. This |
| 16 | +document was last updated [August 18, 2023] by [michaelrj] and may |
| 17 | +not be accurate after this point. |
| 18 | + |
| 19 | +The behavior of LLVM-libc's printf is heavily influenced by compile-time flags. |
| 20 | +Make sure to check what flags are defined before filing a bug report. It is also |
| 21 | +not relevant to any other libc implementation of printf, which may or may not |
| 22 | +share the same behavior. |
| 23 | + |
| 24 | +This document assumes familiarity with the definition of the printf function and |
| 25 | +is intended as a reference, not a replacement for the original standards. |
| 26 | + |
| 27 | +-------------- |
| 28 | +General Flags: |
| 29 | +-------------- |
| 30 | +These compile-time flags will change the behavior of LLVM-libc's printf when it |
| 31 | +is compiled. Combinations of flags that are incompatible will be marked. |
| 32 | + |
| 33 | +LIBC_COPT_PRINTF_USE_SYSTEM_FILE |
| 34 | +-------------------------------- |
| 35 | +When set, this flag changes fprintf and printf to use the FILE API from the |
| 36 | +system's libc, instead of LLVM-libc's internal FILE API. This is set by default |
| 37 | +when LLVM-libc is built in overlay mode. |
| 38 | + |
| 39 | +LIBC_COPT_PRINTF_DISABLE_INDEX_MODE |
| 40 | +----------------------------------- |
| 41 | +When set, this flag disables support for the POSIX "%n$" format, hereafter |
| 42 | +referred to as "index mode"; conversions using the index mode format will be |
| 43 | +treated as invalid. This reduces code size. |
| 44 | + |
| 45 | +LIBC_COPT_PRINTF_INDEX_ARR_LEN |
| 46 | +------------------------------ |
| 47 | +This flag takes a positive integer value, defaulting to 128. This flag |
| 48 | +determines the number of entries the parser's type descriptor array has. This is |
| 49 | +used in index mode to avoid re-parsing the format string to determine types when |
| 50 | +an index lower than the previously specified one is requested. This has no |
| 51 | +effect when index mode is disabled. |
| 52 | + |
| 53 | +LIBC_COPT_PRINTF_DISABLE_WRITE_INT |
| 54 | +---------------------------------- |
| 55 | +When set, this flag disables support for the C Standard "%n" conversion; any |
| 56 | +"%n" conversion will be treated as invalid. This is set by default to improve |
| 57 | +security. |
| 58 | + |
| 59 | +LIBC_COPT_PRINTF_DISABLE_FLOAT |
| 60 | +------------------------------ |
| 61 | +When set, this flag disables support for floating point numbers and all their |
| 62 | +conversions (%a, %f, %e, %g); any floating point number conversion will be |
| 63 | +treated as invalid. This reduces code size. |
| 64 | + |
| 65 | +LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS |
| 66 | +---------------------------------- |
| 67 | +When set, this flag disables the nullptr checks in %n and %s. |
| 68 | + |
| 69 | +LIBC_COPT_PRINTF_CONV_ATLAS |
| 70 | +--------------------------- |
| 71 | +When set, this flag changes the include path for the "converter atlas" which is |
| 72 | +a header that includes all the files containing the conversion functions. This |
| 73 | +is not recommended to be set without careful consideration. |
| 74 | + |
| 75 | +LIBC_COPT_PRINTF_HEX_LONG_DOUBLE |
| 76 | +-------------------------------- |
| 77 | +When set, this flag replaces all decimal long double conversions (%Lf, %Le, %Lg) |
| 78 | +with hexadecimal long double conversions (%La). This will improve performance |
| 79 | +significantly, but may cause some tests to fail. This has no effect when float |
| 80 | +conversions are disabled. |
| 81 | + |
| 82 | +-------------------------------- |
| 83 | +Float Conversion Internal Flags: |
| 84 | +-------------------------------- |
| 85 | +The following floating point conversion flags are provided for reference, but |
| 86 | +are not recommended to be adjusted except by persons familiar with the Printf |
| 87 | +Ryu Algorithm. Additionally they have no effect when float conversions are |
| 88 | +disabled. |
| 89 | + |
| 90 | +LIBC_COPT_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE |
| 91 | +------------------------------------------------- |
| 92 | +When set, the float to string decimal conversion algorithm will use a larger |
| 93 | +table to accelerate long double conversions. This larger table is around 5MB of |
| 94 | +size when compiled. This flag is enabled by default in the CMake. |
| 95 | + |
| 96 | +LIBC_COPT_FLOAT_TO_STR_USE_DYADIC_FLOAT(_LD) |
| 97 | +-------------------------------------------- |
| 98 | +When set, the float to string decimal conversion algorithm will use dyadic |
| 99 | +floats instead of a table when performing floating point conversions. This |
| 100 | +results in ~50 digits of accuracy in the result, then zeroes for the remaining |
| 101 | +values. This may improve performance but may also cause some tests to fail. The |
| 102 | +flag ending in _LD is the same, but only applies to long double decimal |
| 103 | +conversions. |
| 104 | + |
| 105 | +LIBC_COPT_FLOAT_TO_STR_USE_INT_CALC |
| 106 | +----------------------------------- |
| 107 | +When set, the float to string decimal conversion algorithm will use wide |
| 108 | +integers instead of a table when performing floating point conversions. This |
| 109 | +gives the same results as the table, but is very slow at the extreme ends of |
| 110 | +the long double range. If no flags are set this is the default behavior for |
| 111 | +long double conversions. |
| 112 | + |
| 113 | +LIBC_COPT_FLOAT_TO_STR_NO_TABLE |
| 114 | +------------------------------- |
| 115 | +When set, the float to string decimal conversion algorithm will not use either |
| 116 | +the mega table or the normal table for any conversions. Instead it will set |
| 117 | +algorithmic constants to improve performance when using calculation algorithms. |
| 118 | +If this flag is set without any calculation algorithm flag set, an error will |
| 119 | +occur. |
| 120 | + |
| 121 | +-------- |
| 122 | +Parsing: |
| 123 | +-------- |
| 124 | + |
| 125 | +When printf encounters an invalid conversion specification, the entire |
| 126 | +conversion specification will be passed literally to the output string. |
| 127 | +As an example, printf("%Z") would display "%Z". |
| 128 | + |
| 129 | +If an index mode conversion is requested for index "n" and there exists a number |
| 130 | +in [1,n) that does not have a conversion specified in the format string, then |
| 131 | +the conversion for index "n" is considered invalid. |
| 132 | + |
| 133 | +If a non-index mode (also referred to as sequential mode) conversion is |
| 134 | +specified after an index mode conversion, the next argument will be read but the |
| 135 | +current index will not be incremented. From this point on, the arguments |
| 136 | +selected by each conversion may or may not be correct. This is considered |
| 137 | +dangerously undefined and may change without warning. |
| 138 | + |
| 139 | +If a conversion specification is provided an invalid type modifier, that type |
| 140 | +modifier will be ignored, and the default type for that conversion will be used. |
| 141 | +In the case of the length modifier "L" and integer conversions, it will be |
| 142 | +treated as if it was "ll" (lowercase LL). For this purpose the list of integer |
| 143 | +conversions is d, i, u, o, x, X, n. |
| 144 | + |
| 145 | +If a conversion specification ending in % has any options that consume arguments |
| 146 | +(e.g. "%*.*%") those arguments will be consumed as normal, but their values will |
| 147 | +be ignored. |
| 148 | + |
| 149 | +If a conversion specification ends in a null byte ('\0') then it shall be |
| 150 | +treated as an invalid conversion followed by a null byte. |
| 151 | + |
| 152 | +If a number passed as a min width or precision value is out of range for an int, |
| 153 | +then it will be treated as the largest or smallest value in the int range |
| 154 | +(e.g. "%-999999999999.999999999999s" is the same as "%-2147483648.2147483647s"). |
| 155 | + |
| 156 | +---------- |
| 157 | +Conversion |
| 158 | +---------- |
| 159 | +Any conversion specification that contains a flag or option that it does not |
| 160 | +have defined behavior for will ignore that flag or option (e.g. %.5c is the same |
| 161 | +as %c). |
| 162 | + |
| 163 | +If a conversion specification ends in %, then it will be treated as if it is |
| 164 | +"%%", ignoring all options. |
| 165 | + |
| 166 | +If a null pointer is passed to a %s conversion specification and null pointer |
| 167 | +checks are enabled, it will be treated as if the provided string is "null". |
| 168 | + |
| 169 | +If a null pointer is passed to a %n conversion specification and null pointer |
| 170 | +checks are enabled, the conversion will fail and printf will return a negative |
| 171 | +value. |
| 172 | + |
| 173 | +If a null pointer is passed to a %p conversion specification, the string |
| 174 | +"(nullptr)" will be returned instead of an integer value. |
| 175 | + |
| 176 | +The %p conversion will display any non-null pointer as if it was a uintptr value |
| 177 | +passed to a "%#tx" conversion, with all other options remaining the same as the |
| 178 | +original conversion. |
| 179 | + |
| 180 | +The %p conversion will display a null pointer as if it was the string |
| 181 | +"(nullptr)" passed to a "%s" conversion, with all other options remaining the |
| 182 | +same as the original conversion. |
0 commit comments