2
0

malloc_io.c 14 KB

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