malloctest.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. /*
  2. * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
  3. * The President and Fellows of Harvard College.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. /*
  30. * malloctest.c
  31. *
  32. * This program contains a variety of tests for malloc and free.
  33. * XXX most tests leak on error.
  34. *
  35. * These tests (subject to restrictions and limitations noted below) should
  36. * work once user-level malloc is implemented.
  37. */
  38. #include <stdint.h>
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <unistd.h>
  42. #include <fcntl.h>
  43. #include <err.h>
  44. #define _PATH_RANDOM "random:"
  45. #define SMALLSIZE 72
  46. #define MEDIUMSIZE 896
  47. #define BIGSIZE 16384
  48. #define HUGESIZE (1024 * 1024 * 1024)
  49. /* Maximum amount of space per block we allow for indexing structures */
  50. #define OVERHEAD 32
  51. /* Point past which we assume something else is going on */
  52. #define ABSURD_OVERHEAD 256
  53. static
  54. int
  55. geti(void)
  56. {
  57. int val=0;
  58. int ch, digits=0;
  59. while (1) {
  60. ch = getchar();
  61. if (ch=='\n' || ch=='\r') {
  62. putchar('\n');
  63. break;
  64. }
  65. else if ((ch=='\b' || ch==127) && digits>0) {
  66. printf("\b \b");
  67. val = val/10;
  68. digits--;
  69. }
  70. else if (ch>='0' && ch<='9') {
  71. putchar(ch);
  72. val = val*10 + (ch-'0');
  73. digits++;
  74. }
  75. else {
  76. putchar('\a');
  77. }
  78. }
  79. if (digits==0) {
  80. return -1;
  81. }
  82. return val;
  83. }
  84. ////////////////////////////////////////////////////////////
  85. /*
  86. * Fill a block of memory with a test pattern.
  87. */
  88. static
  89. void
  90. markblock(volatile void *ptr, size_t size, unsigned bias, int doprint)
  91. {
  92. size_t n, i;
  93. unsigned long *pl;
  94. unsigned long val;
  95. pl = (unsigned long *)ptr;
  96. n = size / sizeof(unsigned long);
  97. for (i=0; i<n; i++) {
  98. val = ((unsigned long)i ^ (unsigned long)bias);
  99. pl[i] = val;
  100. if (doprint && (i%64==63)) {
  101. printf(".");
  102. }
  103. }
  104. if (doprint) {
  105. printf("\n");
  106. }
  107. }
  108. /*
  109. * Check a block marked with markblock()
  110. */
  111. static
  112. int
  113. checkblock(volatile void *ptr, size_t size, unsigned bias, int doprint)
  114. {
  115. size_t n, i;
  116. unsigned long *pl;
  117. unsigned long val;
  118. pl = (unsigned long *)ptr;
  119. n = size / sizeof(unsigned long);
  120. for (i=0; i<n; i++) {
  121. val = ((unsigned long)i ^ (unsigned long)bias);
  122. if (pl[i] != val) {
  123. if (doprint) {
  124. printf("\n");
  125. }
  126. printf("FAILED: data mismatch at offset %lu of block "
  127. "at 0x%lx: %lu vs. %lu\n",
  128. (unsigned long) (i*sizeof(unsigned long)),
  129. (unsigned long)(uintptr_t)pl,
  130. pl[i], val);
  131. return -1;
  132. }
  133. if (doprint && (i%64==63)) {
  134. printf(".");
  135. }
  136. }
  137. if (doprint) {
  138. printf("\n");
  139. }
  140. return 0;
  141. }
  142. ////////////////////////////////////////////////////////////
  143. /*
  144. * Test 1
  145. *
  146. * This test checks if all the bytes we asked for are getting
  147. * allocated.
  148. */
  149. static
  150. void
  151. test1(void)
  152. {
  153. volatile unsigned *x;
  154. printf("*** Malloc test 1 ***\n");
  155. printf("Allocating %u bytes\n", BIGSIZE);
  156. x = malloc(BIGSIZE);
  157. if (x==NULL) {
  158. printf("FAILED: malloc failed\n");
  159. return;
  160. }
  161. markblock(x, BIGSIZE, 0, 0);
  162. if (checkblock(x, BIGSIZE, 0, 0)) {
  163. printf("FAILED: data corrupt\n");
  164. return;
  165. }
  166. free((void *)x);
  167. printf("Passed malloc test 1.\n");
  168. }
  169. ////////////////////////////////////////////////////////////
  170. /*
  171. * Test 2
  172. *
  173. * Tests if malloc gracefully handles failing requests.
  174. *
  175. * This test assumes that one of the following conditions holds:
  176. * 1. swap is not overcommitted; or
  177. * 2. user processes are limited to some maximum size, and enough
  178. * swap exists to hold a maximal user process.
  179. *
  180. * That is, it assumes that malloc returns NULL when out of memory,
  181. * and that the process will not be killed for running out of
  182. * memory/swap at other times.
  183. *
  184. * If mallocing more memory than the system can actually provide
  185. * backing for succeeds, this test will blow up. That's ok, but please
  186. * provide a way to switch on one of the above conditions so this test
  187. * can be run.
  188. *
  189. * This test works by trying a huge malloc, and then trying
  190. * successively smaller mallocs until one works. Then it touches the
  191. * whole block to make sure the memory is actually successfully
  192. * allocated. Then it frees the block and allocates it again, which
  193. * should succeed.
  194. *
  195. * Note that this test may give spurious failures if anything else is
  196. * running at the same time and changing the amount of memory
  197. * available.
  198. */
  199. static
  200. void
  201. test2(void)
  202. {
  203. volatile unsigned *x;
  204. size_t size;
  205. printf("Entering malloc test 2.\n");
  206. printf("Make sure you read and understand the comment in malloctest.c "
  207. "that\nexplains the conditions this test assumes.\n\n");
  208. printf("Testing how much memory we can allocate:\n");
  209. for (size = HUGESIZE; (x = malloc(size))==NULL; size = size/2) {
  210. printf(" %9lu bytes: failed\n", (unsigned long) size);
  211. }
  212. printf(" %9lu bytes: succeeded\n", (unsigned long) size);
  213. printf("Passed part 1\n");
  214. printf("Touching all the words in the block.\n");
  215. markblock(x, size, 0, 1);
  216. printf("Validating the words in the block.\n");
  217. if (checkblock(x, size, 0, 1)) {
  218. printf("FAILED: data corrupt\n");
  219. return;
  220. }
  221. printf("Passed part 2\n");
  222. printf("Freeing the block\n");
  223. free((void *)x);
  224. printf("Passed part 3\n");
  225. printf("Allocating another block\n");
  226. x = malloc(size);
  227. if (x==NULL) {
  228. printf("FAILED: free didn't return the memory?\n");
  229. return;
  230. }
  231. free((void *)x);
  232. printf("Passed malloc test 2.\n");
  233. }
  234. ////////////////////////////////////////////////////////////
  235. /*
  236. * Test 3
  237. *
  238. * Tests if malloc gracefully handles failing requests.
  239. *
  240. * This test assumes the same conditions as test 2.
  241. *
  242. * This test works by mallocing a lot of small blocks in a row until
  243. * malloc starts failing.
  244. */
  245. struct test3 {
  246. struct test3 *next;
  247. char junk[(SMALLSIZE - sizeof(struct test3 *))];
  248. };
  249. static
  250. void
  251. test3(void)
  252. {
  253. struct test3 *list = NULL, *tmp;
  254. size_t tot=0;
  255. int ct=0, failed=0;
  256. void *x;
  257. printf("Entering malloc test 3.\n");
  258. printf("Make sure you read and understand the comment in malloctest.c "
  259. "that\nexplains the conditions this test assumes.\n\n");
  260. printf("Testing how much memory we can allocate:\n");
  261. while ((tmp = malloc(sizeof(struct test3))) != NULL) {
  262. tmp->next = list;
  263. list = tmp;
  264. tot += sizeof(struct test3);
  265. markblock(list->junk, sizeof(list->junk), (uintptr_t)list, 0);
  266. ct++;
  267. if (ct%128==0) {
  268. printf(".");
  269. }
  270. }
  271. printf("Allocated %lu bytes\n", (unsigned long) tot);
  272. printf("Trying some more allocations which I expect to fail...\n");
  273. x = malloc(SMALLSIZE);
  274. if (x != NULL) {
  275. printf("FAILED: malloc(%u) succeeded\n", SMALLSIZE);
  276. return;
  277. }
  278. x = malloc(MEDIUMSIZE);
  279. if (x != NULL) {
  280. printf("FAILED: malloc(%u) succeeded\n", MEDIUMSIZE);
  281. return;
  282. }
  283. x = malloc(BIGSIZE);
  284. if (x != NULL) {
  285. printf("FAILED: malloc(%u) succeeded\n", BIGSIZE);
  286. return;
  287. }
  288. printf("Ok, now I'm going to free everything...\n");
  289. while (list != NULL) {
  290. tmp = list->next;
  291. if (checkblock(list->junk, sizeof(list->junk),
  292. (uintptr_t)list, 0)) {
  293. failed = 1;
  294. }
  295. free(list);
  296. list = tmp;
  297. }
  298. if (failed) {
  299. printf("FAILED: data corruption\n");
  300. return;
  301. }
  302. printf("Let me see if I can allocate some more now...\n");
  303. x = malloc(MEDIUMSIZE);
  304. if (x == NULL) {
  305. printf("FAIL: Nope, I couldn't.\n");
  306. return;
  307. }
  308. free(x);
  309. printf("Passed malloc test 3\n");
  310. }
  311. ////////////////////////////////////////////////////////////
  312. /*
  313. * Test 4
  314. *
  315. * Tries to test in detail if malloc coalesces the free list properly.
  316. *
  317. * This test will likely fail if something other than a basic first-fit/
  318. * next-fit/best-fit algorithm is used.
  319. */
  320. static
  321. void
  322. test4(void)
  323. {
  324. void *x, *y, *z;
  325. unsigned long lx, ly, lz, overhead, zsize;
  326. printf("Entering malloc test 4.\n");
  327. printf("This test is intended for first/best-fit based mallocs.\n");
  328. printf("This test may not work correctly if run after other tests.\n");
  329. printf("Testing free list coalescing:\n");
  330. x = malloc(SMALLSIZE);
  331. if (x==NULL) {
  332. printf("FAILED: malloc(%u) failed\n", SMALLSIZE);
  333. return;
  334. }
  335. y = malloc(MEDIUMSIZE);
  336. if (y==NULL) {
  337. printf("FAILED: malloc(%u) failed\n", MEDIUMSIZE);
  338. return;
  339. }
  340. if (sizeof(unsigned long) < sizeof(void *)) {
  341. printf("Buh? I can't fit a void * in an unsigned long\n");
  342. printf("ENVIRONMENT FAILED...\n");
  343. return;
  344. }
  345. lx = (unsigned long)x;
  346. ly = (unsigned long)y;
  347. printf("x is 0x%lx; y is 0x%lx\n", lx, ly);
  348. /*
  349. * The memory should look something like this:
  350. *
  351. * OXXXOYYYYYYYYYYY
  352. *
  353. * where O are optional overhead (indexing) blocks.
  354. */
  355. /* This is obviously wrong. */
  356. if (lx == ly) {
  357. printf("FAIL: x == y\n");
  358. return;
  359. }
  360. /*
  361. * Check for overlap. It is sufficient to check if the start
  362. * of each block is within the other block. (If the end of a
  363. * block is within the other block, either the start is too,
  364. * or the other block's start is within the first block.)
  365. */
  366. if (lx < ly && lx + SMALLSIZE > ly) {
  367. printf("FAIL: y starts within x\n");
  368. return;
  369. }
  370. if (ly < lx && ly + MEDIUMSIZE > lx) {
  371. printf("FAIL: x starts within y\n");
  372. return;
  373. }
  374. /*
  375. * If y is lower than x, some memory scheme we don't
  376. * understand is in use, or else there's already stuff on the
  377. * free list.
  378. */
  379. if (ly < lx) {
  380. printf("TEST UNSUITABLE: y is below x\n");
  381. return;
  382. }
  383. /*
  384. * Compute the space used by index structures.
  385. */
  386. overhead = ly - (lx + SMALLSIZE);
  387. printf("Apparent block overhead: %lu\n", overhead);
  388. if (overhead > ABSURD_OVERHEAD) {
  389. printf("TEST UNSUITABLE: block overhead absurdly large.\n");
  390. return;
  391. }
  392. if (overhead > OVERHEAD) {
  393. printf("FAIL: block overhead is too large.\n");
  394. return;
  395. }
  396. printf("Freeing blocks...\n");
  397. free(x);
  398. free(y);
  399. zsize = SMALLSIZE + MEDIUMSIZE + overhead;
  400. printf("Now allocating %lu bytes... should reuse the space.\n", zsize);
  401. z = malloc(zsize);
  402. if (z == NULL) {
  403. printf("FAIL: Allocation failed...\n");
  404. return;
  405. }
  406. lz = (unsigned long) z;
  407. printf("z is 0x%lx (x was 0x%lx, y 0x%lx)\n", lz, lx, ly);
  408. if (lz==lx) {
  409. printf("Passed.\n");
  410. }
  411. else {
  412. printf("Failed.\n");
  413. }
  414. free(z);
  415. }
  416. ////////////////////////////////////////////////////////////
  417. /*
  418. * Test 5/6/7
  419. *
  420. * Generally beats on malloc/free.
  421. *
  422. * Test 5 uses random seed 0.
  423. * Test 6 seeds the random number generator from random:.
  424. * Test 7 asks for a seed.
  425. */
  426. static
  427. void
  428. test567(int testno, unsigned long seed)
  429. {
  430. static const int sizes[8] = { 13, 17, 69, 176, 433, 871, 1150, 6060 };
  431. void *ptrs[32];
  432. int psizes[32];
  433. int i, n, size, failed=0;
  434. srandom(seed);
  435. printf("Seeded random number generator with %lu.\n", seed);
  436. for (i=0; i<32; i++) {
  437. ptrs[i] = NULL;
  438. psizes[i] = 0;
  439. }
  440. for (i=0; i<100000; i++) {
  441. n = random()%32;
  442. if (ptrs[n] == NULL) {
  443. size = sizes[random()%8];
  444. ptrs[n] = malloc(size);
  445. psizes[n] = size;
  446. if (ptrs[n] == NULL) {
  447. printf("\nmalloc %u failed\n", size);
  448. failed = 1;
  449. break;
  450. }
  451. markblock(ptrs[n], size, n, 0);
  452. }
  453. else {
  454. size = psizes[n];
  455. if (checkblock(ptrs[n], size, n, 0)) {
  456. failed = 1;
  457. break;
  458. }
  459. free(ptrs[n]);
  460. ptrs[n] = NULL;
  461. psizes[n] = 0;
  462. }
  463. if (i%256==0) {
  464. printf(".");
  465. }
  466. }
  467. printf("\n");
  468. for (i=0; i<32; i++) {
  469. if (ptrs[i] != NULL) {
  470. free(ptrs[i]);
  471. }
  472. }
  473. if (failed) {
  474. printf("FAILED malloc test %d\n", testno);
  475. }
  476. else {
  477. printf("Passed malloc test %d\n", testno);
  478. }
  479. }
  480. static
  481. void
  482. test5(void)
  483. {
  484. printf("Beginning malloc test 5\n");
  485. test567(5, 0);
  486. }
  487. static
  488. void
  489. test6(void)
  490. {
  491. int fd, len;
  492. unsigned long seed;
  493. printf("Beginning malloc test 6\n");
  494. fd = open(_PATH_RANDOM, O_RDONLY);
  495. if (fd < 0) {
  496. err(1, "%s", _PATH_RANDOM);
  497. }
  498. len = read(fd, &seed, sizeof(seed));
  499. if (len < 0) {
  500. err(1, "%s", _PATH_RANDOM);
  501. }
  502. else if (len < (int)sizeof(seed)) {
  503. errx(1, "%s: Short read", _PATH_RANDOM);
  504. }
  505. close(fd);
  506. test567(6, seed);
  507. }
  508. static
  509. void
  510. test7(void)
  511. {
  512. unsigned long seed;
  513. printf("Beginning malloc test 7\n");
  514. printf("Enter random seed: ");
  515. seed = geti();
  516. test567(7, seed);
  517. }
  518. ////////////////////////////////////////////////////////////
  519. static struct {
  520. int num;
  521. const char *desc;
  522. void (*func)(void);
  523. } tests[] = {
  524. { 1, "Simple allocation test", test1 },
  525. { 2, "Allocate all memory in a big chunk", test2 },
  526. { 3, "Allocate all memory in small chunks", test3 },
  527. { 4, "Free list coalescing test (first/next/best-fit only)", test4 },
  528. { 5, "Stress test", test5 },
  529. { 6, "Randomized stress test", test6 },
  530. { 7, "Stress test with particular seed", test7 },
  531. { -1, NULL, NULL }
  532. };
  533. static
  534. int
  535. dotest(int tn)
  536. {
  537. int i;
  538. for (i=0; tests[i].num>=0; i++) {
  539. if (tests[i].num == tn) {
  540. tests[i].func();
  541. return 0;
  542. }
  543. }
  544. return -1;
  545. }
  546. int
  547. main(int argc, char *argv[])
  548. {
  549. int i, tn, menu=1;
  550. if (argc > 1) {
  551. for (i=1; i<argc; i++) {
  552. dotest(atoi(argv[i]));
  553. }
  554. return 0;
  555. }
  556. while (1) {
  557. if (menu) {
  558. for (i=0; tests[i].num>=0; i++) {
  559. printf(" %2d %s\n", tests[i].num,
  560. tests[i].desc);
  561. }
  562. menu = 0;
  563. }
  564. printf("malloctest: ");
  565. tn = geti();
  566. if (tn < 0) {
  567. break;
  568. }
  569. if (dotest(tn)) {
  570. menu = 1;
  571. }
  572. }
  573. return 0;
  574. }