File: zprintf.texi

package info (click to toggle)
gnulib 20251215-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 180,904 kB
  • sloc: ansic: 393,155; sh: 30,853; python: 8,371; cpp: 2,918; yacc: 1,847; perl: 920; makefile: 642; lisp: 328; sed: 11; java: 5
file content (231 lines) | stat: -rw-r--r-- 8,398 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
@node Modernized printf
@section Modernized printf

@c Copyright (C) 2024--2025 Free Software Foundation, Inc.

@c Permission is granted to copy, distribute and/or modify this document
@c under the terms of the GNU Free Documentation License, Version 1.3 or
@c any later version published by the Free Software Foundation; with no
@c Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.  A
@c copy of the license is at <https://www.gnu.org/licenses/fdl-1.3.en.html>.

@c Written by Bruno Haible.

The @code{*zprintf} family of functions is
a modernized form of the @code{*printf} family of functions.

@subheading The problem

The @code{*printf} functions have a return type @samp{int}
and therefore can only produce results that are up to (2 GiB - 1 byte) long.

The problem with this is not so much that it is an arbitrary limitation
(that persists even in processes that have, say, 50 GiB of RAM available).
The bigger problem is that in reliable programs,
it requires handling of an error code @code{EOVERFLOW}
that indicates a result whose size would be 2 GiB or larger.

@c A symptom of this missing EOVERFLOW handling can be
@c warnings from static analyzers, see e.g.
@c https://lists.gnu.org/archive/html/bug-gnulib/2023-06/msg00014.html

How does a reliable program do error handling of @code{*printf} function calls?
For output to strings and file descriptors
(such as @code{sprintf} and @code{dprintf}),
there is no other way than to check each such call.

For output to @code{FILE} streams (such as @code{fprintf}),
beginners are tempted to ignore the return value of each call
and instead check @code{ferror (stream)} at the end.
The problem with this approach is that
at the moment the error is detected,
incorrect output has already been sent onto the stream.
So, in this case as well, the reliable approach is to check each such call.

The @emph{simple format strings} that most programs use in 99% of the places,
namely with no wide string or wide character arguments,
nor with widths passed as @code{int} argument,
can only fail with two possible error codes:
@itemize
@item
@code{ENOMEM}, when
the result would be too large to allocate in the process' memory.
@item
@code{EOVERFLOW}, when
the result is 2 GiB or larger but still allocatable.
@end itemize

Many GNU programs use ``checking'' wrappers (functions @code{xvasprintf}, etc.)
that check for @code{ENOMEM} and call @code{xalloc_die},
thus aborting the program in that case.
The problem is that @code{EOVERFLOW} is not handled, even with such wrappers.

