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 #include <stdlib.h>
00040 #include <unistd.h>
00041 #include <err.h>
00042 #include <stdint.h>
00043
00044 #undef MALLOCDEBUG
00045
00046 #if defined(__mips__) || defined(__i386__)
00047 #define MALLOC32
00048 #elif defined(__alpha__)
00049 #define MALLOC64
00050 #else
00051 #error "please fix me"
00052 #endif
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 struct mheader {
00071
00072 #if defined(MALLOC32)
00073 #define MBLOCKSIZE 8
00074 #define MBLOCKSHIFT 3
00075 #define MMAGIC 2
00076
00077
00078
00079
00080 unsigned mh_prevblock:29;
00081 unsigned mh_pad:1;
00082 unsigned mh_magic1:2;
00083
00084 unsigned mh_nextblock:29;
00085 unsigned mh_inuse:1;
00086 unsigned mh_magic2:2;
00087
00088 #elif defined(MALLOC64)
00089 #define MBLOCKSIZE 16
00090 #define MBLOCKSHIFT 4
00091 #define MMAGIC 6
00092
00093
00094
00095
00096 unsigned mh_prevblock:62;
00097 unsigned mh_pad:1;
00098 unsigned mh_magic1:3;
00099
00100 unsigned mh_nextblock:62;
00101 unsigned mh_inuse:1;
00102 unsigned mh_magic2:3;
00103
00104 #else
00105 #error "please fix me"
00106 #endif
00107 };
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 #define M_NEXTOFF(mh) ((size_t)(((size_t)((mh)->mh_nextblock))<<MBLOCKSHIFT))
00125 #define M_PREVOFF(mh) ((size_t)(((size_t)((mh)->mh_prevblock))<<MBLOCKSHIFT))
00126 #define M_NEXT(mh) ((struct mheader *)(((char*)(mh))+M_NEXTOFF(mh)))
00127 #define M_PREV(mh) ((struct mheader *)(((char*)(mh))-M_PREVOFF(mh)))
00128
00129 #define M_DATA(mh) ((void *)((mh)+1))
00130 #define M_SIZE(mh) (M_NEXTOFF(mh)-MBLOCKSIZE)
00131
00132 #define M_OK(mh) ((mh)->mh_magic1==MMAGIC && (mh)->mh_magic2==MMAGIC)
00133
00134 #define M_MKFIELD(off) ((off)>>MBLOCKSHIFT)
00135
00136
00137
00138
00139
00140
00141 static uintptr_t __heapbase, __heaptop;
00142
00143
00144
00145
00146 static
00147 void
00148 __malloc_init(void)
00149 {
00150 void *x;
00151
00152
00153
00154
00155 if (sizeof(struct mheader) != MBLOCKSIZE) {
00156 errx(1, "malloc: Internal error - MBLOCKSIZE wrong");
00157 }
00158 if ((MBLOCKSIZE & (MBLOCKSIZE-1))!=0) {
00159 errx(1, "malloc: Internal error - MBLOCKSIZE not power of 2");
00160 }
00161 if (1<<MBLOCKSHIFT != MBLOCKSIZE) {
00162 errx(1, "malloc: Internal error - MBLOCKSHIFT wrong");
00163 }
00164
00165
00166 if (__heapbase!=0 || __heaptop!=0) {
00167 errx(1, "malloc: Internal error - bad init call");
00168 }
00169
00170
00171 x = sbrk(0);
00172 if (x==(void *)-1) {
00173 err(1, "malloc: initial sbrk failed");
00174 }
00175 if (x==(void *) 0) {
00176 errx(1, "malloc: Internal error - heap began at 0");
00177 }
00178 __heapbase = __heaptop = (uintptr_t)x;
00179
00180
00181
00182
00183
00184
00185
00186
00187 if (__heapbase % MBLOCKSIZE != 0) {
00188 size_t adjust = MBLOCKSIZE - (__heapbase % MBLOCKSIZE);
00189 x = sbrk(adjust);
00190 if (x==(void *)-1) {
00191 err(1, "malloc: sbrk failed aligning heap base");
00192 }
00193 if ((uintptr_t)x != __heapbase) {
00194 err(1, "malloc: heap base moved during init");
00195 }
00196 #ifdef MALLOCDEBUG
00197 warnx("malloc: adjusted heap base upwards by %lu bytes",
00198 (unsigned long) adjust);
00199 #endif
00200 __heapbase += adjust;
00201 __heaptop = __heapbase;
00202 }
00203 }
00204
00205
00206
00207 #ifdef MALLOCDEBUG
00208
00209
00210
00211
00212 static
00213 void
00214 __malloc_dump(void)
00215 {
00216 struct mheader *mh;
00217 uintptr_t i;
00218 size_t rightprevblock;
00219
00220 warnx("heap: ************************************************");
00221
00222 rightprevblock = 0;
00223 for (i=__heapbase; i<__heaptop; i += M_NEXTOFF(mh)) {
00224 mh = (struct mheader *) i;
00225 if (!M_OK(mh)) {
00226 errx(1, "malloc: Heap corrupt; header at 0x%lx"
00227 " has bad magic bits",
00228 (unsigned long) i);
00229 }
00230 if (mh->mh_prevblock != rightprevblock) {
00231 errx(1, "malloc: Heap corrupt; header at 0x%lx"
00232 " has bad previous-block size %lu "
00233 "(should be %lu)",
00234 (unsigned long) i,
00235 (unsigned long) mh->mh_prevblock << MBLOCKSHIFT,
00236 (unsigned long) rightprevblock << MBLOCKSHIFT);
00237 }
00238 rightprevblock = mh->mh_nextblock;
00239
00240 warnx("heap: 0x%lx 0x%-6lx (next: 0x%lx) %s",
00241 (unsigned long) i + MBLOCKSIZE,
00242 (unsigned long) M_SIZE(mh),
00243 (unsigned long) (i+M_NEXTOFF(mh)),
00244 mh->mh_inuse ? "INUSE" : "FREE");
00245 }
00246 if (i!=__heaptop) {
00247 errx(1, "malloc: Heap corrupt; ran off end");
00248 }
00249
00250 warnx("heap: ************************************************");
00251 }
00252
00253 #endif
00254
00255
00256
00257
00258
00259
00260
00261 static
00262 void *
00263 __malloc_sbrk(size_t size)
00264 {
00265 void *x;
00266
00267 x = sbrk(size);
00268 if (x == (void *)-1) {
00269 return NULL;
00270 }
00271
00272 if ((uintptr_t)x != __heaptop) {
00273 errx(1, "malloc: Internal error - "
00274 "heap top moved itself from 0x%lx to 0x%lx",
00275 (unsigned long) __heaptop,
00276 (unsigned long) (uintptr_t) x);
00277 }
00278 __heaptop += size;
00279 return x;
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 static
00291 void
00292 __malloc_split(struct mheader *mh, size_t size)
00293 {
00294 struct mheader *mhnext, *mhnew;
00295 size_t oldsize;
00296
00297 if (size % MBLOCKSIZE != 0) {
00298 errx(1, "malloc: Internal error (size %lu passed to split)",
00299 (unsigned long) size);
00300 }
00301
00302 if (M_SIZE(mh) - size < 2*MBLOCKSIZE) {
00303
00304 return;
00305 }
00306
00307 mhnext = M_NEXT(mh);
00308
00309 oldsize = M_SIZE(mh);
00310 mh->mh_nextblock = M_MKFIELD(size + MBLOCKSIZE);
00311
00312 mhnew = M_NEXT(mh);
00313 if (mhnew==mhnext) {
00314 errx(1, "malloc: Internal error (split screwed up?)");
00315 }
00316
00317 mhnew->mh_prevblock = M_MKFIELD(size + MBLOCKSIZE);
00318 mhnew->mh_pad = 0;
00319 mhnew->mh_magic1 = MMAGIC;
00320 mhnew->mh_nextblock = M_MKFIELD(oldsize - size);
00321 mhnew->mh_inuse = 0;
00322 mhnew->mh_magic2 = MMAGIC;
00323
00324 if (mhnext != (struct mheader *) __heaptop) {
00325 mhnext->mh_prevblock = mhnew->mh_nextblock;
00326 }
00327 }
00328
00329
00330
00331
00332 void *
00333 malloc(size_t size)
00334 {
00335 struct mheader *mh;
00336 uintptr_t i;
00337 size_t rightprevblock;
00338
00339 if (__heapbase==0) {
00340 __malloc_init();
00341 }
00342 if (__heapbase==0 || __heaptop==0 || __heapbase > __heaptop) {
00343 warnx("malloc: Internal error - local data corrupt");
00344 errx(1, "malloc: heapbase 0x%lx; heaptop 0x%lx",
00345 (unsigned long) __heapbase, (unsigned long) __heaptop);
00346 }
00347
00348 #ifdef MALLOCDEBUG
00349 warnx("malloc: about to allocate %lu (0x%lx) bytes",
00350 (unsigned long) size, (unsigned long) size);
00351 __malloc_dump();
00352 #endif
00353
00354
00355 size = ((size + MBLOCKSIZE - 1) & ~(size_t)(MBLOCKSIZE-1));
00356
00357
00358
00359
00360
00361 rightprevblock = 0;
00362 for (i=__heapbase; i<__heaptop; i += M_NEXTOFF(mh)) {
00363 mh = (struct mheader *) i;
00364 if (!M_OK(mh)) {
00365 errx(1, "malloc: Heap corrupt; header at 0x%lx"
00366 " has bad magic bits",
00367 (unsigned long) i);
00368 }
00369 if (mh->mh_prevblock != rightprevblock) {
00370 errx(1, "malloc: Heap corrupt; header at 0x%lx"
00371 " has bad previous-block size %lu "
00372 "(should be %lu)",
00373 (unsigned long) i,
00374 (unsigned long) mh->mh_prevblock << MBLOCKSHIFT,
00375 (unsigned long) rightprevblock << MBLOCKSHIFT);
00376 }
00377 rightprevblock = mh->mh_nextblock;
00378
00379
00380 if (mh->mh_inuse) {
00381 continue;
00382 }
00383
00384
00385 if (M_SIZE(mh) < size) {
00386 continue;
00387 }
00388
00389
00390 __malloc_split(mh, size);
00391
00392
00393
00394
00395 mh->mh_inuse = 1;
00396
00397 #ifdef MALLOCDEBUG
00398 warnx("malloc: allocating at %p", M_DATA(mh));
00399 __malloc_dump();
00400 #endif
00401 return M_DATA(mh);
00402 }
00403 if (i!=__heaptop) {
00404 errx(1, "malloc: Heap corrupt; ran off end");
00405 }
00406
00407
00408
00409
00410
00411 mh = __malloc_sbrk(size + MBLOCKSIZE);
00412 if (mh == NULL) {
00413 return NULL;
00414 }
00415
00416 mh->mh_prevblock = rightprevblock;
00417 mh->mh_magic1 = MMAGIC;
00418 mh->mh_magic2 = MMAGIC;
00419 mh->mh_pad = 0;
00420 mh->mh_inuse = 1;
00421 mh->mh_nextblock = M_MKFIELD(size + MBLOCKSIZE);
00422
00423 #ifdef MALLOCDEBUG
00424 warnx("malloc: allocating at %p", M_DATA(mh));
00425 __malloc_dump();
00426 #endif
00427 return M_DATA(mh);
00428 }
00429
00430
00431
00432
00433
00434
00435
00436 static
00437 void
00438 __malloc_deadbeef(void *ptr, size_t size)
00439 {
00440 uint32_t *x = ptr;
00441 size_t i, n = size/sizeof(uint32_t);
00442 for (i=0; i<n; i++) {
00443 x[i] = 0xdeadbeef;
00444 }
00445 }
00446
00447
00448
00449
00450 static
00451 void
00452 __malloc_trymerge(struct mheader *mh, struct mheader *mhnext)
00453 {
00454 struct mheader *mhnextnext;
00455
00456 if (mh->mh_nextblock != mhnext->mh_prevblock) {
00457 errx(1, "free: Heap corrupt (%p and %p inconsistent)",
00458 mh, mhnext);
00459 }
00460 if (mh->mh_inuse || mhnext->mh_inuse) {
00461
00462 return;
00463 }
00464
00465 mhnextnext = M_NEXT(mhnext);
00466
00467 mh->mh_nextblock = M_MKFIELD(MBLOCKSIZE + M_SIZE(mh) +
00468 MBLOCKSIZE + M_SIZE(mhnext));
00469
00470 if (mhnextnext != (struct mheader *)__heaptop) {
00471 mhnextnext->mh_prevblock = mh->mh_nextblock;
00472 }
00473
00474
00475 __malloc_deadbeef(mhnext, sizeof(struct mheader));
00476 }
00477
00478
00479
00480
00481 void
00482 free(void *x)
00483 {
00484 struct mheader *mh, *mhnext, *mhprev;
00485
00486 if (x==NULL) {
00487
00488 return;
00489 }
00490
00491
00492 if (__heapbase==0 || __heaptop==0 || __heapbase > __heaptop) {
00493 warnx("free: Internal error - local data corrupt");
00494 errx(1, "free: heapbase 0x%lx; heaptop 0x%lx",
00495 (unsigned long) __heapbase, (unsigned long) __heaptop);
00496 }
00497
00498
00499 if ((uintptr_t)x < __heapbase || (uintptr_t)x >= __heaptop) {
00500 errx(1, "free: Invalid pointer %p freed (out of range)", x);
00501 }
00502
00503 #ifdef MALLOCDEBUG
00504 warnx("free: about to free %p", x);
00505 __malloc_dump();
00506 #endif
00507
00508 mh = ((struct mheader *)x)-1;
00509 if (!M_OK(mh)) {
00510 errx(1, "free: Invalid pointer %p freed (corrupt header)", x);
00511 }
00512
00513 if (!mh->mh_inuse) {
00514 errx(1, "free: Invalid pointer %p freed (already free)", x);
00515 }
00516
00517
00518 mh->mh_inuse = 0;
00519
00520
00521 __malloc_deadbeef(M_DATA(mh), M_SIZE(mh));
00522
00523
00524 mhnext = M_NEXT(mh);
00525 if (mhnext != (struct mheader *)__heaptop) {
00526 __malloc_trymerge(mh, mhnext);
00527 }
00528
00529
00530 if (mh != (struct mheader *)__heapbase) {
00531 mhprev = M_PREV(mh);
00532 __malloc_trymerge(mhprev, mh);
00533 }
00534
00535 #ifdef MALLOCDEBUG
00536 warnx("free: freed %p", x);
00537 __malloc_dump();
00538 #endif
00539 }