PageRenderTime 51ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/jemalloc-3.0.0/src/util.c

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