1#define assert(e) do { \ 2 if (config_debug && !(e)) { \ 3 malloc_write("<jemalloc>: Failed assertion\n"); \ 4 abort(); \ 5 } \ 6} while (0) 7 8#define not_reached() do { \ 9 if (config_debug) { \ 10 malloc_write("<jemalloc>: Unreachable code reached\n"); \ 11 abort(); \ 12 } \ 13} while (0) 14 15#define not_implemented() do { \ 16 if (config_debug) { \ 17 malloc_write("<jemalloc>: Not implemented\n"); \ 18 abort(); \ 19 } \ 20} while (0) 21 22#define JEMALLOC_UTIL_C_ 23#include "jemalloc/internal/jemalloc_internal.h" 24 25/******************************************************************************/ 26/* Function prototypes for non-inline static functions. */ 27 28static void wrtmessage(void *cbopaque, const char *s); 29#define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1) 30static char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s, 31 size_t *slen_p); 32#define D2S_BUFSIZE (1 + U2S_BUFSIZE) 33static char *d2s(intmax_t x, char sign, char *s, size_t *slen_p); 34#define O2S_BUFSIZE (1 + U2S_BUFSIZE) 35static char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p); 36#define X2S_BUFSIZE (2 + U2S_BUFSIZE) 37static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, 38 size_t *slen_p); 39 40/******************************************************************************/ 41 42/* malloc_message() setup. */ 43static void 44wrtmessage(void *cbopaque, const char *s) 45{ 46 47#ifdef SYS_write 48 /* 49 * Use syscall(2) rather than write(2) when possible in order to avoid 50 * the possibility of memory allocation within libc. This is necessary 51 * on FreeBSD; most operating systems do not have this problem though. 52 */ 53 UNUSED int result = syscall(SYS_write, STDERR_FILENO, s, strlen(s)); 54#else 55 UNUSED int result = write(STDERR_FILENO, s, strlen(s)); 56#endif 57} 58 59JEMALLOC_EXPORT void (*je_malloc_message)(void *, const char *s); 60 61JEMALLOC_ATTR(visibility("hidden")) 62void 63wrtmessage_1_0(const char *s1, const char *s2, const char *s3, 64 const char *s4) 65{ 66 67 wrtmessage(NULL, s1); 68 wrtmessage(NULL, s2); 69 wrtmessage(NULL, s3); 70 wrtmessage(NULL, s4); 71} 72 73void (*__malloc_message_1_0)(const char *s1, const char *s2, const char *s3, 74 const char *s4) = wrtmessage_1_0; 75__sym_compat(_malloc_message, __malloc_message_1_0, FBSD_1.0); 76 77/* 78 * Wrapper around malloc_message() that avoids the need for 79 * je_malloc_message(...) throughout the code. 80 */ 81void 82malloc_write(const char *s) 83{ 84 85 if (je_malloc_message != NULL) 86 je_malloc_message(NULL, s); 87 else 88 wrtmessage(NULL, s); 89} 90 91/* 92 * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so 93 * provide a wrapper. 94 */ 95int
| 1#define assert(e) do { \ 2 if (config_debug && !(e)) { \ 3 malloc_write("<jemalloc>: Failed assertion\n"); \ 4 abort(); \ 5 } \ 6} while (0) 7 8#define not_reached() do { \ 9 if (config_debug) { \ 10 malloc_write("<jemalloc>: Unreachable code reached\n"); \ 11 abort(); \ 12 } \ 13} while (0) 14 15#define not_implemented() do { \ 16 if (config_debug) { \ 17 malloc_write("<jemalloc>: Not implemented\n"); \ 18 abort(); \ 19 } \ 20} while (0) 21 22#define JEMALLOC_UTIL_C_ 23#include "jemalloc/internal/jemalloc_internal.h" 24 25/******************************************************************************/ 26/* Function prototypes for non-inline static functions. */ 27 28static void wrtmessage(void *cbopaque, const char *s); 29#define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1) 30static char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s, 31 size_t *slen_p); 32#define D2S_BUFSIZE (1 + U2S_BUFSIZE) 33static char *d2s(intmax_t x, char sign, char *s, size_t *slen_p); 34#define O2S_BUFSIZE (1 + U2S_BUFSIZE) 35static char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p); 36#define X2S_BUFSIZE (2 + U2S_BUFSIZE) 37static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, 38 size_t *slen_p); 39 40/******************************************************************************/ 41 42/* malloc_message() setup. */ 43static void 44wrtmessage(void *cbopaque, const char *s) 45{ 46 47#ifdef SYS_write 48 /* 49 * Use syscall(2) rather than write(2) when possible in order to avoid 50 * the possibility of memory allocation within libc. This is necessary 51 * on FreeBSD; most operating systems do not have this problem though. 52 */ 53 UNUSED int result = syscall(SYS_write, STDERR_FILENO, s, strlen(s)); 54#else 55 UNUSED int result = write(STDERR_FILENO, s, strlen(s)); 56#endif 57} 58 59JEMALLOC_EXPORT void (*je_malloc_message)(void *, const char *s); 60 61JEMALLOC_ATTR(visibility("hidden")) 62void 63wrtmessage_1_0(const char *s1, const char *s2, const char *s3, 64 const char *s4) 65{ 66 67 wrtmessage(NULL, s1); 68 wrtmessage(NULL, s2); 69 wrtmessage(NULL, s3); 70 wrtmessage(NULL, s4); 71} 72 73void (*__malloc_message_1_0)(const char *s1, const char *s2, const char *s3, 74 const char *s4) = wrtmessage_1_0; 75__sym_compat(_malloc_message, __malloc_message_1_0, FBSD_1.0); 76 77/* 78 * Wrapper around malloc_message() that avoids the need for 79 * je_malloc_message(...) throughout the code. 80 */ 81void 82malloc_write(const char *s) 83{ 84 85 if (je_malloc_message != NULL) 86 je_malloc_message(NULL, s); 87 else 88 wrtmessage(NULL, s); 89} 90 91/* 92 * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so 93 * provide a wrapper. 94 */ 95int
|
96buferror(char *buf, size_t buflen)
| 96buferror(int err, char *buf, size_t buflen)
|
97{ 98 99#ifdef _WIN32 100 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, 101 (LPSTR)buf, buflen, NULL); 102 return (0); 103#elif defined(_GNU_SOURCE)
| 97{ 98 99#ifdef _WIN32 100 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, 101 (LPSTR)buf, buflen, NULL); 102 return (0); 103#elif defined(_GNU_SOURCE)
|
104 char *b = strerror_r(errno, buf, buflen);
| 104 char *b = strerror_r(err, buf, buflen);
|
105 if (b != buf) { 106 strncpy(buf, b, buflen); 107 buf[buflen-1] = '\0'; 108 } 109 return (0); 110#else
| 105 if (b != buf) { 106 strncpy(buf, b, buflen); 107 buf[buflen-1] = '\0'; 108 } 109 return (0); 110#else
|
111 return (strerror_r(errno, buf, buflen));
| 111 return (strerror_r(err, buf, buflen));
|
112#endif 113} 114 115uintmax_t
| 112#endif 113} 114 115uintmax_t
|
116malloc_strtoumax(const char *nptr, char **endptr, int base)
| 116malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base)
|
117{ 118 uintmax_t ret, digit; 119 int b; 120 bool neg; 121 const char *p, *ns; 122
| 117{ 118 uintmax_t ret, digit; 119 int b; 120 bool neg; 121 const char *p, *ns; 122
|
| 123 p = nptr;
|
123 if (base < 0 || base == 1 || base > 36) {
| 124 if (base < 0 || base == 1 || base > 36) {
|
| 125 ns = p;
|
124 set_errno(EINVAL);
| 126 set_errno(EINVAL);
|
125 return (UINTMAX_MAX);
| 127 ret = UINTMAX_MAX; 128 goto label_return;
|
126 } 127 b = base; 128 129 /* Swallow leading whitespace and get sign, if any. */ 130 neg = false;
| 129 } 130 b = base; 131 132 /* Swallow leading whitespace and get sign, if any. */ 133 neg = false;
|
131 p = nptr;
| |
132 while (true) { 133 switch (*p) { 134 case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': 135 p++; 136 break; 137 case '-': 138 neg = true; 139 /* Fall through. */ 140 case '+': 141 p++; 142 /* Fall through. */ 143 default: 144 goto label_prefix; 145 } 146 } 147 148 /* Get prefix, if any. */ 149 label_prefix: 150 /* 151 * Note where the first non-whitespace/sign character is so that it is 152 * possible to tell whether any digits are consumed (e.g., " 0" vs. 153 * " -x"). 154 */ 155 ns = p; 156 if (*p == '0') { 157 switch (p[1]) { 158 case '0': case '1': case '2': case '3': case '4': case '5': 159 case '6': case '7': 160 if (b == 0) 161 b = 8; 162 if (b == 8) 163 p++; 164 break;
| 134 while (true) { 135 switch (*p) { 136 case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': 137 p++; 138 break; 139 case '-': 140 neg = true; 141 /* Fall through. */ 142 case '+': 143 p++; 144 /* Fall through. */ 145 default: 146 goto label_prefix; 147 } 148 } 149 150 /* Get prefix, if any. */ 151 label_prefix: 152 /* 153 * Note where the first non-whitespace/sign character is so that it is 154 * possible to tell whether any digits are consumed (e.g., " 0" vs. 155 * " -x"). 156 */ 157 ns = p; 158 if (*p == '0') { 159 switch (p[1]) { 160 case '0': case '1': case '2': case '3': case '4': case '5': 161 case '6': case '7': 162 if (b == 0) 163 b = 8; 164 if (b == 8) 165 p++; 166 break;
|
165 case 'x':
| 167 case 'X': case 'x':
|
166 switch (p[2]) { 167 case '0': case '1': case '2': case '3': case '4': 168 case '5': case '6': case '7': case '8': case '9': 169 case 'A': case 'B': case 'C': case 'D': case 'E': 170 case 'F': 171 case 'a': case 'b': case 'c': case 'd': case 'e': 172 case 'f': 173 if (b == 0) 174 b = 16; 175 if (b == 16) 176 p += 2; 177 break; 178 default: 179 break; 180 } 181 break; 182 default:
| 168 switch (p[2]) { 169 case '0': case '1': case '2': case '3': case '4': 170 case '5': case '6': case '7': case '8': case '9': 171 case 'A': case 'B': case 'C': case 'D': case 'E': 172 case 'F': 173 case 'a': case 'b': case 'c': case 'd': case 'e': 174 case 'f': 175 if (b == 0) 176 b = 16; 177 if (b == 16) 178 p += 2; 179 break; 180 default: 181 break; 182 } 183 break; 184 default:
|
183 break;
| 185 p++; 186 ret = 0; 187 goto label_return;
|
184 } 185 } 186 if (b == 0) 187 b = 10; 188 189 /* Convert. */ 190 ret = 0; 191 while ((*p >= '0' && *p <= '9' && (digit = *p - '0') < b) 192 || (*p >= 'A' && *p <= 'Z' && (digit = 10 + *p - 'A') < b) 193 || (*p >= 'a' && *p <= 'z' && (digit = 10 + *p - 'a') < b)) { 194 uintmax_t pret = ret; 195 ret *= b; 196 ret += digit; 197 if (ret < pret) { 198 /* Overflow. */ 199 set_errno(ERANGE);
| 188 } 189 } 190 if (b == 0) 191 b = 10; 192 193 /* Convert. */ 194 ret = 0; 195 while ((*p >= '0' && *p <= '9' && (digit = *p - '0') < b) 196 || (*p >= 'A' && *p <= 'Z' && (digit = 10 + *p - 'A') < b) 197 || (*p >= 'a' && *p <= 'z' && (digit = 10 + *p - 'a') < b)) { 198 uintmax_t pret = ret; 199 ret *= b; 200 ret += digit; 201 if (ret < pret) { 202 /* Overflow. */ 203 set_errno(ERANGE);
|
200 return (UINTMAX_MAX);
| 204 ret = UINTMAX_MAX; 205 goto label_return;
|
201 } 202 p++; 203 } 204 if (neg) 205 ret = -ret; 206
| 206 } 207 p++; 208 } 209 if (neg) 210 ret = -ret; 211
|
| 212 if (p == ns) { 213 /* No conversion performed. */ 214 set_errno(EINVAL); 215 ret = UINTMAX_MAX; 216 goto label_return; 217 } 218 219label_return:
|
207 if (endptr != NULL) { 208 if (p == ns) { 209 /* No characters were converted. */ 210 *endptr = (char *)nptr; 211 } else 212 *endptr = (char *)p; 213 }
| 220 if (endptr != NULL) { 221 if (p == ns) { 222 /* No characters were converted. */ 223 *endptr = (char *)nptr; 224 } else 225 *endptr = (char *)p; 226 }
|
214
| |
215 return (ret); 216} 217 218static char * 219u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p) 220{ 221 unsigned i; 222 223 i = U2S_BUFSIZE - 1; 224 s[i] = '\0'; 225 switch (base) { 226 case 10: 227 do { 228 i--; 229 s[i] = "0123456789"[x % (uint64_t)10]; 230 x /= (uint64_t)10; 231 } while (x > 0); 232 break; 233 case 16: { 234 const char *digits = (uppercase) 235 ? "0123456789ABCDEF" 236 : "0123456789abcdef"; 237 238 do { 239 i--; 240 s[i] = digits[x & 0xf]; 241 x >>= 4; 242 } while (x > 0); 243 break; 244 } default: { 245 const char *digits = (uppercase) 246 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 247 : "0123456789abcdefghijklmnopqrstuvwxyz"; 248 249 assert(base >= 2 && base <= 36); 250 do { 251 i--; 252 s[i] = digits[x % (uint64_t)base]; 253 x /= (uint64_t)base; 254 } while (x > 0); 255 }} 256 257 *slen_p = U2S_BUFSIZE - 1 - i; 258 return (&s[i]); 259} 260 261static char * 262d2s(intmax_t x, char sign, char *s, size_t *slen_p) 263{ 264 bool neg; 265 266 if ((neg = (x < 0))) 267 x = -x; 268 s = u2s(x, 10, false, s, slen_p); 269 if (neg) 270 sign = '-'; 271 switch (sign) { 272 case '-': 273 if (neg == false) 274 break; 275 /* Fall through. */ 276 case ' ': 277 case '+': 278 s--; 279 (*slen_p)++; 280 *s = sign; 281 break; 282 default: not_reached(); 283 } 284 return (s); 285} 286 287static char * 288o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) 289{ 290 291 s = u2s(x, 8, false, s, slen_p); 292 if (alt_form && *s != '0') { 293 s--; 294 (*slen_p)++; 295 *s = '0'; 296 } 297 return (s); 298} 299 300static char * 301x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p) 302{ 303 304 s = u2s(x, 16, uppercase, s, slen_p); 305 if (alt_form) { 306 s -= 2; 307 (*slen_p) += 2; 308 memcpy(s, uppercase ? "0X" : "0x", 2); 309 } 310 return (s); 311} 312 313int 314malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) 315{ 316 int ret; 317 size_t i; 318 const char *f; 319 320#define APPEND_C(c) do { \ 321 if (i < size) \ 322 str[i] = (c); \ 323 i++; \ 324} while (0) 325#define APPEND_S(s, slen) do { \ 326 if (i < size) { \ 327 size_t cpylen = (slen <= size - i) ? slen : size - i; \ 328 memcpy(&str[i], s, cpylen); \ 329 } \ 330 i += slen; \ 331} while (0) 332#define APPEND_PADDED_S(s, slen, width, left_justify) do { \ 333 /* Left padding. */ \ 334 size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \ 335 (size_t)width - slen : 0); \ 336 if (left_justify == false && pad_len != 0) { \ 337 size_t j; \ 338 for (j = 0; j < pad_len; j++) \ 339 APPEND_C(' '); \ 340 } \ 341 /* Value. */ \ 342 APPEND_S(s, slen); \ 343 /* Right padding. */ \ 344 if (left_justify && pad_len != 0) { \ 345 size_t j; \ 346 for (j = 0; j < pad_len; j++) \ 347 APPEND_C(' '); \ 348 } \ 349} while (0)
| 227 return (ret); 228} 229 230static char * 231u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p) 232{ 233 unsigned i; 234 235 i = U2S_BUFSIZE - 1; 236 s[i] = '\0'; 237 switch (base) { 238 case 10: 239 do { 240 i--; 241 s[i] = "0123456789"[x % (uint64_t)10]; 242 x /= (uint64_t)10; 243 } while (x > 0); 244 break; 245 case 16: { 246 const char *digits = (uppercase) 247 ? "0123456789ABCDEF" 248 : "0123456789abcdef"; 249 250 do { 251 i--; 252 s[i] = digits[x & 0xf]; 253 x >>= 4; 254 } while (x > 0); 255 break; 256 } default: { 257 const char *digits = (uppercase) 258 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 259 : "0123456789abcdefghijklmnopqrstuvwxyz"; 260 261 assert(base >= 2 && base <= 36); 262 do { 263 i--; 264 s[i] = digits[x % (uint64_t)base]; 265 x /= (uint64_t)base; 266 } while (x > 0); 267 }} 268 269 *slen_p = U2S_BUFSIZE - 1 - i; 270 return (&s[i]); 271} 272 273static char * 274d2s(intmax_t x, char sign, char *s, size_t *slen_p) 275{ 276 bool neg; 277 278 if ((neg = (x < 0))) 279 x = -x; 280 s = u2s(x, 10, false, s, slen_p); 281 if (neg) 282 sign = '-'; 283 switch (sign) { 284 case '-': 285 if (neg == false) 286 break; 287 /* Fall through. */ 288 case ' ': 289 case '+': 290 s--; 291 (*slen_p)++; 292 *s = sign; 293 break; 294 default: not_reached(); 295 } 296 return (s); 297} 298 299static char * 300o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) 301{ 302 303 s = u2s(x, 8, false, s, slen_p); 304 if (alt_form && *s != '0') { 305 s--; 306 (*slen_p)++; 307 *s = '0'; 308 } 309 return (s); 310} 311 312static char * 313x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p) 314{ 315 316 s = u2s(x, 16, uppercase, s, slen_p); 317 if (alt_form) { 318 s -= 2; 319 (*slen_p) += 2; 320 memcpy(s, uppercase ? "0X" : "0x", 2); 321 } 322 return (s); 323} 324 325int 326malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) 327{ 328 int ret; 329 size_t i; 330 const char *f; 331 332#define APPEND_C(c) do { \ 333 if (i < size) \ 334 str[i] = (c); \ 335 i++; \ 336} while (0) 337#define APPEND_S(s, slen) do { \ 338 if (i < size) { \ 339 size_t cpylen = (slen <= size - i) ? slen : size - i; \ 340 memcpy(&str[i], s, cpylen); \ 341 } \ 342 i += slen; \ 343} while (0) 344#define APPEND_PADDED_S(s, slen, width, left_justify) do { \ 345 /* Left padding. */ \ 346 size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \ 347 (size_t)width - slen : 0); \ 348 if (left_justify == false && pad_len != 0) { \ 349 size_t j; \ 350 for (j = 0; j < pad_len; j++) \ 351 APPEND_C(' '); \ 352 } \ 353 /* Value. */ \ 354 APPEND_S(s, slen); \ 355 /* Right padding. */ \ 356 if (left_justify && pad_len != 0) { \ 357 size_t j; \ 358 for (j = 0; j < pad_len; j++) \ 359 APPEND_C(' '); \ 360 } \ 361} while (0)
|
350#define GET_ARG_NUMERIC(val, len) do { \
| 362#define GET_ARG_NUMERIC(val, len) do { \
|
351 switch (len) { \ 352 case '?': \ 353 val = va_arg(ap, int); \ 354 break; \ 355 case '?' | 0x80: \ 356 val = va_arg(ap, unsigned int); \ 357 break; \ 358 case 'l': \ 359 val = va_arg(ap, long); \ 360 break; \ 361 case 'l' | 0x80: \ 362 val = va_arg(ap, unsigned long); \ 363 break; \ 364 case 'q': \ 365 val = va_arg(ap, long long); \ 366 break; \ 367 case 'q' | 0x80: \ 368 val = va_arg(ap, unsigned long long); \ 369 break; \ 370 case 'j': \ 371 val = va_arg(ap, intmax_t); \ 372 break; \
| 363 switch (len) { \ 364 case '?': \ 365 val = va_arg(ap, int); \ 366 break; \ 367 case '?' | 0x80: \ 368 val = va_arg(ap, unsigned int); \ 369 break; \ 370 case 'l': \ 371 val = va_arg(ap, long); \ 372 break; \ 373 case 'l' | 0x80: \ 374 val = va_arg(ap, unsigned long); \ 375 break; \ 376 case 'q': \ 377 val = va_arg(ap, long long); \ 378 break; \ 379 case 'q' | 0x80: \ 380 val = va_arg(ap, unsigned long long); \ 381 break; \ 382 case 'j': \ 383 val = va_arg(ap, intmax_t); \ 384 break; \
|
| 385 case 'j' | 0x80: \ 386 val = va_arg(ap, uintmax_t); \ 387 break; \
|
373 case 't': \ 374 val = va_arg(ap, ptrdiff_t); \ 375 break; \ 376 case 'z': \ 377 val = va_arg(ap, ssize_t); \ 378 break; \ 379 case 'z' | 0x80: \ 380 val = va_arg(ap, size_t); \ 381 break; \ 382 case 'p': /* Synthetic; used for %p. */ \ 383 val = va_arg(ap, uintptr_t); \ 384 break; \ 385 default: not_reached(); \ 386 } \ 387} while (0) 388 389 i = 0; 390 f = format; 391 while (true) { 392 switch (*f) { 393 case '\0': goto label_out; 394 case '%': { 395 bool alt_form = false; 396 bool left_justify = false; 397 bool plus_space = false; 398 bool plus_plus = false; 399 int prec = -1; 400 int width = -1; 401 unsigned char len = '?'; 402 403 f++;
| 388 case 't': \ 389 val = va_arg(ap, ptrdiff_t); \ 390 break; \ 391 case 'z': \ 392 val = va_arg(ap, ssize_t); \ 393 break; \ 394 case 'z' | 0x80: \ 395 val = va_arg(ap, size_t); \ 396 break; \ 397 case 'p': /* Synthetic; used for %p. */ \ 398 val = va_arg(ap, uintptr_t); \ 399 break; \ 400 default: not_reached(); \ 401 } \ 402} while (0) 403 404 i = 0; 405 f = format; 406 while (true) { 407 switch (*f) { 408 case '\0': goto label_out; 409 case '%': { 410 bool alt_form = false; 411 bool left_justify = false; 412 bool plus_space = false; 413 bool plus_plus = false; 414 int prec = -1; 415 int width = -1; 416 unsigned char len = '?'; 417 418 f++;
|
404 if (*f == '%') { 405 /* %% */ 406 APPEND_C(*f); 407 break; 408 }
| |
409 /* Flags. */ 410 while (true) { 411 switch (*f) { 412 case '#': 413 assert(alt_form == false); 414 alt_form = true; 415 break; 416 case '-': 417 assert(left_justify == false); 418 left_justify = true; 419 break; 420 case ' ': 421 assert(plus_space == false); 422 plus_space = true; 423 break; 424 case '+': 425 assert(plus_plus == false); 426 plus_plus = true; 427 break; 428 default: goto label_width; 429 } 430 f++; 431 } 432 /* Width. */ 433 label_width: 434 switch (*f) { 435 case '*': 436 width = va_arg(ap, int); 437 f++;
| 419 /* Flags. */ 420 while (true) { 421 switch (*f) { 422 case '#': 423 assert(alt_form == false); 424 alt_form = true; 425 break; 426 case '-': 427 assert(left_justify == false); 428 left_justify = true; 429 break; 430 case ' ': 431 assert(plus_space == false); 432 plus_space = true; 433 break; 434 case '+': 435 assert(plus_plus == false); 436 plus_plus = true; 437 break; 438 default: goto label_width; 439 } 440 f++; 441 } 442 /* Width. */ 443 label_width: 444 switch (*f) { 445 case '*': 446 width = va_arg(ap, int); 447 f++;
|
| 448 if (width < 0) { 449 left_justify = true; 450 width = -width; 451 }
|
438 break; 439 case '0': case '1': case '2': case '3': case '4': 440 case '5': case '6': case '7': case '8': case '9': { 441 uintmax_t uwidth; 442 set_errno(0); 443 uwidth = malloc_strtoumax(f, (char **)&f, 10); 444 assert(uwidth != UINTMAX_MAX || get_errno() != 445 ERANGE); 446 width = (int)uwidth;
| 452 break; 453 case '0': case '1': case '2': case '3': case '4': 454 case '5': case '6': case '7': case '8': case '9': { 455 uintmax_t uwidth; 456 set_errno(0); 457 uwidth = malloc_strtoumax(f, (char **)&f, 10); 458 assert(uwidth != UINTMAX_MAX || get_errno() != 459 ERANGE); 460 width = (int)uwidth;
|
447 if (*f == '.') { 448 f++; 449 goto label_precision; 450 } else 451 goto label_length;
| |
452 break;
| 461 break;
|
453 } case '.': 454 f++; 455 goto label_precision; 456 default: goto label_length;
| 462 } default: 463 break;
|
457 }
| 464 }
|
| 465 /* Width/precision separator. */ 466 if (*f == '.') 467 f++; 468 else 469 goto label_length;
|
458 /* Precision. */
| 470 /* Precision. */
|
459 label_precision:
| |
460 switch (*f) { 461 case '*': 462 prec = va_arg(ap, int); 463 f++; 464 break; 465 case '0': case '1': case '2': case '3': case '4': 466 case '5': case '6': case '7': case '8': case '9': { 467 uintmax_t uprec; 468 set_errno(0); 469 uprec = malloc_strtoumax(f, (char **)&f, 10); 470 assert(uprec != UINTMAX_MAX || get_errno() != 471 ERANGE); 472 prec = (int)uprec; 473 break; 474 } 475 default: break; 476 } 477 /* Length. */ 478 label_length: 479 switch (*f) { 480 case 'l': 481 f++; 482 if (*f == 'l') { 483 len = 'q'; 484 f++; 485 } else 486 len = 'l'; 487 break;
| 471 switch (*f) { 472 case '*': 473 prec = va_arg(ap, int); 474 f++; 475 break; 476 case '0': case '1': case '2': case '3': case '4': 477 case '5': case '6': case '7': case '8': case '9': { 478 uintmax_t uprec; 479 set_errno(0); 480 uprec = malloc_strtoumax(f, (char **)&f, 10); 481 assert(uprec != UINTMAX_MAX || get_errno() != 482 ERANGE); 483 prec = (int)uprec; 484 break; 485 } 486 default: break; 487 } 488 /* Length. */ 489 label_length: 490 switch (*f) { 491 case 'l': 492 f++; 493 if (*f == 'l') { 494 len = 'q'; 495 f++; 496 } else 497 len = 'l'; 498 break;
|
488 case 'j': 489 len = 'j';
| 499 case 'q': case 'j': case 't': case 'z': 500 len = *f;
|
490 f++; 491 break;
| 501 f++; 502 break;
|
492 case 't': 493 len = 't'; 494 f++; 495 break; 496 case 'z': 497 len = 'z'; 498 f++; 499 break;
| |
500 default: break; 501 } 502 /* Conversion specifier. */ 503 switch (*f) { 504 char *s; 505 size_t slen;
| 503 default: break; 504 } 505 /* Conversion specifier. */ 506 switch (*f) { 507 char *s; 508 size_t slen;
|
| 509 case '%': 510 /* %% */ 511 APPEND_C(*f); 512 f++; 513 break;
|
506 case 'd': case 'i': { 507 intmax_t val JEMALLOC_CC_SILENCE_INIT(0); 508 char buf[D2S_BUFSIZE]; 509 510 GET_ARG_NUMERIC(val, len); 511 s = d2s(val, (plus_plus ? '+' : (plus_space ? 512 ' ' : '-')), buf, &slen); 513 APPEND_PADDED_S(s, slen, width, left_justify); 514 f++; 515 break; 516 } case 'o': { 517 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 518 char buf[O2S_BUFSIZE]; 519 520 GET_ARG_NUMERIC(val, len | 0x80); 521 s = o2s(val, alt_form, buf, &slen); 522 APPEND_PADDED_S(s, slen, width, left_justify); 523 f++; 524 break; 525 } case 'u': { 526 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 527 char buf[U2S_BUFSIZE]; 528 529 GET_ARG_NUMERIC(val, len | 0x80); 530 s = u2s(val, 10, false, buf, &slen); 531 APPEND_PADDED_S(s, slen, width, left_justify); 532 f++; 533 break; 534 } case 'x': case 'X': { 535 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 536 char buf[X2S_BUFSIZE]; 537 538 GET_ARG_NUMERIC(val, len | 0x80); 539 s = x2s(val, alt_form, *f == 'X', buf, &slen); 540 APPEND_PADDED_S(s, slen, width, left_justify); 541 f++; 542 break; 543 } case 'c': { 544 unsigned char val; 545 char buf[2]; 546 547 assert(len == '?' || len == 'l'); 548 assert_not_implemented(len != 'l'); 549 val = va_arg(ap, int); 550 buf[0] = val; 551 buf[1] = '\0'; 552 APPEND_PADDED_S(buf, 1, width, left_justify); 553 f++; 554 break; 555 } case 's': 556 assert(len == '?' || len == 'l'); 557 assert_not_implemented(len != 'l'); 558 s = va_arg(ap, char *);
| 514 case 'd': case 'i': { 515 intmax_t val JEMALLOC_CC_SILENCE_INIT(0); 516 char buf[D2S_BUFSIZE]; 517 518 GET_ARG_NUMERIC(val, len); 519 s = d2s(val, (plus_plus ? '+' : (plus_space ? 520 ' ' : '-')), buf, &slen); 521 APPEND_PADDED_S(s, slen, width, left_justify); 522 f++; 523 break; 524 } case 'o': { 525 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 526 char buf[O2S_BUFSIZE]; 527 528 GET_ARG_NUMERIC(val, len | 0x80); 529 s = o2s(val, alt_form, buf, &slen); 530 APPEND_PADDED_S(s, slen, width, left_justify); 531 f++; 532 break; 533 } case 'u': { 534 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 535 char buf[U2S_BUFSIZE]; 536 537 GET_ARG_NUMERIC(val, len | 0x80); 538 s = u2s(val, 10, false, buf, &slen); 539 APPEND_PADDED_S(s, slen, width, left_justify); 540 f++; 541 break; 542 } case 'x': case 'X': { 543 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 544 char buf[X2S_BUFSIZE]; 545 546 GET_ARG_NUMERIC(val, len | 0x80); 547 s = x2s(val, alt_form, *f == 'X', buf, &slen); 548 APPEND_PADDED_S(s, slen, width, left_justify); 549 f++; 550 break; 551 } case 'c': { 552 unsigned char val; 553 char buf[2]; 554 555 assert(len == '?' || len == 'l'); 556 assert_not_implemented(len != 'l'); 557 val = va_arg(ap, int); 558 buf[0] = val; 559 buf[1] = '\0'; 560 APPEND_PADDED_S(buf, 1, width, left_justify); 561 f++; 562 break; 563 } case 's': 564 assert(len == '?' || len == 'l'); 565 assert_not_implemented(len != 'l'); 566 s = va_arg(ap, char *);
|
559 slen = (prec == -1) ? strlen(s) : prec;
| 567 slen = (prec < 0) ? strlen(s) : prec;
|
560 APPEND_PADDED_S(s, slen, width, left_justify); 561 f++; 562 break; 563 case 'p': { 564 uintmax_t val; 565 char buf[X2S_BUFSIZE]; 566 567 GET_ARG_NUMERIC(val, 'p'); 568 s = x2s(val, true, false, buf, &slen); 569 APPEND_PADDED_S(s, slen, width, left_justify); 570 f++; 571 break;
| 568 APPEND_PADDED_S(s, slen, width, left_justify); 569 f++; 570 break; 571 case 'p': { 572 uintmax_t val; 573 char buf[X2S_BUFSIZE]; 574 575 GET_ARG_NUMERIC(val, 'p'); 576 s = x2s(val, true, false, buf, &slen); 577 APPEND_PADDED_S(s, slen, width, left_justify); 578 f++; 579 break;
|
| 580 } default: not_reached();
|
572 }
| 581 }
|
573 default: not_implemented(); 574 }
| |
575 break; 576 } default: { 577 APPEND_C(*f); 578 f++; 579 break; 580 }} 581 } 582 label_out: 583 if (i < size) 584 str[i] = '\0'; 585 else 586 str[size - 1] = '\0'; 587 ret = i; 588 589#undef APPEND_C 590#undef APPEND_S 591#undef APPEND_PADDED_S 592#undef GET_ARG_NUMERIC 593 return (ret); 594} 595 596JEMALLOC_ATTR(format(printf, 3, 4)) 597int 598malloc_snprintf(char *str, size_t size, const char *format, ...) 599{ 600 int ret; 601 va_list ap; 602 603 va_start(ap, format); 604 ret = malloc_vsnprintf(str, size, format, ap); 605 va_end(ap); 606 607 return (ret); 608} 609 610void 611malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque, 612 const char *format, va_list ap) 613{ 614 char buf[MALLOC_PRINTF_BUFSIZE]; 615 616 if (write_cb == NULL) { 617 /* 618 * The caller did not provide an alternate write_cb callback 619 * function, so use the default one. malloc_write() is an 620 * inline function, so use malloc_message() directly here. 621 */ 622 write_cb = (je_malloc_message != NULL) ? je_malloc_message : 623 wrtmessage; 624 cbopaque = NULL; 625 } 626 627 malloc_vsnprintf(buf, sizeof(buf), format, ap); 628 write_cb(cbopaque, buf); 629} 630 631/* 632 * Print to a callback function in such a way as to (hopefully) avoid memory 633 * allocation. 634 */ 635JEMALLOC_ATTR(format(printf, 3, 4)) 636void 637malloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque, 638 const char *format, ...) 639{ 640 va_list ap; 641 642 va_start(ap, format); 643 malloc_vcprintf(write_cb, cbopaque, format, ap); 644 va_end(ap); 645} 646 647/* Print to stderr in such a way as to avoid memory allocation. */ 648JEMALLOC_ATTR(format(printf, 1, 2)) 649void 650malloc_printf(const char *format, ...) 651{ 652 va_list ap; 653 654 va_start(ap, format); 655 malloc_vcprintf(NULL, NULL, format, ap); 656 va_end(ap); 657}
| 582 break; 583 } default: { 584 APPEND_C(*f); 585 f++; 586 break; 587 }} 588 } 589 label_out: 590 if (i < size) 591 str[i] = '\0'; 592 else 593 str[size - 1] = '\0'; 594 ret = i; 595 596#undef APPEND_C 597#undef APPEND_S 598#undef APPEND_PADDED_S 599#undef GET_ARG_NUMERIC 600 return (ret); 601} 602 603JEMALLOC_ATTR(format(printf, 3, 4)) 604int 605malloc_snprintf(char *str, size_t size, const char *format, ...) 606{ 607 int ret; 608 va_list ap; 609 610 va_start(ap, format); 611 ret = malloc_vsnprintf(str, size, format, ap); 612 va_end(ap); 613 614 return (ret); 615} 616 617void 618malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque, 619 const char *format, va_list ap) 620{ 621 char buf[MALLOC_PRINTF_BUFSIZE]; 622 623 if (write_cb == NULL) { 624 /* 625 * The caller did not provide an alternate write_cb callback 626 * function, so use the default one. malloc_write() is an 627 * inline function, so use malloc_message() directly here. 628 */ 629 write_cb = (je_malloc_message != NULL) ? je_malloc_message : 630 wrtmessage; 631 cbopaque = NULL; 632 } 633 634 malloc_vsnprintf(buf, sizeof(buf), format, ap); 635 write_cb(cbopaque, buf); 636} 637 638/* 639 * Print to a callback function in such a way as to (hopefully) avoid memory 640 * allocation. 641 */ 642JEMALLOC_ATTR(format(printf, 3, 4)) 643void 644malloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque, 645 const char *format, ...) 646{ 647 va_list ap; 648 649 va_start(ap, format); 650 malloc_vcprintf(write_cb, cbopaque, format, ap); 651 va_end(ap); 652} 653 654/* Print to stderr in such a way as to avoid memory allocation. */ 655JEMALLOC_ATTR(format(printf, 1, 2)) 656void 657malloc_printf(const char *format, ...) 658{ 659 va_list ap; 660 661 va_start(ap, format); 662 malloc_vcprintf(NULL, NULL, format, ap); 663 va_end(ap); 664}
|