prof_mdump.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. #include "test/jemalloc_test.h"
  2. #include "jemalloc/internal/prof_sys.h"
  3. static const char *test_filename = "test_filename";
  4. static bool did_prof_dump_open;
  5. static int
  6. prof_dump_open_file_intercept(const char *filename, int mode) {
  7. int fd;
  8. did_prof_dump_open = true;
  9. /*
  10. * Stronger than a strcmp() - verifying that we internally directly use
  11. * the caller supplied char pointer.
  12. */
  13. expect_ptr_eq(filename, test_filename,
  14. "Dump file name should be \"%s\"", test_filename);
  15. fd = open("/dev/null", O_WRONLY);
  16. assert_d_ne(fd, -1, "Unexpected open() failure");
  17. return fd;
  18. }
  19. TEST_BEGIN(test_mdump_normal) {
  20. test_skip_if(!config_prof);
  21. prof_dump_open_file_t *open_file_orig = prof_dump_open_file;
  22. void *p = mallocx(1, 0);
  23. assert_ptr_not_null(p, "Unexpected mallocx() failure");
  24. prof_dump_open_file = prof_dump_open_file_intercept;
  25. did_prof_dump_open = false;
  26. expect_d_eq(mallctl("prof.dump", NULL, NULL, (void *)&test_filename,
  27. sizeof(test_filename)), 0,
  28. "Unexpected mallctl failure while dumping");
  29. expect_true(did_prof_dump_open, "Expected a profile dump");
  30. dallocx(p, 0);
  31. prof_dump_open_file = open_file_orig;
  32. }
  33. TEST_END
  34. static int
  35. prof_dump_open_file_error(const char *filename, int mode) {
  36. return -1;
  37. }
  38. /*
  39. * In the context of test_mdump_output_error, prof_dump_write_file_count is the
  40. * total number of times prof_dump_write_file_error() is expected to be called.
  41. * In the context of test_mdump_maps_error, prof_dump_write_file_count is the
  42. * total number of times prof_dump_write_file_error() is expected to be called
  43. * starting from the one that contains an 'M' (beginning the "MAPPED_LIBRARIES"
  44. * header).
  45. */
  46. static int prof_dump_write_file_count;
  47. static ssize_t
  48. prof_dump_write_file_error(int fd, const void *s, size_t len) {
  49. --prof_dump_write_file_count;
  50. expect_d_ge(prof_dump_write_file_count, 0,
  51. "Write is called after error occurs");
  52. if (prof_dump_write_file_count == 0) {
  53. return -1;
  54. } else {
  55. /*
  56. * Any non-negative number indicates success, and for
  57. * simplicity we just use 0. When prof_dump_write_file_count
  58. * is positive, it means that we haven't reached the write that
  59. * we want to fail; when prof_dump_write_file_count is
  60. * negative, it means that we've already violated the
  61. * expect_d_ge(prof_dump_write_file_count, 0) statement above,
  62. * but instead of aborting, we continue the rest of the test,
  63. * and we indicate that all the writes after the failed write
  64. * are successful.
  65. */
  66. return 0;
  67. }
  68. }
  69. static void
  70. expect_write_failure(int count) {
  71. prof_dump_write_file_count = count;
  72. expect_d_eq(mallctl("prof.dump", NULL, NULL, (void *)&test_filename,
  73. sizeof(test_filename)), EFAULT, "Dump should err");
  74. expect_d_eq(prof_dump_write_file_count, 0,
  75. "Dumping stopped after a wrong number of writes");
  76. }
  77. TEST_BEGIN(test_mdump_output_error) {
  78. test_skip_if(!config_prof);
  79. test_skip_if(!config_debug);
  80. prof_dump_open_file_t *open_file_orig = prof_dump_open_file;
  81. prof_dump_write_file_t *write_file_orig = prof_dump_write_file;
  82. prof_dump_write_file = prof_dump_write_file_error;
  83. void *p = mallocx(1, 0);
  84. assert_ptr_not_null(p, "Unexpected mallocx() failure");
  85. /*
  86. * When opening the dump file fails, there shouldn't be any write, and
  87. * mallctl() should return failure.
  88. */
  89. prof_dump_open_file = prof_dump_open_file_error;
  90. expect_write_failure(0);
  91. /*
  92. * When the n-th write fails, there shouldn't be any more write, and
  93. * mallctl() should return failure.
  94. */
  95. prof_dump_open_file = prof_dump_open_file_intercept;
  96. expect_write_failure(1); /* First write fails. */
  97. expect_write_failure(2); /* Second write fails. */
  98. dallocx(p, 0);
  99. prof_dump_open_file = open_file_orig;
  100. prof_dump_write_file = write_file_orig;
  101. }
  102. TEST_END
  103. static int
  104. prof_dump_open_maps_error() {
  105. return -1;
  106. }
  107. static bool started_piping_maps_file;
  108. static ssize_t
  109. prof_dump_write_maps_file_error(int fd, const void *s, size_t len) {
  110. /* The main dump doesn't contain any capital 'M'. */
  111. if (!started_piping_maps_file && strchr(s, 'M') != NULL) {
  112. started_piping_maps_file = true;
  113. }
  114. if (started_piping_maps_file) {
  115. return prof_dump_write_file_error(fd, s, len);
  116. } else {
  117. /* Return success when we haven't started piping maps. */
  118. return 0;
  119. }
  120. }
  121. static void
  122. expect_maps_write_failure(int count) {
  123. int mfd = prof_dump_open_maps();
  124. if (mfd == -1) {
  125. /* No need to continue if we just can't find the maps file. */
  126. return;
  127. }
  128. close(mfd);
  129. started_piping_maps_file = false;
  130. expect_write_failure(count);
  131. expect_true(started_piping_maps_file, "Should start piping maps");
  132. }
  133. TEST_BEGIN(test_mdump_maps_error) {
  134. test_skip_if(!config_prof);
  135. test_skip_if(!config_debug);
  136. prof_dump_open_file_t *open_file_orig = prof_dump_open_file;
  137. prof_dump_write_file_t *write_file_orig = prof_dump_write_file;
  138. prof_dump_open_maps_t *open_maps_orig = prof_dump_open_maps;
  139. prof_dump_open_file = prof_dump_open_file_intercept;
  140. prof_dump_write_file = prof_dump_write_maps_file_error;
  141. void *p = mallocx(1, 0);
  142. assert_ptr_not_null(p, "Unexpected mallocx() failure");
  143. /*
  144. * When opening the maps file fails, there shouldn't be any maps write,
  145. * and mallctl() should return success.
  146. */
  147. prof_dump_open_maps = prof_dump_open_maps_error;
  148. started_piping_maps_file = false;
  149. prof_dump_write_file_count = 0;
  150. expect_d_eq(mallctl("prof.dump", NULL, NULL, (void *)&test_filename,
  151. sizeof(test_filename)), 0,
  152. "mallctl should not fail in case of maps file opening failure");
  153. expect_false(started_piping_maps_file, "Shouldn't start piping maps");
  154. expect_d_eq(prof_dump_write_file_count, 0,
  155. "Dumping stopped after a wrong number of writes");
  156. /*
  157. * When the n-th maps write fails (given that we are able to find the
  158. * maps file), there shouldn't be any more maps write, and mallctl()
  159. * should return failure.
  160. */
  161. prof_dump_open_maps = open_maps_orig;
  162. expect_maps_write_failure(1); /* First write fails. */
  163. expect_maps_write_failure(2); /* Second write fails. */
  164. dallocx(p, 0);
  165. prof_dump_open_file = open_file_orig;
  166. prof_dump_write_file = write_file_orig;
  167. }
  168. TEST_END
  169. int
  170. main(void) {
  171. return test(
  172. test_mdump_normal,
  173. test_mdump_output_error,
  174. test_mdump_maps_error);
  175. }