Should @code{EOVERFLOW} be handled like @code{ENOMEM}, by aborting the program?
No, as mentioned above, that would be an arbitrary limitation, which the
@ifinfo
GNU Coding Standards
urge us to avoid
(@pxref{Semantics,,, standards}).
@end ifinfo
@ifnotinfo
@url{https://www.gnu.org/prep/standards/html_node/Semantics.html,,GNU Coding Standards}
urge us to avoid.
@end ifnotinfo

@subheading The solution

The @code{*zprintf} functions are like the @code{*printf} functions,
except that the return type is
@itemize
@item
@code{ptrdiff_t} instead of @code{int},
for output to strings,
@item
@code{off64_t} (which is always equivalent to @code{int64_t})
instead of @code{int},
for output to file streams and file descriptors.
@end itemize
@noindent
Thus, for these functions, @code{EOVERFLOW} cannot occur
(except for format strings which take widths as argument,
which we have excluded above),
and the ``checking'' wrappers (functions @code{xvasprintf}, etc.)
are thus sufficient for ensuring an error-free result.

Note:
In 64-bit processes, @code{ptrdiff_t} is 64 bits wide,
i.e. equivalent to @code{int64_t}.
In 32-bit processes, @code{ptrdiff_t} is only 32 bits wide,
but since in these environments,
memory regions of 2 GiB or larger cannot be allocated anyway
(@code{malloc} would fail with @code{ENOMEM}),
this type is sufficient.

The following Gnulib functions and modules exist:

@mindex szprintf
@mindex szprintf-posix
@mindex szprintf-gnu
@mindex vszprintf
@mindex vszprintf-posix
@mindex vszprintf-gnu
@mindex snzprintf
@mindex snzprintf-posix
@mindex snzprintf-gnu
@mindex vsnzprintf
@mindex vsnzprintf-posix
@mindex vsnzprintf-gnu
@mindex vaszprintf
@mindex vaszprintf-posix
@mindex vaszprintf-gnu
@mindex c-snzprintf
@mindex c-snzprintf-gnu
@mindex c-vsnzprintf
@mindex c-vsnzprintf-gnu
@mindex c-vaszprintf
@mindex c-vaszprintf-gnu
@mindex fzprintf
@mindex fzprintf-posix
@mindex fzprintf-gnu
@mindex vfzprintf
@mindex vfzprintf-posix
@mindex vfzprintf-gnu
@mindex zprintf
@mindex zprintf-posix
@mindex zprintf-gnu
@mindex vzprintf
@mindex vzprintf-posix
@mindex vzprintf-gnu
@mindex dzprintf
@mindex dzprintf-posix
@mindex dzprintf-gnu
@mindex vdzprintf
@mindex vdzprintf-posix
@mindex vdzprintf-gnu
@mindex obstack-zprintf
@mindex obstack-zprintf-posix
@mindex obstack-zprintf-gnu
@multitable @columnfractions .25 .25 .5
@headitem Original function @tab Modernized function @tab Modules
@item @code{sprintf} @tab @code{szprintf}
 @tab @code{szprintf}, @code{szprintf-posix}, @code{szprintf-gnu}
@item @code{vsprintf} @tab @code{vszprintf}
 @tab @code{vszprintf}, @code{vszprintf-posix}, @code{vszprintf-gnu}
@item @code{snprintf} @tab @code{snzprintf}
 @tab @code{snzprintf}, @code{snzprintf-posix}, @code{snzprintf-gnu}
@item @code{vsnprintf} @tab @code{vsnzprintf}
 @tab @code{vsnzprintf}, @code{vsnzprintf-posix}, @code{vsnzprintf-gnu}
@item @code{asprintf} @tab @code{aszprintf}
 @tab @code{vaszprintf}, @code{vaszprintf-posix}, @code{vaszprintf-gnu}
@item @code{vasprintf} @tab @code{vaszprintf}
 @tab @code{vaszprintf}, @code{vaszprintf-posix}, @code{vaszprintf-gnu}
@item @code{c_snprintf} @tab @code{c_snzprintf}
 @tab @code{c-snzprintf}, @code{c-snzprintf-gnu}
@item @code{c_vsnprintf} @tab @code{c_vsnzprintf}
 @tab @code{c-vsnzprintf}, @code{c-vsnzprintf-gnu}
@item @code{c_asprintf} @tab @code{c_aszprintf}
 @tab @code{c-vaszprintf}, @code{c-vaszprintf-gnu}
@item @code{c_vasprintf} @tab @code{c_vaszprintf}
 @tab @code{c-vaszprintf}, @code{c-vaszprintf-gnu}
@item @code{fprintf} @tab @code{fzprintf}
 @tab @code{fzprintf}, @code{fzprintf-posix}, @code{fzprintf-gnu}
@item @code{vfprintf} @tab @code{vfzprintf}
 @tab @code{vfzprintf}, @code{vfzprintf-posix}, @code{vfzprintf-gnu}
@item @code{printf} @tab @code{zprintf}
 @tab @code{zprintf}, @code{zprintf-posix}, @code{zprintf-gnu}
@item @code{vprintf} @tab @code{vzprintf}
 @tab @code{vzprintf}, @code{vzprintf-posix}, @code{vzprintf-gnu}
@item @code{dprintf} @tab @code{dzprintf}
 @tab @code{dzprintf}, @code{dzprintf-posix}, @code{dzprintf-gnu}
@item @code{vdprintf} @tab @code{vdzprintf}
 @tab @code{vdzprintf}, @code{vdzprintf-posix}, @code{vdzprintf-gnu}
@item @code{obstack_printf} @tab @code{obstack_zprintf}
 @tab @code{obstack-zprintf},
      @code{obstack-zprintf-posix}, @code{obstack-zprintf-gnu}
@item @code{obstack_vprintf} @tab @code{obstack_vzprintf}
 @tab @code{obstack-zprintf},
      @code{obstack-zprintf-posix}, @code{obstack-zprintf-gnu}
@end multitable

The following functions use the @code{*zprintf} functions under the hood
and thus don't need a @code{*zprintf} variant:

@mindex xvasprintf
@mindex xvasprintf-posix
@mindex xvasprintf-gnu
@mindex c-xvasprintf
@mindex xprintf
@mindex xprintf-posix
@mindex xprintf-gnu
@multitable @columnfractions .5 .5
@headitem Function @tab Modules
@item @code{xasprintf}
 @tab @code{xvasprintf}, @code{xvasprintf-posix}, @code{xvasprintf-gnu}
@item @code{xvasprintf}
 @tab @code{xvasprintf}, @code{xvasprintf-posix}, @code{xvasprintf-gnu}
@item @code{c_xasprintf}
 @tab @code{c-xvasprintf}
@item @code{c_xvasprintf}
 @tab @code{c-xvasprintf}
@item @code{xprintf}
 @tab @code{xprintf}, @code{xprintf-posix}, @code{xprintf-gnu}
@item @code{xvprintf}
 @tab @code{xprintf}, @code{xprintf-posix}, @code{xprintf-gnu}
@item @code{xfprintf}
 @tab @code{xprintf}, @code{xprintf-posix}, @code{xprintf-gnu}
@item @code{xvfprintf}
 @tab @code{xprintf}, @code{xprintf-posix}, @code{xprintf-gnu}
@end multitable

Note: Even with the @code{*zprintf} functions,
you need to be prepared to handle specific error codes
when you use non-simple format strings:
@itemize
@item
@code{EILSEQ} when
the format string takes wide strings or wide characters as arguments,
@item
@code{EOVERFLOW} when
the format string takes a width as argument
and you cannot ensure that its value is in the range @code{0}...@code{INT_MAX}.
@end itemize