00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include <stdint.h>
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <unistd.h>
00044 #include <fcntl.h>
00045 #include <err.h>
00046
00047
00048 #define _PATH_RANDOM "random:"
00049
00050 #define SMALLSIZE 72
00051 #define MEDIUMSIZE 896
00052 #define BIGSIZE 16384
00053 #define HUGESIZE (1024 * 1024 * 1024)
00054
00055
00056 #define OVERHEAD 32
00057
00058
00059 #define ABSURD_OVERHEAD 256
00060
00061 static
00062 int
00063 geti(void)
00064 {
00065 int val=0;
00066 int ch, digits=0;
00067
00068 while (1) {
00069 ch = getchar();
00070 if (ch=='\n' || ch=='\r') {
00071 putchar('\n');
00072 break;
00073 }
00074 else if ((ch=='\b' || ch==127) && digits>0) {
00075 printf("\b \b");
00076 val = val/10;
00077 digits--;
00078 }
00079 else if (ch>='0' && ch<='9') {
00080 putchar(ch);
00081 val = val*10 + (ch-'0');
00082 digits++;
00083 }
00084 else {
00085 putchar('\a');
00086 }
00087 }
00088
00089 if (digits==0) {
00090 return -1;
00091 }
00092 return val;
00093 }
00094
00095
00096
00097
00098
00099
00100 static
00101 void
00102 markblock(volatile void *ptr, size_t size, unsigned bias, int doprint)
00103 {
00104 size_t n, i;
00105 unsigned long *pl;
00106 unsigned long val;
00107
00108 pl = (unsigned long *)ptr;
00109 n = size / sizeof(unsigned long);
00110
00111 for (i=0; i<n; i++) {
00112 val = ((unsigned long)i ^ (unsigned long)bias);
00113 pl[i] = val;
00114 if (doprint && (i%64==63)) {
00115 printf(".");
00116 }
00117 }
00118 if (doprint) {
00119 printf("\n");
00120 }
00121 }
00122
00123
00124
00125
00126 static
00127 int
00128 checkblock(volatile void *ptr, size_t size, unsigned bias, int doprint)
00129 {
00130 size_t n, i;
00131 unsigned long *pl;
00132 unsigned long val;
00133
00134 pl = (unsigned long *)ptr;
00135 n = size / sizeof(unsigned long);
00136
00137 for (i=0; i<n; i++) {
00138 val = ((unsigned long)i ^ (unsigned long)bias);
00139 if (pl[i] != val) {
00140 if (doprint) {
00141 printf("\n");
00142 }
00143 printf("FAILED: data mismatch at offset %lu of block "
00144 "at 0x%lx: %lu vs. %lu\n",
00145 (unsigned long) (i*sizeof(unsigned long)),
00146 (unsigned long)(uintptr_t)pl,
00147 pl[i], val);
00148 return -1;
00149 }
00150 if (doprint && (i%64==63)) {
00151 printf(".");
00152 }
00153 }
00154 if (doprint) {
00155 printf("\n");
00156 }
00157
00158 return 0;
00159 }
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 static
00171 void
00172 test1(void)
00173 {
00174 volatile unsigned *x;
00175
00176 printf("*** Malloc test 1 ***\n");
00177 printf("Allocating %u bytes\n", BIGSIZE);
00178 x = malloc(BIGSIZE);
00179 if (x==NULL) {
00180 printf("FAILED: malloc failed\n");
00181 return;
00182 }
00183
00184 markblock(x, BIGSIZE, 0, 0);
00185 if (checkblock(x, BIGSIZE, 0, 0)) {
00186 printf("FAILED: data corrupt\n");
00187 return;
00188 }
00189
00190 free((void *)x);
00191
00192 printf("Passed malloc test 1.\n");
00193 }
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 static
00229 void
00230 test2(void)
00231 {
00232 volatile unsigned *x;
00233 size_t size;
00234
00235 printf("Entering malloc test 2.\n");
00236 printf("Make sure you read and understand the comment in malloctest.c "
00237 "that\nexplains the conditions this test assumes.\n\n");
00238
00239 printf("Testing how much memory we can allocate:\n");
00240
00241 for (size = HUGESIZE; (x = malloc(size))==NULL; size = size/2) {
00242 printf(" %9lu bytes: failed\n", (unsigned long) size);
00243 }
00244 printf(" %9lu bytes: succeeded\n", (unsigned long) size);
00245
00246 printf("Passed part 1\n");
00247
00248 printf("Touching all the words in the block.\n");
00249 markblock(x, size, 0, 1);
00250
00251 printf("Validating the words in the block.\n");
00252 if (checkblock(x, size, 0, 1)) {
00253 printf("FAILED: data corrupt\n");
00254 return;
00255 }
00256 printf("Passed part 2\n");
00257
00258
00259 printf("Freeing the block\n");
00260 free((void *)x);
00261 printf("Passed part 3\n");
00262 printf("Allocating another block\n");
00263
00264 x = malloc(size);
00265 if (x==NULL) {
00266 printf("FAILED: free didn't return the memory?\n");
00267 return;
00268 }
00269 free((void *)x);
00270
00271 printf("Passed malloc test 2.\n");
00272 }
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 struct test3 {
00289 struct test3 *next;
00290 char junk[(SMALLSIZE - sizeof(struct test3 *))];
00291 };
00292
00293 static
00294 void
00295 test3(void)
00296 {
00297 struct test3 *list = NULL, *tmp;
00298 size_t tot=0;
00299 int ct=0, failed=0;
00300 void *x;
00301
00302 printf("Entering malloc test 3.\n");
00303 printf("Make sure you read and understand the comment in malloctest.c "
00304 "that\nexplains the conditions this test assumes.\n\n");
00305
00306 printf("Testing how much memory we can allocate:\n");
00307
00308 while ((tmp = malloc(sizeof(struct test3))) != NULL) {
00309
00310 tmp->next = list;
00311 list = tmp;
00312
00313 tot += sizeof(struct test3);
00314
00315 markblock(list->junk, sizeof(list->junk), (uintptr_t)list, 0);
00316
00317 ct++;
00318 if (ct%128==0) {
00319 printf(".");
00320 }
00321 }
00322
00323 printf("Allocated %lu bytes\n", (unsigned long) tot);
00324
00325 printf("Trying some more allocations which I expect to fail...\n");
00326
00327 x = malloc(SMALLSIZE);
00328 if (x != NULL) {
00329 printf("FAILED: malloc(%u) succeeded\n", SMALLSIZE);
00330 return;
00331 }
00332
00333 x = malloc(MEDIUMSIZE);
00334 if (x != NULL) {
00335 printf("FAILED: malloc(%u) succeeded\n", MEDIUMSIZE);
00336 return;
00337 }
00338
00339 x = malloc(BIGSIZE);
00340 if (x != NULL) {
00341 printf("FAILED: malloc(%u) succeeded\n", BIGSIZE);
00342 return;
00343 }
00344
00345 printf("Ok, now I'm going to free everything...\n");
00346
00347 while (list != NULL) {
00348 tmp = list->next;
00349
00350 if (checkblock(list->junk, sizeof(list->junk),
00351 (uintptr_t)list, 0)) {
00352 failed = 1;
00353 }
00354
00355 free(list);
00356 list = tmp;
00357 }
00358
00359 if (failed) {
00360 printf("FAILED: data corruption\n");
00361 return;
00362 }
00363
00364 printf("Let me see if I can allocate some more now...\n");
00365
00366 x = malloc(MEDIUMSIZE);
00367 if (x == NULL) {
00368 printf("FAIL: Nope, I couldn't.\n");
00369 return;
00370 }
00371 free(x);
00372
00373 printf("Passed malloc test 3\n");
00374 }
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 static
00388 void
00389 test4(void)
00390 {
00391 void *x, *y, *z;
00392 unsigned long lx, ly, lz, overhead, zsize;
00393
00394 printf("Entering malloc test 4.\n");
00395 printf("This test is intended for first/best-fit based mallocs.\n");
00396 printf("This test may not work correctly if run after other tests.\n");
00397
00398 printf("Testing free list coalescing:\n");
00399
00400 x = malloc(SMALLSIZE);
00401 if (x==NULL) {
00402 printf("FAILED: malloc(%u) failed\n", SMALLSIZE);
00403 return;
00404 }
00405
00406 y = malloc(MEDIUMSIZE);
00407 if (y==NULL) {
00408 printf("FAILED: malloc(%u) failed\n", MEDIUMSIZE);
00409 return;
00410 }
00411
00412 if (sizeof(unsigned long) < sizeof(void *)) {
00413 printf("Buh? I can't fit a void * in an unsigned long\n");
00414 printf("ENVIRONMENT FAILED...\n");
00415 return;
00416 }
00417
00418 lx = (unsigned long)x;
00419 ly = (unsigned long)y;
00420
00421 printf("x is 0x%lx; y is 0x%lx\n", lx, ly);
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 if (lx == ly) {
00433 printf("FAIL: x == y\n");
00434 return;
00435 }
00436
00437
00438
00439
00440
00441
00442
00443 if (lx < ly && lx + SMALLSIZE > ly) {
00444 printf("FAIL: y starts within x\n");
00445 return;
00446 }
00447 if (ly < lx && ly + MEDIUMSIZE > lx) {
00448 printf("FAIL: x starts within y\n");
00449 return;
00450 }
00451
00452
00453
00454
00455
00456
00457 if (ly < lx) {
00458 printf("TEST UNSUITABLE: y is below x\n");
00459 return;
00460 }
00461
00462
00463
00464
00465 overhead = ly - (lx + SMALLSIZE);
00466 printf("Apparent block overhead: %lu\n", overhead);
00467
00468 if (overhead > ABSURD_OVERHEAD) {
00469 printf("TEST UNSUITABLE: block overhead absurdly large.\n");
00470 return;
00471 }
00472 if (overhead > OVERHEAD) {
00473 printf("FAIL: block overhead is too large.\n");
00474 return;
00475 }
00476
00477 printf("Freeing blocks...\n");
00478 free(x);
00479 free(y);
00480
00481 zsize = SMALLSIZE + MEDIUMSIZE + overhead;
00482
00483 printf("Now allocating %lu bytes... should reuse the space.\n", zsize);
00484 z = malloc(zsize);
00485 if (z == NULL) {
00486 printf("FAIL: Allocation failed...\n");
00487 return;
00488 }
00489
00490 lz = (unsigned long) z;
00491
00492 printf("z is 0x%lx (x was 0x%lx, y 0x%lx)\n", lz, lx, ly);
00493
00494 if (lz==lx) {
00495 printf("Passed.\n");
00496 }
00497 else {
00498 printf("Failed.\n");
00499 }
00500
00501 free(z);
00502 }
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 static
00517 void
00518 test567(int testno, unsigned long seed)
00519 {
00520 static const int sizes[8] = { 13, 17, 69, 176, 433, 871, 1150, 6060 };
00521
00522 void *ptrs[32];
00523 int psizes[32];
00524 int i, n, size, failed=0;
00525
00526 srandom(seed);
00527 printf("Seeded random number generator with %lu.\n", seed);
00528
00529 for (i=0; i<32; i++) {
00530 ptrs[i] = NULL;
00531 psizes[i] = 0;
00532 }
00533
00534 for (i=0; i<100000; i++) {
00535 n = random()%32;
00536 if (ptrs[n] == NULL) {
00537 size = sizes[random()%8];
00538 ptrs[n] = malloc(size);
00539 psizes[n] = size;
00540 if (ptrs[n] == NULL) {
00541 printf("\nmalloc %u failed\n", size);
00542 failed = 1;
00543 break;
00544 }
00545 markblock(ptrs[n], size, n, 0);
00546 }
00547 else {
00548 size = psizes[n];
00549 if (checkblock(ptrs[n], size, n, 0)) {
00550 failed = 1;
00551 break;
00552 }
00553 free(ptrs[n]);
00554 ptrs[n] = NULL;
00555 psizes[n] = 0;
00556 }
00557 if (i%256==0) {
00558 printf(".");
00559 }
00560 }
00561 printf("\n");
00562
00563 for (i=0; i<32; i++) {
00564 if (ptrs[i] != NULL) {
00565 free(ptrs[i]);
00566 }
00567 }
00568
00569 if (failed) {
00570 printf("FAILED malloc test %d\n", testno);
00571 }
00572 else {
00573 printf("Passed malloc test %d\n", testno);
00574 }
00575 }
00576
00577 static
00578 void
00579 test5(void)
00580 {
00581 printf("Beginning malloc test 5\n");
00582 test567(5, 0);
00583 }
00584
00585 static
00586 void
00587 test6(void)
00588 {
00589 int fd, len;
00590 unsigned long seed;
00591
00592 printf("Beginning malloc test 6\n");
00593
00594 fd = open(_PATH_RANDOM, O_RDONLY);
00595 if (fd < 0) {
00596 err(1, "%s", _PATH_RANDOM);
00597 }
00598 len = read(fd, &seed, sizeof(seed));
00599 if (len < 0) {
00600 err(1, "%s", _PATH_RANDOM);
00601 }
00602 else if (len < (int)sizeof(seed)) {
00603 errx(1, "%s: Short read", _PATH_RANDOM);
00604 }
00605 close(fd);
00606
00607 test567(6, seed);
00608 }
00609
00610 static
00611 void
00612 test7(void)
00613 {
00614 unsigned long seed;
00615
00616 printf("Beginning malloc test 7\n");
00617
00618 printf("Enter random seed: ");
00619 seed = geti();
00620
00621 test567(7, seed);
00622 }
00623
00624
00625
00626 static struct {
00627 int num;
00628 const char *desc;
00629 void (*func)(void);
00630 } tests[] = {
00631 { 1, "Simple allocation test", test1 },
00632 { 2, "Allocate all memory in a big chunk", test2 },
00633 { 3, "Allocate all memory in small chunks", test3 },
00634 { 4, "Free list coalescing test (first/next/best-fit only)", test4 },
00635 { 5, "Stress test", test5 },
00636 { 6, "Randomized stress test", test6 },
00637 { 7, "Stress test with particular seed", test7 },
00638 { -1, NULL, NULL }
00639 };
00640
00641 static
00642 int
00643 dotest(int tn)
00644 {
00645 int i;
00646 for (i=0; tests[i].num>=0; i++) {
00647 if (tests[i].num == tn) {
00648 tests[i].func();
00649 return 0;
00650 }
00651 }
00652 return -1;
00653 }
00654
00655 int
00656 main(int argc, char *argv[])
00657 {
00658 int i, tn, menu=1;
00659
00660 if (argc > 1) {
00661 for (i=1; i<argc; i++) {
00662 dotest(atoi(argv[i]));
00663 }
00664 return 0;
00665 }
00666
00667 while (1) {
00668 if (menu) {
00669 for (i=0; tests[i].num>=0; i++) {
00670 printf(" %2d %s\n", tests[i].num,
00671 tests[i].desc);
00672 }
00673 menu = 0;
00674 }
00675 printf("malloctest: ");
00676 tn = geti();
00677 if (tn < 0) {
00678 break;
00679 }
00680
00681 if (dotest(tn)) {
00682 menu = 1;
00683 }
00684 }
00685
00686 return 0;
00687 }
00688