Skip to content

Commit aa1eacd

Browse files
[libc][docs] Printf behavior doc
In the document on undefined behavior, I noted that writing down your decisions is very important. This document contains all the information for compile flags and undefined behavior for our printf. Reviewed By: sivachandra Differential Revision: https://reviews.llvm.org/D158311
1 parent 1b07d43 commit aa1eacd

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed

libc/docs/dev/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ Navigate to the links below for information on the respective topics:
1818
header_generation
1919
implementation_standard
2020
undefined_behavior
21+
printf_behavior
2122
api_test
2223
mechanics_of_public_api

libc/docs/dev/printf_behavior.rst

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
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

Comments
 (0)