/work/obj-fuzz/dist/include/mozilla/Printf.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | | * vim: set ts=8 sts=4 et sw=4 tw=99: |
3 | | * This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | /* Printf-like functions, with canned variants that malloc their result. */ |
8 | | |
9 | | #ifndef mozilla_Printf_h |
10 | | #define mozilla_Printf_h |
11 | | |
12 | | /* |
13 | | ** API for PR printf like routines. |
14 | | ** |
15 | | ** These exist partly for historical reasons -- initially they were in |
16 | | ** NSPR, then forked in tree and modified in js/ -- but now the prime |
17 | | ** motivation is both closer control over the exact formatting (with |
18 | | ** one exception, see below) and also the ability to control where |
19 | | ** exactly the generated results are sent. |
20 | | ** |
21 | | ** It might seem that this could all be dispensed with in favor of a |
22 | | ** wrapper around |vsnprintf| -- except that this implementation |
23 | | ** guarantees that the %s format will accept a NULL pointer, whereas |
24 | | ** with standard functions this is undefined. |
25 | | ** |
26 | | ** This supports the following formats. It implements a subset of the |
27 | | ** standard formats; due to the use of MOZ_FORMAT_PRINTF, it is not |
28 | | ** permissible to extend the standard, aside from relaxing undefined |
29 | | ** behavior. |
30 | | ** |
31 | | ** %d - decimal |
32 | | ** %u - unsigned decimal |
33 | | ** %x - unsigned hex |
34 | | ** %X - unsigned uppercase hex |
35 | | ** %o - unsigned octal |
36 | | ** %hd, %hu, %hx, %hX, %ho - "short" versions of above |
37 | | ** %ld, %lu, %lx, %lX, %lo - "long" versions of above |
38 | | ** %lld, %llu, %llx, %llX, %llo - "long long" versions of above |
39 | | ** %zd, %zo, %zu, %zx, %zX - size_t versions of above |
40 | | ** %Id, %Io, %Iu, %Ix, %IX - size_t versions of above (for Windows compat). |
41 | | ** Note that MSVC 2015 and newer supports the z length modifier so |
42 | | ** users should prefer using %z instead of %I. We are supporting %I in |
43 | | ** addition to %z in case third-party code that uses %I gets routed to |
44 | | ** use this printf implementation. |
45 | | ** %s - string |
46 | | ** %S, %ls - wide string, that is wchar_t* |
47 | | ** %c - character |
48 | | ** %p - pointer (deals with machine dependent pointer size) |
49 | | ** %f - float; note that this is actually formatted using the |
50 | | ** system's native printf, and so the results may vary |
51 | | ** %g - float; note that this is actually formatted using the |
52 | | ** system's native printf, and so the results may vary |
53 | | */ |
54 | | |
55 | | #include "mozilla/AllocPolicy.h" |
56 | | #include "mozilla/Assertions.h" |
57 | | #include "mozilla/Attributes.h" |
58 | | #include "mozilla/IntegerPrintfMacros.h" |
59 | | #include "mozilla/Types.h" |
60 | | #include "mozilla/UniquePtr.h" |
61 | | |
62 | | #include <stdarg.h> |
63 | | #include <string.h> |
64 | | |
65 | | namespace mozilla { |
66 | | |
67 | | /* |
68 | | * This class may be subclassed to provide a way to get the output of |
69 | | * a printf-like call, as the output is generated. |
70 | | */ |
71 | | class PrintfTarget |
72 | | { |
73 | | public: |
74 | | /* The Printf-like interface. */ |
75 | | bool MFBT_API print(const char* format, ...) MOZ_FORMAT_PRINTF(2, 3); |
76 | | |
77 | | /* The Vprintf-like interface. */ |
78 | | bool MFBT_API vprint(const char* format, va_list) MOZ_FORMAT_PRINTF(2, 0); |
79 | | |
80 | | protected: |
81 | | MFBT_API PrintfTarget(); |
82 | 18.9k | virtual ~PrintfTarget() { } |
83 | | |
84 | | /* Subclasses override this. It is called when more output is |
85 | | available. It may be called with len==0. This should return |
86 | | true on success, or false on failure. */ |
87 | | virtual bool append(const char* sp, size_t len) = 0; |
88 | | |
89 | | private: |
90 | | |
91 | | /* Number of bytes emitted so far. */ |
92 | | size_t mEmitted; |
93 | | |
94 | | /* The implementation calls this to emit bytes and update |
95 | | mEmitted. */ |
96 | 236k | bool emit(const char* sp, size_t len) { |
97 | 236k | mEmitted += len; |
98 | 236k | return append(sp, len); |
99 | 236k | } |
100 | | |
101 | | bool fill2(const char* src, int srclen, int width, int flags); |
102 | | bool fill_n(const char* src, int srclen, int width, int prec, int type, int flags); |
103 | | bool cvt_l(long num, int width, int prec, int radix, int type, int flags, const char* hxp); |
104 | | bool cvt_ll(int64_t num, int width, int prec, int radix, int type, int flags, const char* hexp); |
105 | | bool cvt_f(double d, const char* fmt0, const char* fmt1); |
106 | | bool cvt_s(const char* s, int width, int prec, int flags); |
107 | | }; |
108 | | |
109 | | namespace detail { |
110 | | |
111 | | template<typename AllocPolicy = mozilla::MallocAllocPolicy> |
112 | | struct AllocPolicyBasedFreePolicy |
113 | | { |
114 | 8.90k | void operator()(const void* ptr) { |
115 | 8.90k | AllocPolicy policy; |
116 | 8.90k | policy.free_(const_cast<void*>(ptr)); |
117 | 8.90k | } mozilla::detail::AllocPolicyBasedFreePolicy<mozilla::MallocAllocPolicy>::operator()(void const*) Line | Count | Source | 114 | 8.90k | void operator()(const void* ptr) { | 115 | 8.90k | AllocPolicy policy; | 116 | 8.90k | policy.free_(const_cast<void*>(ptr)); | 117 | 8.90k | } |
Unexecuted instantiation: mozilla::detail::AllocPolicyBasedFreePolicy<js::SystemAllocPolicy>::operator()(void const*) |
118 | | }; |
119 | | |
120 | | } |
121 | | |
122 | | // The type returned by Smprintf and friends. |
123 | | template<typename AllocPolicy> |
124 | | using SmprintfPolicyPointer = mozilla::UniquePtr<char, detail::AllocPolicyBasedFreePolicy<AllocPolicy>>; |
125 | | |
126 | | // The default type if no alloc policy is specified. |
127 | | typedef SmprintfPolicyPointer<mozilla::MallocAllocPolicy> SmprintfPointer; |
128 | | |
129 | | // Used in the implementation of Smprintf et al. |
130 | | template<typename AllocPolicy> |
131 | | class MOZ_STACK_CLASS SprintfState final : private mozilla::PrintfTarget, private AllocPolicy |
132 | | { |
133 | | public: |
134 | | explicit SprintfState(char* base) |
135 | | : mMaxlen(base ? strlen(base) : 0) |
136 | | , mBase(base) |
137 | | , mCur(base ? base + mMaxlen : 0) |
138 | 8.90k | { |
139 | 8.90k | } mozilla::SprintfState<mozilla::MallocAllocPolicy>::SprintfState(char*) Line | Count | Source | 138 | 8.90k | { | 139 | 8.90k | } |
Unexecuted instantiation: mozilla::SprintfState<js::SystemAllocPolicy>::SprintfState(char*) |
140 | | |
141 | 8.90k | ~SprintfState() { |
142 | 8.90k | this->free_(mBase); |
143 | 8.90k | } mozilla::SprintfState<mozilla::MallocAllocPolicy>::~SprintfState() Line | Count | Source | 141 | 8.90k | ~SprintfState() { | 142 | 8.90k | this->free_(mBase); | 143 | 8.90k | } |
Unexecuted instantiation: mozilla::SprintfState<js::SystemAllocPolicy>::~SprintfState() |
144 | | |
145 | 8.90k | bool vprint(const char* format, va_list ap_list) MOZ_FORMAT_PRINTF(2, 0) { |
146 | 8.90k | // The "" here has a single \0 character, which is what we're |
147 | 8.90k | // trying to append. |
148 | 8.90k | return mozilla::PrintfTarget::vprint(format, ap_list) && append("", 1); |
149 | 8.90k | } mozilla::SprintfState<mozilla::MallocAllocPolicy>::vprint(char const*, __va_list_tag*) Line | Count | Source | 145 | 8.90k | bool vprint(const char* format, va_list ap_list) MOZ_FORMAT_PRINTF(2, 0) { | 146 | 8.90k | // The "" here has a single \0 character, which is what we're | 147 | 8.90k | // trying to append. | 148 | 8.90k | return mozilla::PrintfTarget::vprint(format, ap_list) && append("", 1); | 149 | 8.90k | } |
Unexecuted instantiation: mozilla::SprintfState<js::SystemAllocPolicy>::vprint(char const*, __va_list_tag*) |
150 | | |
151 | 8.90k | SmprintfPolicyPointer<AllocPolicy> release() { |
152 | 8.90k | SmprintfPolicyPointer<AllocPolicy> result(mBase); |
153 | 8.90k | mBase = nullptr; |
154 | 8.90k | return result; |
155 | 8.90k | } mozilla::SprintfState<mozilla::MallocAllocPolicy>::release() Line | Count | Source | 151 | 8.90k | SmprintfPolicyPointer<AllocPolicy> release() { | 152 | 8.90k | SmprintfPolicyPointer<AllocPolicy> result(mBase); | 153 | 8.90k | mBase = nullptr; | 154 | 8.90k | return result; | 155 | 8.90k | } |
Unexecuted instantiation: mozilla::SprintfState<js::SystemAllocPolicy>::release() |
156 | | |
157 | | protected: |
158 | | |
159 | 195k | bool append(const char* sp, size_t len) override { |
160 | 195k | ptrdiff_t off; |
161 | 195k | char* newbase; |
162 | 195k | size_t newlen; |
163 | 195k | |
164 | 195k | off = mCur - mBase; |
165 | 195k | if (off + len >= mMaxlen) { |
166 | 9.12k | /* Grow the buffer */ |
167 | 9.12k | newlen = mMaxlen + ((len > 32) ? len : 32); |
168 | 9.12k | newbase = this->template maybe_pod_malloc<char>(newlen); |
169 | 9.12k | if (!newbase) { |
170 | 0 | /* Ran out of memory */ |
171 | 0 | return false; |
172 | 0 | } |
173 | 9.12k | memcpy(newbase, mBase, mMaxlen); |
174 | 9.12k | this->free_(mBase); |
175 | 9.12k | mBase = newbase; |
176 | 9.12k | mMaxlen = newlen; |
177 | 9.12k | mCur = mBase + off; |
178 | 9.12k | } |
179 | 195k | |
180 | 195k | /* Copy data */ |
181 | 195k | memcpy(mCur, sp, len); |
182 | 195k | mCur += len; |
183 | 195k | MOZ_ASSERT(size_t(mCur - mBase) <= mMaxlen); |
184 | 195k | return true; |
185 | 195k | } mozilla::SprintfState<mozilla::MallocAllocPolicy>::append(char const*, unsigned long) Line | Count | Source | 159 | 195k | bool append(const char* sp, size_t len) override { | 160 | 195k | ptrdiff_t off; | 161 | 195k | char* newbase; | 162 | 195k | size_t newlen; | 163 | 195k | | 164 | 195k | off = mCur - mBase; | 165 | 195k | if (off + len >= mMaxlen) { | 166 | 9.12k | /* Grow the buffer */ | 167 | 9.12k | newlen = mMaxlen + ((len > 32) ? len : 32); | 168 | 9.12k | newbase = this->template maybe_pod_malloc<char>(newlen); | 169 | 9.12k | if (!newbase) { | 170 | 0 | /* Ran out of memory */ | 171 | 0 | return false; | 172 | 0 | } | 173 | 9.12k | memcpy(newbase, mBase, mMaxlen); | 174 | 9.12k | this->free_(mBase); | 175 | 9.12k | mBase = newbase; | 176 | 9.12k | mMaxlen = newlen; | 177 | 9.12k | mCur = mBase + off; | 178 | 9.12k | } | 179 | 195k | | 180 | 195k | /* Copy data */ | 181 | 195k | memcpy(mCur, sp, len); | 182 | 195k | mCur += len; | 183 | 195k | MOZ_ASSERT(size_t(mCur - mBase) <= mMaxlen); | 184 | 195k | return true; | 185 | 195k | } |
Unexecuted instantiation: mozilla::SprintfState<js::SystemAllocPolicy>::append(char const*, unsigned long) |
186 | | |
187 | | private: |
188 | | |
189 | | size_t mMaxlen; |
190 | | char* mBase; |
191 | | char* mCur; |
192 | | }; |
193 | | |
194 | | /* |
195 | | ** sprintf into a malloc'd buffer. Return a pointer to the malloc'd |
196 | | ** buffer on success, nullptr on failure. Call AllocPolicy::free_ to release |
197 | | ** the memory returned. |
198 | | */ |
199 | | template<typename AllocPolicy = mozilla::MallocAllocPolicy> |
200 | | MOZ_FORMAT_PRINTF(1, 2) |
201 | | SmprintfPolicyPointer<AllocPolicy> Smprintf(const char* fmt, ...) |
202 | 0 | { |
203 | 0 | SprintfState<AllocPolicy> ss(nullptr); |
204 | 0 | va_list ap; |
205 | 0 | va_start(ap, fmt); |
206 | 0 | bool r = ss.vprint(fmt, ap); |
207 | 0 | va_end(ap); |
208 | 0 | if (!r) { |
209 | 0 | return nullptr; |
210 | 0 | } |
211 | 0 | return ss.release(); |
212 | 0 | } |
213 | | |
214 | | /* |
215 | | ** "append" sprintf into a malloc'd buffer. "last" is the last value of |
216 | | ** the malloc'd buffer. sprintf will append data to the end of last, |
217 | | ** growing it as necessary using realloc. If last is nullptr, SmprintfAppend |
218 | | ** will allocate the initial string. The return value is the new value of |
219 | | ** last for subsequent calls, or nullptr if there is a malloc failure. |
220 | | */ |
221 | | template<typename AllocPolicy = mozilla::MallocAllocPolicy> |
222 | | MOZ_FORMAT_PRINTF(2, 3) |
223 | | SmprintfPolicyPointer<AllocPolicy> SmprintfAppend(SmprintfPolicyPointer<AllocPolicy>&& last, |
224 | | const char* fmt, ...) |
225 | | { |
226 | | SprintfState<AllocPolicy> ss(last.release()); |
227 | | va_list ap; |
228 | | va_start(ap, fmt); |
229 | | bool r = ss.vprint(fmt, ap); |
230 | | va_end(ap); |
231 | | if (!r) { |
232 | | return nullptr; |
233 | | } |
234 | | return ss.release(); |
235 | | } |
236 | | |
237 | | /* |
238 | | ** va_list forms of the above. |
239 | | */ |
240 | | template<typename AllocPolicy = mozilla::MallocAllocPolicy> |
241 | | MOZ_FORMAT_PRINTF(1, 0) |
242 | | SmprintfPolicyPointer<AllocPolicy> Vsmprintf(const char* fmt, va_list ap) |
243 | 8.90k | { |
244 | 8.90k | SprintfState<AllocPolicy> ss(nullptr); |
245 | 8.90k | if (!ss.vprint(fmt, ap)) |
246 | 0 | return nullptr; |
247 | 8.90k | return ss.release(); |
248 | 8.90k | } mozilla::UniquePtr<char, mozilla::detail::AllocPolicyBasedFreePolicy<mozilla::MallocAllocPolicy> > mozilla::Vsmprintf<mozilla::MallocAllocPolicy>(char const*, __va_list_tag*) Line | Count | Source | 243 | 8.90k | { | 244 | 8.90k | SprintfState<AllocPolicy> ss(nullptr); | 245 | 8.90k | if (!ss.vprint(fmt, ap)) | 246 | 0 | return nullptr; | 247 | 8.90k | return ss.release(); | 248 | 8.90k | } |
Unexecuted instantiation: mozilla::UniquePtr<char, mozilla::detail::AllocPolicyBasedFreePolicy<js::SystemAllocPolicy> > mozilla::Vsmprintf<js::SystemAllocPolicy>(char const*, __va_list_tag*) |
249 | | |
250 | | template<typename AllocPolicy = mozilla::MallocAllocPolicy> |
251 | | MOZ_FORMAT_PRINTF(2, 0) |
252 | | SmprintfPolicyPointer<AllocPolicy> VsmprintfAppend(SmprintfPolicyPointer<AllocPolicy>&& last, |
253 | | const char* fmt, va_list ap) |
254 | 0 | { |
255 | 0 | SprintfState<AllocPolicy> ss(last.release()); |
256 | 0 | if (!ss.vprint(fmt, ap)) |
257 | 0 | return nullptr; |
258 | 0 | return ss.release(); |
259 | 0 | } Unexecuted instantiation: mozilla::UniquePtr<char, mozilla::detail::AllocPolicyBasedFreePolicy<mozilla::MallocAllocPolicy> > mozilla::VsmprintfAppend<mozilla::MallocAllocPolicy>(mozilla::UniquePtr<char, mozilla::detail::AllocPolicyBasedFreePolicy<mozilla::MallocAllocPolicy> >&&, char const*, __va_list_tag*) Unexecuted instantiation: mozilla::UniquePtr<char, mozilla::detail::AllocPolicyBasedFreePolicy<js::SystemAllocPolicy> > mozilla::VsmprintfAppend<js::SystemAllocPolicy>(mozilla::UniquePtr<char, mozilla::detail::AllocPolicyBasedFreePolicy<js::SystemAllocPolicy> >&&, char const*, __va_list_tag*) |
260 | | |
261 | | } // namespace mozilla |
262 | | |
263 | | #endif /* mozilla_Printf_h */ |