home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / mallc120 / part02 < prev    next >
Encoding:
Text File  |  1993-04-05  |  68.4 KB  |  2,331 lines

  1. Newsgroups: comp.sources.unix
  2. From: gray@antaire.com (Gray Watson)
  3. Subject: v26i099: malloc - debugging version of malloc, V1.2.0, Part02/05
  4. Sender: unix-sources-moderator@vix.com
  5. Approved: paul@vix.com
  6.  
  7. Submitted-By: gray@antaire.com (Gray Watson)
  8. Posting-Number: Volume 26, Issue 99
  9. Archive-Name: malloc-1.2.0/part02
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 2 (of 5)."
  18. # Contents:  chunk.c
  19. # Wrapped by gray@toaster.antaire.com on Tue Apr  6 01:24:06 1993
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'chunk.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'chunk.c'\"
  23. else
  24. echo shar: Extracting \"'chunk.c'\" \(66104 characters\)
  25. sed "s/^X//" >'chunk.c' <<'END_OF_FILE'
  26. X/*
  27. X * memory chunk low-level allocation routines
  28. X *
  29. X * Copyright 1992 by Gray Watson and the Antaire Corporation
  30. X *
  31. X * This file is part of the malloc-debug package.
  32. X *
  33. X * This library is free software; you can redistribute it and/or
  34. X * modify it under the terms of the GNU Library General Public
  35. X * License as published by the Free Software Foundation; either
  36. X * version 2 of the License, or (at your option) any later version.
  37. X *
  38. X * This library is distributed in the hope that it will be useful,
  39. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  40. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  41. X * Library General Public License for more details.
  42. X *
  43. X * You should have received a copy of the GNU Library General Public
  44. X * License along with this library (see COPYING-LIB); if not, write to the
  45. X * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  46. X *
  47. X * The author of the program may be contacted at gray.watson@antaire.com
  48. X */
  49. X
  50. X/*
  51. X * This file contains algorithm level routine for the heap.  They handle the
  52. X * manipulation and administration of chunks of memory.
  53. X */
  54. X
  55. X#define MALLOC_DEBUG_DISABLE
  56. X
  57. X#include "malloc.h"
  58. X#include "malloc_loc.h"
  59. X
  60. X#include "chunk.h"
  61. X#include "chunk_loc.h"
  62. X#include "compat.h"
  63. X#include "conf.h"
  64. X#include "dbg_values.h"
  65. X#include "error.h"
  66. X#include "error_val.h"
  67. X#include "heap.h"
  68. X#include "version.h"
  69. X
  70. X#if INCLUDE_RCS_IDS
  71. XLOCAL    char    *rcs_id =
  72. X  "$Id: chunk.c,v 1.29 1993/04/05 22:29:52 gray Exp $";
  73. X#endif
  74. X
  75. X/* checking information */
  76. X#define MIN_FILE_LENGTH            3        /* min "[a-zA-Z].c" length */
  77. X#define MAX_FILE_LENGTH           40        /* max __FILE__ length */
  78. X#define MAX_LINE_NUMBER        10000        /* max __LINE__ value */
  79. X
  80. X#define FREE_COLUMN            5        /* for dump_free formatting */
  81. X#define FREE_CHAR        '\305'        /* to blank free space with */
  82. X
  83. X/* free lists of bblocks and dblocks */
  84. XLOCAL    bblock_t    *free_bblock[LARGEST_BLOCK + 1];
  85. XLOCAL    dblock_t    *free_dblock[BASIC_BLOCK];
  86. X
  87. X/* administrative structures */
  88. XLOCAL    bblock_adm_t    *bblock_adm_head = NULL; /* pointer to 1st bb_admin */
  89. XLOCAL    bblock_adm_t    *bblock_adm_tail = NULL; /* pointer to last bb_admin */
  90. X
  91. X/* user information shifts for display purposes */
  92. XLOCAL    int        pnt_below_adm    = 0;    /* add to pnt for display */
  93. XLOCAL    int        pnt_total_adm    = 0;    /* total adm per pointer */
  94. X
  95. X/* memory stats */
  96. XLOCAL    long        alloc_current    = 0;    /* current memory usage */
  97. XLOCAL    long        alloc_cur_given    = 0;    /* current mem given */
  98. XLOCAL    long        alloc_maximum    = 0;    /* maximum memory usage  */
  99. XLOCAL    long        alloc_max_given    = 0;    /* maximum mem given  */
  100. XLOCAL    long        alloc_total    = 0;    /* total allocation */
  101. XLOCAL    long        alloc_one_max    = 0;    /* maximum at once */
  102. XLOCAL    int        free_space_count = 0;    /* count the free bytes */
  103. X
  104. X/* pointer stats */
  105. XLOCAL    long        alloc_cur_pnts    = 0;    /* current pointers */
  106. XLOCAL    long        alloc_max_pnts    = 0;    /* maximum pointers */
  107. XLOCAL    long        alloc_tot_pnts    = 0;    /* current pointers */
  108. X
  109. X/* admin counts */
  110. XLOCAL    int        bblock_adm_count = 0;    /* count of bblock_admin */
  111. XLOCAL    int        dblock_adm_count = 0;    /* count of dblock_admin */
  112. XLOCAL    int        bblock_count     = 0;    /* count of basic-blocks */
  113. XLOCAL    int        dblock_count     = 0;    /* count of divided-blocks */
  114. X
  115. X/* alloc counts */
  116. XEXPORT    int        _calloc_count    = 0;    /* # callocs, done in alloc */
  117. XLOCAL    int        free_count    = 0;    /* count the frees */
  118. XLOCAL    int        malloc_count    = 0;    /* count the mallocs */
  119. XLOCAL    int        realloc_count    = 0;    /* count the reallocs */
  120. X
  121. X/************************* fence-post error functions ************************/
  122. X
  123. X/*
  124. X * check PNT of SIZE for fence-post magic numbers, returns ERROR or NOERROR
  125. X */
  126. XLOCAL    int    fence_read(const char * file, const unsigned int line,
  127. X               char * pnt, unsigned int size)
  128. X{
  129. X  long        top, *longp;
  130. X  
  131. X  /*
  132. X   * write magic numbers into block in bottom of allocation
  133. X   *
  134. X   * WARNING: assuming a word-boundary here
  135. X   */
  136. X  for (longp = (long *)pnt; longp < (long *)(pnt + FENCE_BOTTOM); longp++)
  137. X    if (*longp != FENCE_MAGIC_BASE) {
  138. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  139. X    _malloc_message("under fence on pointer '%#lx' alloced in '%s:%u'",
  140. X            CHUNK_TO_USER(pnt), file, line);
  141. X      malloc_errno = MALLOC_UNDER_FENCE;
  142. X      _malloc_perror("fence_read");
  143. X      return ERROR;
  144. X    }
  145. X  
  146. X  /*
  147. X   * write magic numbers into block in top of allocation
  148. X   *
  149. X   * WARNING: not guaranteed a word-boundary here
  150. X   */
  151. X  for (longp = (long *)(pnt + size - FENCE_TOP); longp < (long *)(pnt + size);
  152. X       longp++) {
  153. X    bcopy(longp, &top, sizeof(long));
  154. X    if (top != FENCE_MAGIC_TOP) {
  155. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  156. X    _malloc_message("over fence on pointer '%#lx' alloced in '%s:%u'",
  157. X            CHUNK_TO_USER(pnt), file, line);
  158. X      malloc_errno = MALLOC_OVER_FENCE;
  159. X      _malloc_perror("fence_read");
  160. X      return ERROR;
  161. X    }
  162. X  }
  163. X  
  164. X  return NOERROR;
  165. X}
  166. X
  167. X/*
  168. X * load PNT of SIZE bytes with fence-post magic numbers
  169. X */
  170. XLOCAL    void    fence_write(char * pnt, unsigned int size)
  171. X{
  172. X  long        top = FENCE_MAGIC_TOP;
  173. X  long        *longp;
  174. X  
  175. X  /* write magic numbers into block in bottom of allocation */
  176. X  for (longp = (long *)pnt; longp < (long *)(pnt + FENCE_BOTTOM); longp++)
  177. X    *longp = FENCE_MAGIC_BASE;
  178. X  
  179. X  /* write magic numbers into block in top of allocation */
  180. X  /* WARNING: not guaranteed a word-boundary here */
  181. X  for (longp = (long *)(pnt + size - FENCE_TOP); longp < (long *)(pnt + size);
  182. X       longp++)
  183. X    bcopy(&top, longp, sizeof(long));
  184. X}
  185. X
  186. X/************************** administration functions *************************/
  187. X
  188. X/*
  189. X * startup the low level malloc routines
  190. X */
  191. XEXPORT    int    _chunk_startup(void)
  192. X{
  193. X  int    binc;
  194. X  
  195. X  /* verify some conditions */
  196. X  if (BB_PER_ADMIN <= 2
  197. X      || sizeof(bblock_adm_t) > BLOCK_SIZE
  198. X      || DB_PER_ADMIN < (1 << (BASIC_BLOCK - SMALLEST_BLOCK))
  199. X      || sizeof(dblock_adm_t) > BLOCK_SIZE
  200. X      || SMALLEST_BLOCK < ALLOCATION_ALIGNMENT_IN_BITS) {
  201. X    malloc_errno = MALLOC_BAD_SETUP;
  202. X    _malloc_perror("_chunk_startup");
  203. X    return ERROR;
  204. X  }
  205. X  
  206. X  /* align the base pointer */
  207. X  if (_heap_align_base(BLOCK_SIZE) == MALLOC_ERROR) {
  208. X    malloc_errno = MALLOC_BAD_SETUP;
  209. X    _malloc_perror("_chunk_startup");
  210. X    return ERROR;
  211. X  }
  212. X  
  213. X  /* initialize free bins */
  214. X  for (binc = 0; binc <= LARGEST_BLOCK; binc++)
  215. X    free_bblock[binc] = NULL;
  216. X  for (binc = 0; binc < BASIC_BLOCK; binc++)
  217. X    free_dblock[binc] = NULL;
  218. X  
  219. X  /* assign value to add to pointers when displaying */
  220. X  if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
  221. X    pnt_below_adm = FENCE_BOTTOM;
  222. X    pnt_total_adm = FENCE_OVERHEAD;
  223. X  }
  224. X  else {
  225. X    pnt_below_adm = 0;
  226. X    pnt_total_adm = 0;
  227. X  }
  228. X  
  229. X  return NOERROR;
  230. X}
  231. X
  232. X/*
  233. X * return the number of bits in number SIZE
  234. X */
  235. XLOCAL    int    num_bits(unsigned int size)
  236. X{
  237. X  unsigned int    tmp = size;
  238. X  int        bitc;
  239. X  
  240. X#if ALLOW_ALLOC_ZERO_SIZE == 0
  241. X  if (size == 0) {
  242. X    malloc_errno = MALLOC_BAD_SIZE;
  243. X    _malloc_perror("num_bits");
  244. X    return ERROR;
  245. X  }
  246. X#endif
  247. X  
  248. X  /* shift right until 0, 2 ^ 0 == 1 */
  249. X  for (bitc = -1; tmp > 0; bitc++)
  250. X    tmp >>= 1;
  251. X  
  252. X  /* are we not a base 2 number? */
  253. X  if (size > (1 << bitc))
  254. X    bitc++;
  255. X  
  256. X  return bitc;
  257. X}
  258. X
  259. X/*
  260. X * "allocate" another bblock administrative block
  261. X * NOTE: some logistic problems with getting from free list
  262. X */
  263. XLOCAL    bblock_adm_t    *get_bblock_admin(void)
  264. X{
  265. X  bblock_adm_t    *new;
  266. X  bblock_t    *bblockp;
  267. X  
  268. X  bblock_adm_count++;
  269. X  bblock_count++;
  270. X  
  271. X  /* get some more space for a bblock_admin structure */
  272. X  new = (bblock_adm_t *)_heap_alloc(BLOCK_SIZE);
  273. X  if (new == (bblock_adm_t *)HEAP_ALLOC_ERROR)
  274. X    return NULL;
  275. X  
  276. X  /* do we need to print admin info? */
  277. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  278. X    _malloc_message("new bblock admin alloced for another %d admin slots",
  279. X            BB_PER_ADMIN);
  280. X  
  281. X  /*
  282. X   * initialize the new bblock_admin block
  283. X   */
  284. X  new->ba_magic1 = CHUNK_MAGIC_BASE;
  285. X  if (bblock_adm_tail == NULL)
  286. X    new->ba_count = 0;
  287. X  else
  288. X    new->ba_count = bblock_adm_tail->ba_count + BB_PER_ADMIN;
  289. X  
  290. X  /* initialize the bblocks in the bblock_admin */
  291. X  for (bblockp = new->ba_block; bblockp < new->ba_block + BB_PER_ADMIN;
  292. X       bblockp++)
  293. X    bblockp->bb_flags = 0;
  294. X  
  295. X  new->ba_next = NULL;
  296. X  new->ba_magic2 = CHUNK_MAGIC_TOP;
  297. X  
  298. X  /*
  299. X   * continue bblock_admin linked-list
  300. X   */
  301. X  if (bblock_adm_tail == NULL)
  302. X    bblock_adm_head = new;
  303. X  else
  304. X    bblock_adm_tail->ba_next = new;
  305. X  bblock_adm_tail = new;
  306. X  
  307. X  return new;
  308. X}
  309. X
  310. X/*
  311. X * get MANY of bblocks, return a pointer to the first one
  312. X */
  313. XLOCAL    bblock_t    *get_bblocks(int bitc)
  314. X{
  315. X  static int    free_slots = 0;        /* free slots in last bb_admin */
  316. X  int        newc, mark;
  317. X  bblock_adm_t    *bblock_admp;
  318. X  bblock_t    *bblockp;
  319. X  
  320. X  if (bitc < BASIC_BLOCK) {
  321. X    malloc_errno = MALLOC_BAD_SIZE;
  322. X    _malloc_perror("get_bblocks");
  323. X    return NULL;
  324. X  }
  325. X  
  326. X  /* do we need to print admin info? */
  327. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  328. X    _malloc_message("need bblocks for %d bytes or %d bits", 1 << bitc, bitc);
  329. X  
  330. X  /* is there anything on the free list? */
  331. X  bblockp = free_bblock[bitc];
  332. X  if (bblockp != NULL) {
  333. X    free_bblock[bitc] = bblockp->bb_next;
  334. X    free_space_count -= 1 << bitc;
  335. X    return bblockp;
  336. X  }
  337. X  
  338. X  bblock_count += 1 << (bitc - BASIC_BLOCK);
  339. X  
  340. X  /* point at first free bblock entry (may be out of range) */
  341. X  bblock_admp = bblock_adm_tail;
  342. X  mark = BB_PER_ADMIN - free_slots;
  343. X  
  344. X  /* loop until we have enough slots */
  345. X  for (newc = 0; free_slots < 1 << (bitc - BASIC_BLOCK); newc++) {
  346. X    if (get_bblock_admin() == NULL)
  347. X      return NULL;
  348. X    
  349. X    /* do we need to move to the next bblock admin? */
  350. X    if (mark == BB_PER_ADMIN) {
  351. X      if (bblock_admp == NULL)
  352. X    bblock_admp = bblock_adm_tail;
  353. X      else
  354. X    bblock_admp = bblock_admp->ba_next;
  355. X      mark = 0;
  356. X    }
  357. X    
  358. X    /* write a bblock entry for the bblock admin */
  359. X    bblockp = &bblock_admp->ba_block[mark];
  360. X    
  361. X    bblockp->bb_flags    = BBLOCK_ADMIN;
  362. X    bblockp->bb_count    = bblock_adm_tail->ba_count;
  363. X    bblockp->bb_adminp    = bblock_adm_tail;
  364. X    
  365. X    /* add one to mark to pass by bblock admin header */
  366. X    mark++;
  367. X    
  368. X    /* adjust free_slot count for addition of new bblock admin */
  369. X    free_slots += BB_PER_ADMIN - 1;
  370. X  }
  371. X  
  372. X  /* do we need to move to the next bblock admin? */
  373. X  if (mark == BB_PER_ADMIN) {
  374. X    bblock_admp = bblock_admp->ba_next;
  375. X    mark = 0;
  376. X  }
  377. X  
  378. X  /* adjust free_slot count for the allocation */
  379. X  free_slots -= 1 << (bitc - BASIC_BLOCK);
  380. X  
  381. X  return &bblock_admp->ba_block[mark];
  382. X}
  383. X
  384. X/*
  385. X * get MANY of contiguous dblock administrative slots
  386. X */
  387. XLOCAL    dblock_t    *get_dblock_admin(int many)
  388. X{
  389. X  static int        free_slots = 0;
  390. X  static dblock_adm_t    *dblock_admp;
  391. X  dblock_t        *dblockp;
  392. X  bblock_t        *bblockp;
  393. X  
  394. X  /* do we need to print admin info? */
  395. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  396. X    _malloc_message("need %d dblock slots", many);
  397. X  
  398. X  /* do we have enough right now */
  399. X  if (free_slots >= many) {
  400. X    free_slots -= many;
  401. X    return &dblock_admp->da_block[DB_PER_ADMIN - (free_slots + many)];
  402. X  }
  403. X  
  404. X  /*
  405. X   * allocate a new bblock of dblock admin slots, should use free list
  406. X   */
  407. X  bblockp = get_bblocks(BASIC_BLOCK);
  408. X  if (bblockp == NULL)
  409. X    return NULL;
  410. X  
  411. X  dblock_adm_count++;
  412. X  
  413. X  /* allocate the block if needed */
  414. X  if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED))
  415. X    dblock_admp = (dblock_adm_t *)bblockp->bb_mem;
  416. X  else
  417. X    dblock_admp = (dblock_adm_t *)_heap_alloc(BLOCK_SIZE);
  418. X  if (dblock_admp == (dblock_adm_t *)HEAP_ALLOC_ERROR)
  419. X    return NULL;
  420. X  
  421. X  bblockp->bb_flags = BBLOCK_DBLOCK_ADMIN;
  422. X  bblockp->bb_slotp = dblock_admp;
  423. X  
  424. X  /* do we need to print admin info? */
  425. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  426. X    _malloc_message("opened another %d dblock slots", DB_PER_ADMIN);
  427. X  
  428. X  dblock_admp->da_magic1 = CHUNK_MAGIC_BASE;
  429. X  
  430. X  /* initialize the db_slots */
  431. X  for (dblockp = dblock_admp->da_block;
  432. X       dblockp < dblock_admp->da_block + DB_PER_ADMIN; dblockp++) {
  433. X    dblockp->db_bblock = NULL;
  434. X    dblockp->db_next = NULL;
  435. X  }
  436. X  
  437. X  dblock_admp->da_magic2 = CHUNK_MAGIC_TOP;
  438. X  
  439. X  free_slots = DB_PER_ADMIN - many;
  440. X  
  441. X  return dblock_admp->da_block;
  442. X}
  443. X
  444. X/*
  445. X * get a dblock of 1<<BITC sized chunks, also asked for the slot memory
  446. X */
  447. XLOCAL    char    *get_dblock(int bitc, dblock_t ** admp)
  448. X{
  449. X  bblock_t    *bblockp;
  450. X  dblock_t    *dblockp;
  451. X  char        *mem;
  452. X  
  453. X  /* is there anything on the dblock free list? */
  454. X  dblockp = free_dblock[bitc];
  455. X  if (dblockp != NULL) {
  456. X    free_dblock[bitc] = dblockp->db_next;
  457. X    free_space_count -= 1 << bitc;
  458. X    
  459. X    *admp = dblockp;
  460. X    
  461. X    /* find pointer to memory chunk */
  462. X    mem = dblockp->db_bblock->bb_mem +
  463. X      (dblockp - dblockp->db_bblock->bb_dblock) * (1 << bitc);
  464. X    
  465. X    /* do we need to print admin info? */
  466. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  467. X      _malloc_message("found a %d byte dblock entry", 1 << bitc);
  468. X    
  469. X    return mem;
  470. X  }
  471. X  
  472. X  /* do we need to print admin info? */
  473. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  474. X    _malloc_message("need to create a dblock for %dx %d byte blocks",
  475. X            1 << (BASIC_BLOCK - bitc), 1 << bitc);
  476. X  
  477. X  /* get some dblock admin slots */
  478. X  dblockp = get_dblock_admin(1 << (BASIC_BLOCK - bitc));
  479. X  if (dblockp == NULL)
  480. X    return NULL;
  481. X  *admp = dblockp;
  482. X  
  483. X  dblock_count++;
  484. X  
  485. X  /* get a bblock from free list */
  486. X  bblockp = get_bblocks(BASIC_BLOCK);
  487. X  if (bblockp == NULL)
  488. X    return NULL;
  489. X  
  490. X  /* allocate the block if needed */
  491. X  if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED))
  492. X    mem = bblockp->bb_mem;
  493. X  else {
  494. X    mem = _heap_alloc(BLOCK_SIZE);
  495. X    if (mem == HEAP_ALLOC_ERROR)
  496. X      return NULL;
  497. X    bblockp->bb_mem = mem;
  498. X  }
  499. X  
  500. X  /* setup bblock information */
  501. X  bblockp->bb_flags    = BBLOCK_DBLOCK;
  502. X  bblockp->bb_bitc    = bitc;
  503. X  bblockp->bb_dblock    = dblockp;
  504. X  
  505. X  /* add the rest to the free list (has to be at least 1 other dblock) */
  506. X  free_dblock[bitc] = ++dblockp;
  507. X  free_space_count += 1 << bitc;
  508. X  
  509. X  for (; dblockp < *admp + (1 << (BASIC_BLOCK - bitc)) - 1; dblockp++) {
  510. X    dblockp->db_next    = dblockp + 1;
  511. X    dblockp->db_bblock    = bblockp;
  512. X    free_space_count    += 1 << bitc;
  513. X  }
  514. X  
  515. X  if (BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
  516. X    (void)memset(mem + (1 << bitc), FREE_CHAR, BLOCK_SIZE - (1 << bitc));
  517. X  
  518. X  /* last one points to NULL */
  519. X  dblockp->db_next    = NULL;
  520. X  dblockp->db_bblock    = bblockp;
  521. X  
  522. X  return mem;
  523. X}
  524. X
  525. X/*
  526. X * find the bblock entry for PNT, return bblock admin in *BB_ADMIN (if != NULL)
  527. X * and return the block number in BLOCK_NUM (if non NULL)
  528. X */
  529. XLOCAL    bblock_t    *find_bblock(char * pnt, int * block_num,
  530. X                     bblock_adm_t ** bb_admin)
  531. X{
  532. X  int        bblockc;
  533. X  bblock_adm_t    *bblock_admp;
  534. X  
  535. X  if (pnt == NULL) {
  536. X    malloc_errno = MALLOC_POINTER_NULL;
  537. X    return NULL;
  538. X  }
  539. X  
  540. X  /*
  541. X   * check validity of the pointer
  542. X   */
  543. X  if (! IS_IN_HEAP(pnt)) {
  544. X    malloc_errno = MALLOC_POINTER_NOT_IN_HEAP;
  545. X    return NULL;
  546. X  }
  547. X  
  548. X  /* find which block it is in */
  549. X  bblockc = WHICH_BLOCK(pnt);
  550. X  
  551. X  /* do we need to return the block number */
  552. X  if (block_num != NULL)
  553. X    *block_num = bblockc;
  554. X  
  555. X  /* find right bblock admin */
  556. X  for (bblock_admp = bblock_adm_head; bblock_admp != NULL;
  557. X       bblock_admp = bblock_admp->ba_next) {
  558. X    if (bblockc < BB_PER_ADMIN)
  559. X      break;
  560. X    
  561. X    bblockc -= BB_PER_ADMIN;
  562. X  }
  563. X  
  564. X  if (bblock_admp == NULL) {
  565. X    malloc_errno = MALLOC_POINTER_NOT_FOUND;
  566. X    return NULL;
  567. X  }
  568. X  
  569. X  /* should we return bblock admin info? */
  570. X  if (bb_admin != NULL)
  571. X    *bb_admin = bblock_admp;
  572. X  
  573. X  return &bblock_admp->ba_block[bblockc];
  574. X}
  575. X
  576. X/*
  577. X * log the heap structure plus information on the blocks if necessary
  578. X */
  579. XLOCAL    void    log_heap_map(void)
  580. X{
  581. X  bblock_adm_t    *bblock_admp;
  582. X  char        line[BB_PER_ADMIN + 10];
  583. X  int        linec, bblockc, bb_adminc;
  584. X  
  585. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  586. X    _malloc_message("logging heap map information");
  587. X  
  588. X  _malloc_message("heap-base = %#lx, heap-end = %#lx, size = %ld bytes",
  589. X          _heap_base, _heap_last, HEAP_SIZE);
  590. X  
  591. X  for (bb_adminc = 0, bblock_admp = bblock_adm_head; bblock_admp != NULL;
  592. X       bb_adminc++, bblock_admp = bblock_admp->ba_next) {
  593. X    linec = 0;
  594. X    
  595. X    for (bblockc = 0; bblockc < BB_PER_ADMIN; bblockc++) {
  596. X      bblock_t    *bblockp = &bblock_admp->ba_block[bblockc];
  597. X      
  598. X      if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED)) {
  599. X    line[linec++] = '_';
  600. X    continue;
  601. X      }
  602. X      
  603. X      if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
  604. X    line[linec++] = 'S';
  605. X    continue;
  606. X      }
  607. X      
  608. X      if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_USER)) {
  609. X    line[linec++] = 'U';
  610. X    continue;
  611. X      }
  612. X      
  613. X      if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_ADMIN)) {
  614. X    line[linec++] = 'A';
  615. X    continue;
  616. X      }
  617. X      
  618. X      if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
  619. X    line[linec++] = 'd';
  620. X    continue;
  621. X      }
  622. X      
  623. X      if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK_ADMIN)) {
  624. X    line[linec++] = 'a';
  625. X    continue;
  626. X      }
  627. X      
  628. X      if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_FREE)) {
  629. X    line[linec++] = 'F';
  630. X    continue;
  631. X      }
  632. X    }
  633. X    
  634. X    /* dumping a line to the logfile */
  635. X    if (linec > 0) {
  636. X      line[linec] = NULLC;
  637. X      _malloc_message("S%d:%s", bb_adminc, line);
  638. X    }
  639. X  }
  640. X  
  641. X  /* if we are not logging blocks then leave */
  642. X  if (! BIT_IS_SET(_malloc_debug, DEBUG_LOG_BLOCKS))
  643. X    return;
  644. X  
  645. X  for (bb_adminc = 0, bblock_admp = bblock_adm_head; bblock_admp != NULL;
  646. X       bb_adminc++, bblock_admp = bblock_admp->ba_next) {
  647. X    
  648. X    for (bblockc = 0; bblockc < BB_PER_ADMIN; bblockc++) {
  649. X      bblock_t    *bblockp = &bblock_admp->ba_block[bblockc];
  650. X      
  651. X      if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED)) {
  652. X    _malloc_message("%d: not-allocated block",
  653. X            bb_adminc * BB_PER_ADMIN + bblockc);
  654. X    /* quit after the first non-allocated is found */
  655. X    break;
  656. X      }
  657. X      
  658. X      if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
  659. X    _malloc_message("%d: start-of-user block: %d bytes from '%s:%u'",
  660. X            bb_adminc * BB_PER_ADMIN + bblockc,
  661. X            bblockp->bb_size, bblockp->bb_file, bblockp->bb_line);
  662. X    continue;
  663. X      }
  664. X      
  665. X      if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags, BBLOCK_USER)) {
  666. X    _malloc_message("%d: user continuation block",
  667. X            bb_adminc * BB_PER_ADMIN + bblockc);
  668. X    continue;
  669. X      }
  670. X      
  671. X      if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags, BBLOCK_ADMIN)) {
  672. X    _malloc_message("%d: administration block",
  673. X            bb_adminc * BB_PER_ADMIN + bblockc);
  674. X    continue;
  675. X      }
  676. X      
  677. X      if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags, BBLOCK_DBLOCK)) {
  678. X    _malloc_message("%d: dblock block",
  679. X            bb_adminc * BB_PER_ADMIN + bblockc);
  680. X    continue;
  681. X      }
  682. X      
  683. X      if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags,
  684. X             BBLOCK_DBLOCK_ADMIN)) {
  685. X    _malloc_message("%d: dblock-admin block",
  686. X            bb_adminc * BB_PER_ADMIN + bblockc);
  687. X    continue;
  688. X      }
  689. X      
  690. X      if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags, BBLOCK_FREE)) {
  691. X    _malloc_message("%d: free block",
  692. X            bb_adminc * BB_PER_ADMIN + bblockc);
  693. X    continue;
  694. X      }
  695. X    }
  696. X  }
  697. X}
  698. X
  699. X/*
  700. X * run extensive tests on the entire heap depending on TYPE
  701. X */
  702. XEXPORT    int    _chunk_heap_check(void)
  703. X{
  704. X  bblock_adm_t    *this, *last_admp;
  705. X  bblock_t    *bblockp, *bblistp, *last_bblockp;
  706. X  dblock_t    *dblockp;
  707. X  int        undef = 0, start = 0;
  708. X  char        *bytep;
  709. X  char        *mem;
  710. X  int        bitc, dblockc = 0, bblockc = 0, freec = 0;
  711. X  int        bbc = 0, len;
  712. X  int        free_bblockc[LARGEST_BLOCK + 1];
  713. X  int        free_dblockc[BASIC_BLOCK];
  714. X  
  715. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  716. X    _malloc_message("checking heap");
  717. X  
  718. X  /* if the heap is empty then no need to check anything */
  719. X  if (bblock_adm_head == NULL)
  720. X    return NOERROR;
  721. X  
  722. X  if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_LISTS)) {
  723. X    
  724. X    /* count the bblock free lists */
  725. X    for (bitc = 0; bitc < LARGEST_BLOCK + 1; bitc++) {
  726. X      free_bblockc[bitc] = 0;
  727. X      
  728. X      /* parse bblock free list doing minimal pointer checking */
  729. X      for (bblockp = free_bblock[bitc]; bblockp != NULL;
  730. X       bblockp = bblockp->bb_next, free_bblockc[bitc]++)
  731. X    if (bblockp->bb_next != NULL && ! IS_IN_HEAP(bblockp->bb_next)) {
  732. X      malloc_errno = MALLOC_BAD_FREE_LIST;
  733. X      _malloc_perror("_chunk_heap_check");
  734. X      return ERROR;
  735. X    }
  736. X    }
  737. X    
  738. X    if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DBLOCK)) {
  739. X      
  740. X      /* count the dblock free lists */
  741. X      for (bitc = 0; bitc < BASIC_BLOCK; bitc++) {
  742. X    free_dblockc[bitc] = 0;
  743. X    
  744. X    /* parse dblock free list doing minimal pointer checking */
  745. X    for (dblockp = free_dblock[bitc]; dblockp != NULL;
  746. X         dblockp = dblockp->db_next, free_dblockc[bitc]++)
  747. X      if (dblockp->db_next != NULL && ! IS_IN_HEAP(dblockp->db_next)) {
  748. X        malloc_errno = MALLOC_BAD_FREE_LIST;
  749. X        _malloc_perror("_chunk_heap_check");
  750. X        return ERROR;
  751. X      }
  752. X      }
  753. X    }
  754. X  }
  755. X  
  756. X  /* start pointers */
  757. X  this = bblock_adm_head;
  758. X  last_admp = NULL;
  759. X  last_bblockp = NULL;
  760. X  
  761. X  /* test admin pointer validity */
  762. X  if (! IS_IN_HEAP(this)) {
  763. X    malloc_errno = MALLOC_BAD_ADMINP;
  764. X    _malloc_perror("_chunk_heap_check");
  765. X    return ERROR;
  766. X  }
  767. X  
  768. X  /* test structure validity */
  769. X  if (this->ba_magic1 != CHUNK_MAGIC_BASE
  770. X      || this->ba_magic2 != CHUNK_MAGIC_TOP) {
  771. X    malloc_errno = MALLOC_BAD_ADMIN_MAGIC;
  772. X    _malloc_perror("_chunk_heap_check");
  773. X    return ERROR;
  774. X  }
  775. X  
  776. X  /* verify count value */
  777. X  if (this->ba_count != bbc) {
  778. X    malloc_errno = MALLOC_BAD_ADMIN_COUNT;
  779. X    _malloc_perror("_chunk_heap_check");
  780. X    return ERROR;
  781. X  }
  782. X  
  783. X  /* check out the basic blocks */
  784. X  for (bblockp = this->ba_block;; last_bblockp = bblockp++) {
  785. X    
  786. X    /* are we at the end of the bb_admin section */
  787. X    if (bblockp >= this->ba_block + BB_PER_ADMIN) {
  788. X      this = this->ba_next;
  789. X      bbc += BB_PER_ADMIN;
  790. X      
  791. X      /* are we done? */
  792. X      if (this == NULL)
  793. X    break;
  794. X      
  795. X      /* test admin pointer validity */
  796. X      if (! IS_IN_HEAP(this)) {
  797. X    malloc_errno = MALLOC_BAD_ADMINP;
  798. X    _malloc_perror("_chunk_heap_check");
  799. X    return ERROR;
  800. X      }
  801. X      
  802. X      /* test structure validity */
  803. X      if (this->ba_magic1 != CHUNK_MAGIC_BASE
  804. X      || this->ba_magic2 != CHUNK_MAGIC_TOP) {
  805. X    malloc_errno = MALLOC_BAD_ADMIN_MAGIC;
  806. X    _malloc_perror("_chunk_heap_check");
  807. X    return ERROR;
  808. X      }
  809. X      
  810. X      /* verify count value */
  811. X      if (this->ba_count != bbc) {
  812. X    malloc_errno = MALLOC_BAD_ADMIN_COUNT;
  813. X    _malloc_perror("_chunk_heap_check");
  814. X    return ERROR;
  815. X      }
  816. X      
  817. X      bblockp = this->ba_block;
  818. X    }
  819. X    
  820. X    /* check for no-allocation */
  821. X    if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED)) {
  822. X      undef = 1;
  823. X      continue;
  824. X    }
  825. X    
  826. X    /* we better not have seen a not-allocated block before */
  827. X    if (undef == 1) {
  828. X      malloc_errno = MALLOC_BAD_BLOCK_ORDER;
  829. X      _malloc_perror("_chunk_heap_check");
  830. X      return ERROR;
  831. X    }
  832. X    
  833. X    start = 0;
  834. X    
  835. X    /*
  836. X     * check for different types
  837. X     */
  838. X    switch (bblockp->bb_flags) {
  839. X      
  840. X      /* check a starting user-block */
  841. X    case BBLOCK_START_USER:
  842. X      
  843. X      /* check X blocks in a row */
  844. X      if (bblockc != 0) {
  845. X    malloc_errno = MALLOC_USER_NON_CONTIG;
  846. X    _malloc_perror("_chunk_heap_check");
  847. X    return ERROR;
  848. X      }
  849. X      
  850. X      /* mark the size in bits */
  851. X      bitc = num_bits(bblockp->bb_size);
  852. X      if (bitc == ERROR)
  853. X    return ERROR;
  854. X      bblockc = 1 << (bitc - BASIC_BLOCK);
  855. X      start = 1;
  856. X      
  857. X      /* check fence-posts for memory chunk */
  858. X      if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
  859. X    mem = BLOCK_POINTER(this->ba_count + (bblockp - this->ba_block));
  860. X    if (fence_read(bblockp->bb_file, bblockp->bb_line,
  861. X               mem, bblockp->bb_size) != NOERROR)
  862. X      return ERROR;
  863. X      }
  864. X      
  865. X      /* NOTE: NO BREAK HERE ON PURPOSE */
  866. X      
  867. X    case BBLOCK_USER:
  868. X      
  869. X      /* check line number */
  870. X      if (bblockp->bb_line > MAX_LINE_NUMBER) {
  871. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  872. X      _malloc_message("bad line number on pointer alloced in '%s:%u'",
  873. X              bblockp->bb_file, bblockp->bb_line);
  874. X    malloc_errno = MALLOC_BAD_LINE;
  875. X    _malloc_perror("_chunk_heap_check");
  876. X    return ERROR;
  877. X      }
  878. X      
  879. X      /* check out size, BLOCK_SIZE / 2 == 512 when dblock allocs take over */
  880. X      if (bblockp->bb_size <= BLOCK_SIZE / 2
  881. X      || bblockp->bb_size > (1 << LARGEST_BLOCK)) {
  882. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  883. X      _malloc_message("bad size on pointer alloced in '%s:%u'",
  884. X              bblockp->bb_file, bblockp->bb_line);
  885. X    malloc_errno = MALLOC_BAD_SIZE;
  886. X    _malloc_perror("_chunk_heap_check");
  887. X    return ERROR;
  888. X      }
  889. X      
  890. X      /* check file pointer */
  891. X      if (bblockp->bb_file == NULL) {
  892. X    len = strlen(bblockp->bb_file);
  893. X    if (len < MIN_FILE_LENGTH || len > MAX_FILE_LENGTH) {
  894. X      malloc_errno = MALLOC_BAD_FILEP;
  895. X      _malloc_perror("_chunk_heap_check");
  896. X      return ERROR;
  897. X    }
  898. X      }
  899. X      
  900. X      /* check X blocks in a row */
  901. X      if (bblockc == 0) {
  902. X    malloc_errno = MALLOC_USER_NON_CONTIG;
  903. X    _malloc_perror("_chunk_heap_check");
  904. X    return ERROR;
  905. X      }
  906. X      else
  907. X    if (start == 0
  908. X        && (last_bblockp == NULL
  909. X        || (last_bblockp->bb_flags != BBLOCK_START_USER &&
  910. X            last_bblockp->bb_flags != BBLOCK_USER)
  911. X        || bblockp->bb_file != last_bblockp->bb_file
  912. X        || bblockp->bb_line != last_bblockp->bb_line
  913. X        || bblockp->bb_size != last_bblockp->bb_size)) {
  914. X      malloc_errno = MALLOC_USER_NON_CONTIG;
  915. X      _malloc_perror("_chunk_heap_check");
  916. X      return ERROR;
  917. X    }
  918. X      
  919. X      bblockc--;
  920. X      
  921. X      /* NOTE: we should check above the allocated space if alloc_blank on */
  922. X      
  923. X      break;
  924. X      
  925. X    case BBLOCK_ADMIN:
  926. X      
  927. X      /* check the bblock_admin linked-list */
  928. X      if ((last_admp == NULL && bblockp->bb_adminp != bblock_adm_head)
  929. X      || (last_admp != NULL && last_admp->ba_next != bblockp->bb_adminp)) {
  930. X    malloc_errno = MALLOC_BAD_BLOCK_ADMINP;
  931. X    _malloc_perror("_chunk_heap_check");
  932. X    return ERROR;
  933. X      }
  934. X      last_admp = bblockp->bb_adminp;
  935. X      
  936. X      /* check count against admin count */
  937. X      if (bblockp->bb_count != bblockp->bb_adminp->ba_count) {
  938. X    malloc_errno = MALLOC_BAD_BLOCK_ADMINC;
  939. X    _malloc_perror("_chunk_heap_check");
  940. X    return ERROR;
  941. X      }
  942. X      break;
  943. X      
  944. X    case BBLOCK_DBLOCK:
  945. X      
  946. X      /* check out bitc */
  947. X      if (bblockp->bb_bitc >= BASIC_BLOCK) {
  948. X    malloc_errno = MALLOC_BAD_DBLOCK_SIZE;
  949. X    _malloc_perror("_chunk_heap_check");
  950. X    return ERROR;
  951. X      }
  952. X      
  953. X      /* check out dblock pointer */
  954. X      if (! IS_IN_HEAP(bblockp->bb_dblock)) {
  955. X    malloc_errno = MALLOC_BAD_DBLOCK_POINTER;
  956. X    _malloc_perror("_chunk_heap_check");
  957. X    return ERROR;
  958. X      }
  959. X      
  960. X      /* verify mem pointer */
  961. X      if (bblockp->bb_mem !=
  962. X      BLOCK_POINTER(this->ba_count + (bblockp - this->ba_block))) {
  963. X    malloc_errno = MALLOC_BAD_DBLOCK_MEM;
  964. X    _malloc_perror("_chunk_heap_check");
  965. X    return ERROR;
  966. X      }
  967. X      
  968. X      /* check dblock entry very closely if necessary */
  969. X      if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DBLOCK)) {
  970. X    for (dblockc = 0, dblockp = bblockp->bb_dblock;
  971. X         dblockp < bblockp->bb_dblock +
  972. X         (1 << (BASIC_BLOCK - bblockp->bb_bitc));
  973. X         dblockc++, dblockp++) {
  974. X      
  975. X      /* check out dblock entry to see if it is not free */
  976. X      if (dblockp->db_next == NULL || IS_IN_HEAP(dblockp->db_next)) {
  977. X        
  978. X        if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_LISTS)) {
  979. X          dblock_t    *dblistp;
  980. X          
  981. X          /* find the free block in the free list */
  982. X          for (dblistp = free_dblock[bblockp->bb_bitc]; dblistp != NULL;
  983. X           dblistp = dblistp->db_next)
  984. X        if (dblistp == dblockp)
  985. X          break;
  986. X          
  987. X          /* did we find it? */
  988. X          if (dblistp == NULL) {
  989. X        malloc_errno = MALLOC_BAD_FREE_LIST;
  990. X        _malloc_perror("_chunk_heap_check");
  991. X        return ERROR;
  992. X          }
  993. X          
  994. X          free_dblockc[bblockp->bb_bitc]--;
  995. X        }
  996. X        
  997. X        continue;
  998. X      }
  999. X      
  1000. X      /*
  1001. X       * check out size, better be less than BLOCK_SIZE / 2
  1002. X       * I have to check this twice :-(
  1003. X       */
  1004. X      if (dblockp->db_size > BLOCK_SIZE / 2) {
  1005. X        if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1006. X          _malloc_message("bad size on pointer alloced in '%s:%u'",
  1007. X                  dblockp->db_file, dblockp->db_line);
  1008. X        malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
  1009. X        _malloc_perror("_chunk_heap_check");
  1010. X        return ERROR;
  1011. X      }
  1012. X      
  1013. X      if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)
  1014. X          && BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DB_FENCE)) {
  1015. X        mem = bblockp->bb_mem + dblockc * (1 << bblockp->bb_bitc);
  1016. X        if (fence_read(dblockp->db_file, dblockp->db_line,
  1017. X               mem, dblockp->db_size) != NOERROR)
  1018. X          return ERROR;
  1019. X      }
  1020. X    }
  1021. X      }
  1022. X      break;
  1023. X      
  1024. X    case BBLOCK_DBLOCK_ADMIN:
  1025. X      
  1026. X      /* check out dblock pointer */
  1027. X      if (! IS_IN_HEAP(bblockp->bb_slotp)) {
  1028. X    malloc_errno = MALLOC_BAD_DBADMIN_POINTER;
  1029. X    _malloc_perror("_chunk_heap_check");
  1030. X    return ERROR;
  1031. X      }
  1032. X      
  1033. X      /* verify magic numbers */
  1034. X      if (bblockp->bb_slotp->da_magic1 != CHUNK_MAGIC_BASE
  1035. X      || bblockp->bb_slotp->da_magic2 != CHUNK_MAGIC_TOP) {
  1036. X    malloc_errno = MALLOC_BAD_DBADMIN_MAGIC;
  1037. X    _malloc_perror("_chunk_heap_check");
  1038. X    return ERROR;
  1039. X      }
  1040. X      
  1041. X      /* check out each dblock_admin struct? */
  1042. X      if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DBLOCK)) {
  1043. X    for (dblockp = bblockp->bb_slotp->da_block;
  1044. X         dblockp < bblockp->bb_slotp->da_block + DB_PER_ADMIN; dblockp++) {
  1045. X      
  1046. X      /* verify if we have a good bblock pointer and good back pointer */
  1047. X      if (dblockp->db_bblock == NULL && dblockp->db_next == NULL)
  1048. X        continue;
  1049. X      
  1050. X      /* check out dblock pointer and next pointer (if free) */
  1051. X      if (dblockp->db_next == NULL || IS_IN_HEAP(dblockp->db_next)) {
  1052. X        
  1053. X        /* find pointer to memory chunk */
  1054. X        mem = dblockp->db_bblock->bb_mem +
  1055. X          (dblockp - dblockp->db_bblock->bb_dblock) *
  1056. X        (1 << dblockp->db_bblock->bb_bitc);
  1057. X        
  1058. X        /* should we verify that we have a block of FREE_CHAR? */
  1059. X        if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FREE)
  1060. X        && BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
  1061. X          for (bytep = (char *)mem;
  1062. X           bytep < (char *)mem + (1 << dblockp->db_bblock->bb_bitc);
  1063. X           bytep++)
  1064. X        if (*bytep != FREE_CHAR) {
  1065. X          if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1066. X            _malloc_message("bad free memory at '%#lx'", bytep);
  1067. X          malloc_errno = MALLOC_FREE_NON_BLANK;
  1068. X          _malloc_perror("_chunk_heap_check");
  1069. X          return ERROR;
  1070. X        }
  1071. X        
  1072. X        continue;
  1073. X      }
  1074. X      
  1075. X      /* check out size, better be less than BLOCK_SIZE / 2 */
  1076. X      if (dblockp->db_size > BLOCK_SIZE / 2) {
  1077. X        if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1078. X          _malloc_message("bad size on pointer alloced in '%s:%u'",
  1079. X                  dblockp->db_file, dblockp->db_line);
  1080. X        malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
  1081. X        _malloc_perror("_chunk_heap_check");
  1082. X        return ERROR;
  1083. X      }
  1084. X      
  1085. X      /* check line number */
  1086. X      if (dblockp->db_line > MAX_LINE_NUMBER) {
  1087. X        if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1088. X          _malloc_message("bad line number on pointer alloced in '%s:%u'",
  1089. X                  dblockp->db_file, dblockp->db_line);
  1090. X        malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
  1091. X        _malloc_perror("_chunk_heap_check");
  1092. X        return ERROR;
  1093. X      }
  1094. X      
  1095. X      len = strlen(dblockp->db_file);
  1096. X      if (len < MIN_FILE_LENGTH || len > MAX_FILE_LENGTH) {
  1097. X        malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
  1098. X        _malloc_perror("_chunk_heap_check");
  1099. X        return ERROR;
  1100. X      }
  1101. X    }
  1102. X      }
  1103. X      break;
  1104. X      
  1105. X    case BBLOCK_FREE:
  1106. X      
  1107. X      /* NOTE: check out free_lists, depending on debug value? */
  1108. X      
  1109. X      /* check out bitc which is the free-lists size */
  1110. X      if (bblockp->bb_bitc < BASIC_BLOCK
  1111. X      || bblockp->bb_bitc > LARGEST_BLOCK) {
  1112. X    malloc_errno = MALLOC_BAD_SIZE;
  1113. X    _malloc_perror("_chunk_heap_check");
  1114. X    return ERROR;
  1115. X      }
  1116. X      
  1117. X      /* verify linked list pointer */
  1118. X      if (bblockp->bb_next != NULL && ! IS_IN_HEAP(bblockp->bb_next)) {
  1119. X    malloc_errno = MALLOC_BAD_FREE_LIST;
  1120. X    _malloc_perror("_chunk_heap_check");
  1121. X    return ERROR;
  1122. X      }
  1123. X      
  1124. X      /* verify mem pointer */
  1125. X      if (bblockp->bb_mem !=
  1126. X      BLOCK_POINTER(this->ba_count + (bblockp - this->ba_block))) {
  1127. X    malloc_errno = MALLOC_BAD_FREE_MEM;
  1128. X    _malloc_perror("_chunk_heap_check");
  1129. X    return ERROR;
  1130. X      }
  1131. X      
  1132. X      /* check X blocks in a row */
  1133. X      if (freec == 0) {
  1134. X    freec = 1 << (bblockp->bb_bitc - BASIC_BLOCK);
  1135. X    
  1136. X    if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_LISTS)) {
  1137. X      
  1138. X      /* find the free block in the free list */
  1139. X      for (bblistp = free_bblock[bblockp->bb_bitc]; bblistp != NULL;
  1140. X           bblistp = bblistp->bb_next)
  1141. X        if (bblistp == bblockp)
  1142. X          break;
  1143. X      
  1144. X      /* did we find it? */
  1145. X      if (bblistp == NULL) {
  1146. X        malloc_errno = MALLOC_BAD_FREE_LIST;
  1147. X        _malloc_perror("_chunk_heap_check");
  1148. X        return ERROR;
  1149. X      }
  1150. X      
  1151. X      free_bblockc[bblockp->bb_bitc]--;
  1152. X    }
  1153. X      }
  1154. X      else
  1155. X    if (last_bblockp == NULL || last_bblockp->bb_flags != BBLOCK_FREE
  1156. X        || bblockp->bb_bitc != last_bblockp->bb_bitc) {
  1157. X      malloc_errno = MALLOC_FREE_NON_CONTIG;
  1158. X      _malloc_perror("_chunk_heap_check");
  1159. X      return ERROR;
  1160. X    }
  1161. X      freec--;
  1162. X      
  1163. X      /* should we verify that we have a block of FREE_CHAR? */
  1164. X      if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FREE)
  1165. X      && BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
  1166. X    for (bytep = (char *)bblockp->bb_mem;
  1167. X         bytep < (char *)bblockp->bb_mem + BLOCK_SIZE; bytep++)
  1168. X      if (*bytep != FREE_CHAR) {
  1169. X        if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1170. X          _malloc_message("bad free memory at '%#lx'", bytep);
  1171. X        malloc_errno = MALLOC_FREE_NON_BLANK;
  1172. X        _malloc_perror("_chunk_heap_check");
  1173. X        return ERROR;
  1174. X      }
  1175. X      break;
  1176. X      
  1177. X    default:
  1178. X      malloc_errno = MALLOC_BAD_FLAG;
  1179. X      _malloc_perror("_chunk_heap_check");
  1180. X      return ERROR;
  1181. X      break;
  1182. X    }
  1183. X  }
  1184. X  
  1185. X  /*
  1186. X   * any left over contiguous counters?
  1187. X   */
  1188. X  if (bblockc > 0) {
  1189. X    malloc_errno = MALLOC_USER_NON_CONTIG;
  1190. X    _malloc_perror("_chunk_heap_check");
  1191. X    return ERROR;
  1192. X  }
  1193. X  if (freec > 0) {
  1194. X    malloc_errno = MALLOC_FREE_NON_CONTIG;
  1195. X    _malloc_perror("_chunk_heap_check");
  1196. X    return ERROR;
  1197. X  }
  1198. X  
  1199. X  if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_LISTS)) {
  1200. X    
  1201. X    /* any free bblock entries not accounted for? */
  1202. X    for (bitc = 0; bitc < LARGEST_BLOCK + 1; bitc++)
  1203. X      if (free_bblockc[bitc] != 0) {
  1204. X    malloc_errno = MALLOC_BAD_FREE_LIST;
  1205. X    _malloc_perror("_chunk_heap_check");
  1206. X    return ERROR;
  1207. X      }
  1208. X    
  1209. X    if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DBLOCK)) {
  1210. X      /* any free dblock entries not accounted for? */
  1211. X      for (bitc = 0; bitc < BASIC_BLOCK; bitc++)
  1212. X    if (free_dblockc[bitc] != 0) {
  1213. X      malloc_errno = MALLOC_BAD_FREE_LIST;
  1214. X      _malloc_perror("_chunk_heap_check");
  1215. X      return ERROR;
  1216. X    }
  1217. X    }
  1218. X  }
  1219. X  
  1220. X  if (BIT_IS_SET(_malloc_debug, DEBUG_HEAP_CHECK_MAP))
  1221. X    log_heap_map();
  1222. X  
  1223. X  return NOERROR;
  1224. X}
  1225. X
  1226. X/*
  1227. X * run extensive tests on PNT from FUNC. test PNT HOW_MUCH of MIN_SIZE
  1228. X * (or 0 if unknown).  returns [NO]ERROR
  1229. X */
  1230. XEXPORT    int    _chunk_pnt_check(const char * func, char * pnt,
  1231. X                 const int check, int min_size)
  1232. X{
  1233. X  bblock_t    *bblockp;
  1234. X  dblock_t    *dblockp;
  1235. X  int        len, diff;
  1236. X  
  1237. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  1238. X    _malloc_message("checking pointer '%#lx'", pnt);
  1239. X  
  1240. X  /* adjust the pointer down if fence-posting */
  1241. X  if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
  1242. X    pnt -= FENCE_BOTTOM;
  1243. X    if (min_size != 0)
  1244. X      min_size += FENCE_OVERHEAD;
  1245. X  }
  1246. X  
  1247. X  /* find which block it is in */
  1248. X  bblockp = find_bblock(pnt, NULL, NULL);
  1249. X  if (bblockp == NULL) {
  1250. X    if (check == CHUNK_PNT_LOOSE) {
  1251. X      /* the pointer might not be the heap or might be NULL */
  1252. X      malloc_errno = 0;
  1253. X      return NOERROR;
  1254. X    }
  1255. X    else {
  1256. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1257. X    _malloc_message("bad pointer '%#lx'", pnt);
  1258. X      _malloc_perror("find_bblock");
  1259. X      return ERROR;
  1260. X    }
  1261. X  }
  1262. X  
  1263. X  if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
  1264. X    /* on a mini-block boundary? */
  1265. X    diff = (pnt - bblockp->bb_mem) % (1 << bblockp->bb_bitc);
  1266. X    if (diff != 0) {
  1267. X      if (check == CHUNK_PNT_LOOSE) {
  1268. X    if (min_size != 0)
  1269. X      min_size += diff;
  1270. X    pnt -= diff;
  1271. X      }
  1272. X      else {
  1273. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1274. X      _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1275. X    malloc_errno = MALLOC_NOT_ON_BLOCK;
  1276. X    _malloc_perror(func);
  1277. X    return ERROR;
  1278. X      }
  1279. X    }
  1280. X    
  1281. X    /* find correct dblockp */
  1282. X    dblockp = bblockp->bb_dblock + (pnt - bblockp->bb_mem) /
  1283. X      (1 << bblockp->bb_bitc);
  1284. X    
  1285. X    if (dblockp->db_bblock == bblockp) {
  1286. X      /* NOTE: we should run through free list here */
  1287. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1288. X    _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1289. X      malloc_errno = MALLOC_ALREADY_FREE;
  1290. X      _malloc_perror(func);
  1291. X      return ERROR;
  1292. X    }
  1293. X    
  1294. X    /* check line number */
  1295. X    if (dblockp->db_line > MAX_LINE_NUMBER) {
  1296. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1297. X    _malloc_message("bad line number on pointer '%#lx' alloced in '%s:%u'",
  1298. X            CHUNK_TO_USER(pnt), dblockp->db_file,
  1299. X            dblockp->db_line);
  1300. X      malloc_errno = MALLOC_BAD_LINE;
  1301. X      _malloc_perror(func);
  1302. X      return ERROR;
  1303. X    }
  1304. X    
  1305. X    /* check out size, BLOCK_SIZE / 2 == 512 when dblock allocs take over */
  1306. X    if (dblockp->db_size > BLOCK_SIZE / 2) {
  1307. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1308. X    _malloc_message("bad size on pointer '%#lx' alloced in '%s:%u'",
  1309. X            CHUNK_TO_USER(pnt), dblockp->db_file,
  1310. X            dblockp->db_line);
  1311. X      malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
  1312. X      _malloc_perror(func);
  1313. X      return ERROR;
  1314. X    }
  1315. X    
  1316. X    if (min_size != 0 && dblockp->db_size < min_size) {
  1317. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1318. X    _malloc_message("not enough space in pointer '%#lx' alloced in "
  1319. X            "'%s:%u'",
  1320. X            CHUNK_TO_USER(pnt), dblockp->db_file,
  1321. X            dblockp->db_line);
  1322. X      malloc_errno = MALLOC_WOULD_OVERWRITE;
  1323. X      _malloc_perror(func);
  1324. X      return ERROR;
  1325. X    }
  1326. X    
  1327. X    /* check file pointer */
  1328. X    if (dblockp->db_file == NULL) {
  1329. X      len = strlen(dblockp->db_file);
  1330. X      if (len < MIN_FILE_LENGTH || len > MAX_FILE_LENGTH) {
  1331. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1332. X      _malloc_message("bad file-name on pointer '%#lx' alloced in '%s:%u'",
  1333. X              CHUNK_TO_USER(pnt), dblockp->db_file,
  1334. X              dblockp->db_line);
  1335. X    malloc_errno = MALLOC_BAD_FILEP;
  1336. X    _malloc_perror(func);
  1337. X    return ERROR;
  1338. X      }
  1339. X    }
  1340. X    
  1341. X    /* check out the fence-posts */
  1342. X    if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1343. X      if (fence_read(dblockp->db_file, dblockp->db_line,
  1344. X             pnt, dblockp->db_size) != NOERROR)
  1345. X    return ERROR;
  1346. X    
  1347. X    return NOERROR;
  1348. X  }
  1349. X  
  1350. X  /* on a block boundary? */
  1351. X  if (! ON_BLOCK(pnt)) {
  1352. X    if (check == CHUNK_PNT_LOOSE) {
  1353. X      /*
  1354. X       * normalize size and pointer to nearest block.
  1355. X       *
  1356. X       * NOTE: we really need to back-track up the block list to find the
  1357. X       * starting user block to test things.
  1358. X       */
  1359. X      diff = pnt - BLOCK_POINTER(WHICH_BLOCK(pnt));
  1360. X      pnt -= diff;
  1361. X      if (min_size != 0)
  1362. X    min_size += diff;
  1363. X    }
  1364. X    else {
  1365. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1366. X    _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1367. X      malloc_errno = MALLOC_NOT_ON_BLOCK;
  1368. X      _malloc_perror(func);
  1369. X      return ERROR;
  1370. X    }
  1371. X  }
  1372. X  
  1373. X  /* are we on a normal block */
  1374. X  if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)
  1375. X      && ! (check == CHUNK_PNT_LOOSE
  1376. X        && BIT_IS_SET(bblockp->bb_flags, BBLOCK_USER))) {
  1377. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1378. X      _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1379. X    malloc_errno = MALLOC_NOT_START_USER;
  1380. X    _malloc_perror(func);
  1381. X    return ERROR;
  1382. X  }
  1383. X  
  1384. X  /* check line number */
  1385. X  if (bblockp->bb_line > MAX_LINE_NUMBER) {
  1386. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1387. X      _malloc_message("bad line number on pointer '%#lx' alloced in '%s:%u'",
  1388. X              CHUNK_TO_USER(pnt), bblockp->bb_file, bblockp->bb_line);
  1389. X    malloc_errno = MALLOC_BAD_LINE;
  1390. X    _malloc_perror(func);
  1391. X    return ERROR;
  1392. X  }
  1393. X  
  1394. X  /* check out size, BLOCK_SIZE / 2 == 512 when dblock allocs take over */
  1395. X  if (bblockp->bb_size <= BLOCK_SIZE / 2
  1396. X      || bblockp->bb_size > (1 << LARGEST_BLOCK)) {
  1397. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1398. X      _malloc_message("bad size on pointer '%#lx' alloced in '%s:%u'",
  1399. X              CHUNK_TO_USER(pnt), bblockp->bb_file, bblockp->bb_line);
  1400. X    malloc_errno = MALLOC_BAD_SIZE;
  1401. X    _malloc_perror(func);
  1402. X    return ERROR;
  1403. X  }
  1404. X  
  1405. X  if (min_size != 0 && bblockp->bb_size < min_size) {
  1406. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1407. X      _malloc_message("not enough space in pointer '%#lx' alloced in '%s:%u'",
  1408. X              CHUNK_TO_USER(pnt), bblockp->bb_file, bblockp->bb_line);
  1409. X    malloc_errno = MALLOC_WOULD_OVERWRITE;
  1410. X    _malloc_perror(func);
  1411. X    return ERROR;
  1412. X  }
  1413. X  
  1414. X  /* check file pointer */
  1415. X  if (bblockp->bb_file == NULL) {
  1416. X    len = strlen(bblockp->bb_file);
  1417. X    if (len < MIN_FILE_LENGTH || len > MAX_FILE_LENGTH) {
  1418. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1419. X    _malloc_message("bad file-name on pointer '%#lx' alloced in '%s:%u'",
  1420. X            CHUNK_TO_USER(pnt), bblockp->bb_file,
  1421. X            bblockp->bb_line);
  1422. X      malloc_errno = MALLOC_BAD_FILEP;
  1423. X      _malloc_perror(func);
  1424. X      return ERROR;
  1425. X    }
  1426. X  }
  1427. X  
  1428. X  /* check out the fence-posts if we are at the start of a user-block */
  1429. X  if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)
  1430. X      && BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1431. X    if (fence_read(bblockp->bb_file, bblockp->bb_line,
  1432. X           pnt, bblockp->bb_size) != NOERROR)
  1433. X      return ERROR;
  1434. X  
  1435. X  return NOERROR;
  1436. X}
  1437. X
  1438. X/**************************** information routines ***************************/
  1439. X
  1440. X/*
  1441. X * return some information associated with PNT, returns [NO]ERROR
  1442. X */
  1443. XEXPORT    int    _chunk_read_info(char * pnt, unsigned int * size,
  1444. X                 char ** file, unsigned int * line)
  1445. X{
  1446. X  bblock_t    *bblockp;
  1447. X  dblock_t    *dblockp;
  1448. X  
  1449. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  1450. X    _malloc_message("reading info about pointer '%#lx'", pnt);
  1451. X  
  1452. X  /* adjust the pointer down if fence-posting */
  1453. X  if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1454. X    pnt -= FENCE_BOTTOM;
  1455. X  
  1456. X  /* find which block it is in */
  1457. X  bblockp = find_bblock(pnt, NULL, NULL);
  1458. X  if (bblockp == NULL) {
  1459. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1460. X      _malloc_message("bad pointer '%#lx'", pnt);
  1461. X    _malloc_perror("find_bblock");
  1462. X    return ERROR;
  1463. X  }
  1464. X  
  1465. X  /* are we looking in a DBLOCK */
  1466. X  if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
  1467. X    /* on a mini-block boundary? */
  1468. X    if ((pnt - bblockp->bb_mem) % (1 << bblockp->bb_bitc) != 0) {
  1469. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1470. X    _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1471. X      malloc_errno = MALLOC_NOT_ON_BLOCK;
  1472. X      _malloc_perror("_chunk_read_info");
  1473. X      return ERROR;
  1474. X    }
  1475. X    
  1476. X    /* find correct dblockp */
  1477. X    dblockp = bblockp->bb_dblock + (pnt - bblockp->bb_mem) /
  1478. X      (1 << bblockp->bb_bitc);
  1479. X    
  1480. X    if (dblockp->db_bblock == bblockp) {
  1481. X      /* NOTE: we should run through free list here */
  1482. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1483. X    _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1484. X      malloc_errno = MALLOC_ALREADY_FREE;
  1485. X      _malloc_perror("_chunk_read_info");
  1486. X      return ERROR;
  1487. X    }
  1488. X    
  1489. X    /* write info back to user space */
  1490. X    if (size != NULL)
  1491. X      *size = dblockp->db_size;
  1492. X    if (file != NULL)
  1493. X      *file = dblockp->db_file;
  1494. X    if (line != NULL)
  1495. X      *line = dblockp->db_line;
  1496. X  }
  1497. X  else {
  1498. X    
  1499. X    /* verify that the pointer is either dblock or user allocated */
  1500. X    if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
  1501. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1502. X    _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1503. X      malloc_errno = MALLOC_NOT_USER;
  1504. X      _malloc_perror("_chunk_read_info");
  1505. X      return ERROR;
  1506. X    }
  1507. X    
  1508. X    /* write info back to user space */
  1509. X    if (size != NULL)
  1510. X      *size = bblockp->bb_size;
  1511. X    if (file != NULL)
  1512. X      *file = bblockp->bb_file;
  1513. X    if (line != NULL)
  1514. X      *line = bblockp->bb_line;
  1515. X  }
  1516. X  
  1517. X  return NOERROR;
  1518. X}
  1519. X
  1520. X/*
  1521. X * write new FILE, LINE, SIZE info into PNT
  1522. X */
  1523. XLOCAL    int    chunk_write_info(const char * file, const unsigned int line,
  1524. X                 char * pnt, unsigned int size)
  1525. X{
  1526. X  int        bitc, bblockc;
  1527. X  bblock_t    *bblockp;
  1528. X  dblock_t    *dblockp;
  1529. X  bblock_adm_t    *bblock_admp;
  1530. X  
  1531. X  /* find which block it is in */
  1532. X  bblockp = find_bblock(pnt, NULL, &bblock_admp);
  1533. X  if (bblockp == NULL) {
  1534. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1535. X      _malloc_message("bad pointer '%#lx'", pnt);
  1536. X    _malloc_perror("find_bblock");
  1537. X    return ERROR;
  1538. X  }
  1539. X  
  1540. X  /* are we looking in a DBLOCK */
  1541. X  if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
  1542. X    /* on a mini-block boundary? */
  1543. X    if ((pnt - bblockp->bb_mem) % (1 << bblockp->bb_bitc) != 0) {
  1544. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1545. X    _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1546. X      malloc_errno = MALLOC_NOT_ON_BLOCK;
  1547. X      _malloc_perror("chunk_write_info");
  1548. X      return ERROR;
  1549. X    }
  1550. X    
  1551. X    /* find correct dblockp */
  1552. X    dblockp = bblockp->bb_dblock + (pnt - bblockp->bb_mem) /
  1553. X      (1 << bblockp->bb_bitc);
  1554. X    
  1555. X    if (dblockp->db_bblock == bblockp) {
  1556. X      /* NOTE: we should run through free list here */
  1557. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1558. X    _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1559. X      malloc_errno = MALLOC_NOT_USER;
  1560. X      _malloc_perror("chunk_write_info");
  1561. X      return ERROR;
  1562. X    }
  1563. X    
  1564. X    /* write info back to user space */
  1565. X    if (size != NULL)
  1566. X      dblockp->db_size = size;
  1567. X    if (file != NULL)
  1568. X      dblockp->db_file = (char *)file;
  1569. X    if (line != NULL)
  1570. X      dblockp->db_line = (unsigned short)line;
  1571. X  }
  1572. X  else {
  1573. X    
  1574. X    /* verify that the pointer is user allocated */
  1575. X    if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
  1576. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1577. X    _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1578. X      malloc_errno = MALLOC_NOT_USER;
  1579. X      _malloc_perror("chunk_write_info");
  1580. X      return ERROR;
  1581. X    }
  1582. X    
  1583. X    /* count the bits */
  1584. X    bitc = num_bits(bblockp->bb_size);
  1585. X    if (bitc == ERROR)
  1586. X      return ERROR;
  1587. X    if (bitc < BASIC_BLOCK) {
  1588. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1589. X    _malloc_message("bad size on pointer '%#lx'", CHUNK_TO_USER(pnt));
  1590. X      malloc_errno = MALLOC_BAD_SIZE_INFO;
  1591. X      _malloc_perror("chunk_write_info");
  1592. X      return ERROR;
  1593. X    }
  1594. X    
  1595. X    /*
  1596. X     * reset values in the bblocks
  1597. X     */
  1598. X    for (bblockc = 0; bblockc < (1 << (bitc - BASIC_BLOCK));
  1599. X     bblockc++, bblockp++) {
  1600. X      
  1601. X      /* do we need to hop to a new bblock_admp header? */
  1602. X      if (bblockp == &bblock_admp->ba_block[BB_PER_ADMIN]) {
  1603. X    bblock_admp = bblock_admp->ba_next;
  1604. X    if (bblock_admp == NULL) {
  1605. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1606. X        _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1607. X      malloc_errno = MALLOC_BAD_ADMIN_LIST;
  1608. X      _malloc_perror("chunk_write_info");
  1609. X      return ERROR;
  1610. X    }
  1611. X    bblockp = bblock_admp->ba_block;
  1612. X      }
  1613. X      
  1614. X      /* set bblock info */
  1615. X      bblockp->bb_size = size;
  1616. X      bblockp->bb_file = (char *)file;
  1617. X      bblockp->bb_line = (unsigned short)line;
  1618. X    }
  1619. X  }
  1620. X  
  1621. X  return NOERROR;
  1622. X}
  1623. X
  1624. X/************************** low-level user functions *************************/
  1625. X
  1626. X/*
  1627. X * get a SIZE chunk of memory for FILE at LINE
  1628. X */
  1629. XEXPORT    char    *_chunk_malloc(const char * file, const unsigned int line,
  1630. X                   unsigned int size)
  1631. X{
  1632. X  int        bitc, bblockc;
  1633. X  bblock_t    *bblockp;
  1634. X  bblock_adm_t    *bblock_admp;
  1635. X  dblock_t    *dblockp;
  1636. X  char        *mem;
  1637. X  
  1638. X  malloc_count++;                /* counts calls to malloc */
  1639. X  
  1640. X#if ALLOW_ALLOC_ZERO_SIZE == 0
  1641. X  if (size == 0) {
  1642. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1643. X      _malloc_message("bad zero byte allocation from '%s:%u'", file, line);
  1644. X    malloc_errno = MALLOC_BAD_SIZE;
  1645. X    _malloc_perror("_chunk_malloc");
  1646. X    return MALLOC_ERROR;
  1647. X  }
  1648. X#endif
  1649. X  
  1650. X  if (file == NULL) {
  1651. X    malloc_errno = MALLOC_BAD_FILEP;
  1652. X    _malloc_perror("_chunk_malloc");
  1653. X    return MALLOC_ERROR;
  1654. X  }
  1655. X  
  1656. X  /* adjust the size */
  1657. X  if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1658. X    size += FENCE_OVERHEAD;
  1659. X  
  1660. X  /* count the bits */
  1661. X  bitc = num_bits(size);
  1662. X  if (bitc == ERROR)
  1663. X    return MALLOC_ERROR;
  1664. X  
  1665. X  /* monitor current allocation level */
  1666. X  alloc_current += size;
  1667. X  alloc_cur_given += 1 << bitc;
  1668. X  alloc_maximum = MAX(alloc_maximum, alloc_current);
  1669. X  alloc_max_given = MAX(alloc_max_given, alloc_cur_given);
  1670. X  alloc_total += size;
  1671. X  alloc_one_max = MAX(alloc_one_max, size);
  1672. X  
  1673. X  /* monitor pointer usage */
  1674. X  alloc_cur_pnts++;
  1675. X  alloc_max_pnts = MAX(alloc_max_pnts, alloc_cur_pnts);
  1676. X  alloc_tot_pnts++;
  1677. X  
  1678. X  /* have we exceeded the upper bounds */
  1679. X  if (bitc > LARGEST_BLOCK) {
  1680. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1681. X      _malloc_message("bad allocation of '%d' bytes from '%s:%u'",
  1682. X              size, file, line);
  1683. X    malloc_errno = MALLOC_TOO_BIG;
  1684. X    _malloc_perror("_chunk_malloc");
  1685. X    return MALLOC_ERROR;
  1686. X  }
  1687. X  
  1688. X  /* normalize to SMALLEST_BLOCK.  No use spending 16 bytes to admin 1 byte */
  1689. X  if (bitc < SMALLEST_BLOCK)
  1690. X    bitc = SMALLEST_BLOCK;
  1691. X  
  1692. X  /* allocate divided block if small */
  1693. X  if (bitc < BASIC_BLOCK) {
  1694. X    mem = get_dblock(bitc, &dblockp);
  1695. X    if (mem == NULL)
  1696. X      return MALLOC_ERROR;
  1697. X    
  1698. X    dblockp->db_line = (unsigned short)line;
  1699. X    dblockp->db_size = (unsigned short)size;
  1700. X    dblockp->db_file = (char *)file;
  1701. X  }
  1702. X  else {
  1703. X    
  1704. X    /*
  1705. X     * allocate some bblock space
  1706. X     */
  1707. X    
  1708. X    /* handle blocks */
  1709. X    bblockp = get_bblocks(bitc);
  1710. X    if (bblockp == NULL)
  1711. X      return MALLOC_ERROR;
  1712. X    
  1713. X    /* calculate current bblock admin pointer and memory pointer */
  1714. X    bblock_admp = (bblock_adm_t *)WHAT_BLOCK(bblockp);
  1715. X    mem = BLOCK_POINTER(bblock_admp->ba_count +
  1716. X            (bblockp - bblock_admp->ba_block));
  1717. X    
  1718. X    /*
  1719. X     * initialize the bblocks
  1720. X     */
  1721. X    for (bblockc = 0; bblockc < (1 << (bitc - BASIC_BLOCK));
  1722. X     bblockc++, bblockp++) {
  1723. X      
  1724. X      /* do we need to hop to a new bblock admin header? */
  1725. X      if (bblockp == &bblock_admp->ba_block[BB_PER_ADMIN]) {
  1726. X    bblock_admp = bblock_admp->ba_next;
  1727. X    if (bblock_admp == NULL)
  1728. X      return MALLOC_ERROR;
  1729. X    
  1730. X    bblockp = bblock_admp->ba_block;
  1731. X      }
  1732. X      
  1733. X      /* allocate the block if needed */
  1734. X      if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED))
  1735. X    if (_heap_alloc(BLOCK_SIZE) == HEAP_ALLOC_ERROR)
  1736. X      return MALLOC_ERROR;
  1737. X      
  1738. X      if (bblockc == 0)
  1739. X    bblockp->bb_flags = BBLOCK_START_USER;
  1740. X      else
  1741. X    bblockp->bb_flags = BBLOCK_USER;
  1742. X      
  1743. X      bblockp->bb_line    = (unsigned short)line;
  1744. X      bblockp->bb_size    = (unsigned int)size;
  1745. X      bblockp->bb_file    = (char *)file;
  1746. X    }
  1747. X  }
  1748. X  
  1749. X  /* overwrite to-be-alloced or non-used portion of memory */
  1750. X  if (BIT_IS_SET(_malloc_debug, DEBUG_ALLOC_BLANK))
  1751. X    (void)memset(mem, FREE_CHAR, 1 << bitc);
  1752. X  
  1753. X  /* write fence post info if needed */
  1754. X  if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1755. X    fence_write(mem, size);
  1756. X  
  1757. X  /* do we need to print transaction info? */
  1758. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_TRANS))
  1759. X    _malloc_message("*** alloc: at '%s:%u' asking %u bytes (%d bits), "
  1760. X            "got '%#lx'",
  1761. X            file, line, size - pnt_total_adm, bitc,
  1762. X            mem + pnt_below_adm);
  1763. X  
  1764. X  return mem + pnt_below_adm;
  1765. X}
  1766. X
  1767. X/*
  1768. X * frees PNT from the heap, returns FREE_ERROR or FREE_NOERROR
  1769. X */
  1770. XEXPORT    int    _chunk_free(const char * file, const unsigned int line,
  1771. X                char * pnt)
  1772. X{
  1773. X  int        bblockc, bitc;
  1774. X  bblock_t    *bblockp, *first;
  1775. X  bblock_adm_t    *bblock_admp;
  1776. X  dblock_t    *dblockp;
  1777. X  
  1778. X  free_count++;                    /* counts calls to free */
  1779. X  
  1780. X  alloc_cur_pnts--;
  1781. X  
  1782. X  /* adjust the pointer down if fence-posting */
  1783. X  if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1784. X    pnt -= FENCE_BOTTOM;
  1785. X  
  1786. X  /* find which block it is in */
  1787. X  bblockp = find_bblock(pnt, NULL, &bblock_admp);
  1788. X  if (bblockp == NULL) {
  1789. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1790. X      _malloc_message("bad pointer '%#lx'", pnt);
  1791. X    _malloc_perror("find_bblock");
  1792. X    return FREE_ERROR;
  1793. X  }
  1794. X  
  1795. X  /* are we free'ing a dblock entry? */
  1796. X  if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
  1797. X    
  1798. X    /* on a mini-block boundary? */
  1799. X    if ((pnt - bblockp->bb_mem) % (1 << bblockp->bb_bitc) != 0) {
  1800. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1801. X    _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1802. X      malloc_errno = MALLOC_NOT_ON_BLOCK;
  1803. X      _malloc_perror("_chunk_free");
  1804. X      return FREE_ERROR;
  1805. X    }
  1806. X    
  1807. X    /* find correct dblockp */
  1808. X    dblockp = bblockp->bb_dblock + (pnt - bblockp->bb_mem) /
  1809. X      (1 << bblockp->bb_bitc);
  1810. X    
  1811. X    if (dblockp->db_bblock == bblockp) {
  1812. X      /* NOTE: we should run through free list here */
  1813. X      if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1814. X    _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1815. X      malloc_errno = MALLOC_ALREADY_FREE;
  1816. X      _malloc_perror("_chunk_free");
  1817. X      return FREE_ERROR;
  1818. X    }
  1819. X    
  1820. X    /* do we need to print transaction info? */
  1821. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_TRANS))
  1822. X      _malloc_message("*** free: at '%s:%u' dblock pnter '%#lx': size %u, "
  1823. X              "file '%s:%u'",
  1824. X              file, line, CHUNK_TO_USER(pnt),
  1825. X              dblockp->db_size - pnt_total_adm,
  1826. X              dblockp->db_file, dblockp->db_line);
  1827. X    
  1828. X    /* check fence-post, probably again */
  1829. X    if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1830. X      if (fence_read(dblockp->db_file, dblockp->db_line,
  1831. X             pnt, dblockp->db_size) != NOERROR)
  1832. X    return FREE_ERROR;
  1833. X    
  1834. X    /* count the bits */
  1835. X    bitc = bblockp->bb_bitc;
  1836. X    
  1837. X    /* monitor current allocation level */
  1838. X    alloc_current -= dblockp->db_size;
  1839. X    alloc_cur_given -= 1 << bitc;
  1840. X    
  1841. X    /* rearrange info */
  1842. X    dblockp->db_bblock    = bblockp;
  1843. X    dblockp->db_next    = free_dblock[bitc];
  1844. X    free_dblock[bitc]    = dblockp;
  1845. X    free_space_count    += 1 << bitc;
  1846. X    
  1847. X    /* should we set free memory with FREE_CHAR? */
  1848. X    if (BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
  1849. X      (void)memset(pnt, FREE_CHAR, 1 << bitc);
  1850. X    
  1851. X    return FREE_NOERROR;
  1852. X  }
  1853. X  
  1854. X  /* on a block boundary? */
  1855. X  if (! ON_BLOCK(pnt)) {
  1856. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1857. X      _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1858. X    malloc_errno = MALLOC_NOT_ON_BLOCK;
  1859. X    _malloc_perror("_chunk_free");
  1860. X    return FREE_ERROR;
  1861. X  }
  1862. X  
  1863. X  /* are we on a normal block */
  1864. X  if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
  1865. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1866. X      _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1867. X    malloc_errno = MALLOC_NOT_START_USER;
  1868. X    _malloc_perror("_chunk_free");
  1869. X    return FREE_ERROR;
  1870. X  }
  1871. X  
  1872. X  /* do we need to print transaction info? */
  1873. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_TRANS))
  1874. X    _malloc_message("*** free: at '%s:%u' bblock pnter '%#lx': size %u, "
  1875. X            "file '%s:%u'",
  1876. X            file, line, CHUNK_TO_USER(pnt),
  1877. X            bblockp->bb_size - pnt_total_adm,
  1878. X            bblockp->bb_file, bblockp->bb_line);
  1879. X  
  1880. X  /* check fence-post, probably again */
  1881. X  if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1882. X    if (fence_read(bblockp->bb_file, bblockp->bb_line,
  1883. X           pnt, bblockp->bb_size) != NOERROR)
  1884. X      return FREE_ERROR;
  1885. X  
  1886. X  /* count the bits */
  1887. X  bitc = num_bits(bblockp->bb_size);
  1888. X  if (bitc == ERROR)
  1889. X    return FREE_ERROR;
  1890. X  
  1891. X  /* monitor current allocation level */
  1892. X  alloc_current -= bblockp->bb_size;
  1893. X  alloc_cur_given -= 1 << bitc;
  1894. X  
  1895. X  if (bitc < BASIC_BLOCK) {
  1896. X    if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1897. X      _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1898. X    malloc_errno = MALLOC_BAD_SIZE_INFO;
  1899. X    _malloc_perror("_chunk_free");
  1900. X    return FREE_ERROR;
  1901. X  }
  1902. X  
  1903. X  /* setup free linked-list */
  1904. X  first = free_bblock[bitc];
  1905. X  free_bblock[bitc] = bblockp;
  1906. X  free_space_count += 1 << bitc;
  1907. X  
  1908. X  bblockp->bb_next = first;
  1909. X  
  1910. X  /*
  1911. X   * initialize the bblocks
  1912. X   */
  1913. X  for (bblockc = 0; bblockc < (1 << (bitc - BASIC_BLOCK));
  1914. X       bblockc++, bblockp++, pnt += BLOCK_SIZE) {
  1915. X    
  1916. X    /* do we need to hop to a new bblock_admp header? */
  1917. X    if (bblockp == &bblock_admp->ba_block[BB_PER_ADMIN]) {
  1918. X      bblock_admp = bblock_admp->ba_next;
  1919. X      if (bblock_admp == NULL) {
  1920. X    malloc_errno = MALLOC_BAD_ADMIN_LIST;
  1921. X    _malloc_perror("_chunk_free");
  1922. X    return FREE_ERROR;
  1923. X      }
  1924. X      bblockp = bblock_admp->ba_block;
  1925. X    }
  1926. X    
  1927. X    /* set bblock info */
  1928. X    bblockp->bb_flags    = BBLOCK_FREE;
  1929. X    bblockp->bb_bitc    = bitc;            /* num bblocks in this chunk */
  1930. X    bblockp->bb_mem    = pnt;            /* pointer to real memory */
  1931. X    bblockp->bb_next    = first;
  1932. X    
  1933. X    /* should we set free memory with FREE_CHAR? */
  1934. X    if (BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
  1935. X      (void)memset(pnt, FREE_CHAR, BLOCK_SIZE);
  1936. X  }
  1937. X  
  1938. X  return FREE_NOERROR;
  1939. X}
  1940. X
  1941. X/*
  1942. X * reallocate a section of memory
  1943. X */
  1944. XEXPORT    char    *_chunk_realloc(const char * file, const unsigned int line,
  1945. X                char * oldp, unsigned int new_size)
  1946. X{
  1947. X  char        *newp, *old_file;
  1948. X  unsigned int    old_size, size, old_line;
  1949. X  int        old_bitc, new_bitc;
  1950. X  
  1951. X  realloc_count++;                /* counts calls to realloc */
  1952. X  
  1953. X  /* get info about old pointer */
  1954. X  if (_chunk_read_info(oldp, &old_size, &old_file, &old_line) != NOERROR)
  1955. X    return REALLOC_ERROR;
  1956. X  
  1957. X  /* adjust the pointer down if fence-posting */
  1958. X  if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
  1959. X    oldp -= FENCE_BOTTOM;
  1960. X    new_size += FENCE_OVERHEAD;
  1961. X  }
  1962. X  
  1963. X  /* check the fence-posting */
  1964. X  if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1965. X    if (fence_read(file, line, oldp, old_size) != NOERROR)
  1966. X      return REALLOC_ERROR;
  1967. X  
  1968. X  /* get the old and new bit sizes */
  1969. X  old_bitc = num_bits(old_size);
  1970. X  if (old_bitc == ERROR)
  1971. X    return REALLOC_ERROR;
  1972. X  
  1973. X  new_bitc = num_bits(new_size);
  1974. X  if (new_bitc == ERROR)
  1975. X    return REALLOC_ERROR;
  1976. X  
  1977. X  /* if we are not realloc copying and the size is the same */
  1978. X  if (BIT_IS_SET(_malloc_debug, DEBUG_REALLOC_COPY) || old_bitc != new_bitc) {
  1979. X    
  1980. X    /* readjust info */
  1981. X    if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
  1982. X      oldp += FENCE_BOTTOM;
  1983. X      old_size -= FENCE_OVERHEAD;
  1984. X      new_size -= FENCE_OVERHEAD;
  1985. X    }
  1986. X    
  1987. X    /* allocate space for new chunk */
  1988. X    newp = _chunk_malloc(file, line, new_size);
  1989. X    if (newp == MALLOC_ERROR)
  1990. X      return REALLOC_ERROR;
  1991. X    
  1992. X    /*
  1993. X     * NOTE: _chunk_malloc() already took care of the fence stuff...
  1994. X     */
  1995. X    
  1996. X    /* copy stuff into new section of memory */
  1997. X    size = MIN(new_size, old_size);
  1998. X    if (size > 0)
  1999. X      bcopy(oldp, newp, size);
  2000. X    
  2001. X    /* free old pointer */
  2002. X    if (_chunk_free(file, line, oldp) != FREE_NOERROR)
  2003. X      return REALLOC_ERROR;
  2004. X  }
  2005. X  else {
  2006. X    /* monitor current allocation level */
  2007. X    alloc_current += new_size - old_size;
  2008. X    alloc_maximum = MAX(alloc_maximum, alloc_current);
  2009. X    alloc_total += new_size;
  2010. X    alloc_one_max = MAX(alloc_one_max, new_size);
  2011. X    
  2012. X    /* monitor pointer usage */
  2013. X    alloc_tot_pnts++;
  2014. X    
  2015. X    /* reuse the old-pointer */
  2016. X    newp = oldp;
  2017. X    
  2018. X    /* rewrite size information */
  2019. X    if (chunk_write_info(file, line, newp, new_size) != NOERROR)
  2020. X      return REALLOC_ERROR;
  2021. X    
  2022. X    /* overwrite to-be-alloced or non-used portion of memory */
  2023. X    if (BIT_IS_SET(_malloc_debug, DEBUG_ALLOC_BLANK)
  2024. X    && (1 << new_bitc) - old_size > 0)
  2025. X      (void)memset(newp + old_size, FREE_CHAR, (1 << new_bitc) - old_size);
  2026. X    
  2027. X    /* write in fence-post info and adjust new pointer over fence info */
  2028. X    if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
  2029. X      fence_write(newp, new_size);
  2030. X      
  2031. X      newp += FENCE_BOTTOM;
  2032. X      oldp += FENCE_BOTTOM;
  2033. X      old_size -= FENCE_OVERHEAD;
  2034. X      new_size -= FENCE_OVERHEAD;
  2035. X    }
  2036. X  }
  2037. X  
  2038. X  /*
  2039. X   * do we need to print transaction info?
  2040. X   *
  2041. X   * NOTE: pointers and sizes here a user-level real
  2042. X   */
  2043. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_TRANS))
  2044. X    _malloc_message("*** realloc: at '%s:%u' from '%#lx' (%u bytes) "
  2045. X            "file '%s:%u' to '%#lx' (%u bytes)",
  2046. X            file, line,
  2047. X            oldp, old_size, old_file, old_line,
  2048. X            newp, new_size);
  2049. X  
  2050. X  /* newp is already user-level real */
  2051. X  return newp;
  2052. X}
  2053. X
  2054. X/***************************** diagnostic routines ***************************/
  2055. X
  2056. X/*
  2057. X * log present free and used lists
  2058. X */
  2059. XEXPORT    void    _chunk_list_count(void)
  2060. X{
  2061. X  int        bitc, count;
  2062. X  char        info[256], tmp[80];
  2063. X  bblock_t    *bblockp;
  2064. X  dblock_t    *dblockp;
  2065. X  
  2066. X  /* print header bit-counts */
  2067. X  info[0] = NULLC;
  2068. X  for (bitc = SMALLEST_BLOCK; bitc <= LARGEST_BLOCK; bitc++) {
  2069. X    (void)sprintf(tmp, "%*d", FREE_COLUMN, bitc);
  2070. X    (void)strcat(info, tmp);
  2071. X  }
  2072. X  
  2073. X  _malloc_message("bits: %s", info);
  2074. X  
  2075. X  /* dump the free (and later used) list counts */
  2076. X  info[0] = NULLC;
  2077. X  for (bitc = SMALLEST_BLOCK; bitc <= LARGEST_BLOCK; bitc++) {
  2078. X    if (bitc < BASIC_BLOCK)
  2079. X      for (count = 0, dblockp = free_dblock[bitc]; dblockp != NULL;
  2080. X       count++, dblockp = dblockp->db_next);
  2081. X    else
  2082. X      for (count = 0, bblockp = free_bblock[bitc]; bblockp != NULL;
  2083. X       count++, bblockp = bblockp->bb_next);
  2084. X    
  2085. X    (void)sprintf(tmp, "%*d", FREE_COLUMN, count);
  2086. X    (void)strcat(info, tmp);
  2087. X  }
  2088. X  
  2089. X  _malloc_message("free: %s", info);
  2090. X}
  2091. X
  2092. X/*
  2093. X * log statistics on the heap
  2094. X */
  2095. XEXPORT    void    _chunk_stats(void)
  2096. X{
  2097. X  long        overhead;
  2098. X  
  2099. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  2100. X    _malloc_message("getting chunk statistics");
  2101. X  
  2102. X  /* version information */
  2103. X  _malloc_message("malloc version '%s'", malloc_version);
  2104. X  
  2105. X  /* general heap information */
  2106. X  _malloc_message("heap start %#lx, heap end %#lx, heap size %ld bytes",
  2107. X          _heap_base, _heap_last, HEAP_SIZE);
  2108. X  
  2109. X  /* log user allocation information */
  2110. X  _malloc_message("alloc calls: malloc %d, realloc %d, calloc %d, free %d",
  2111. X          malloc_count - _calloc_count, realloc_count, _calloc_count,
  2112. X          free_count);
  2113. X  
  2114. X  _malloc_message("total amount of memory allocated:   %ld bytes (%ld pnts)",
  2115. X          alloc_total, alloc_tot_pnts);
  2116. X  
  2117. X  _malloc_message("maximum memory in use at one time:  %ld bytes (%ld pnts)",
  2118. X          alloc_maximum, alloc_max_pnts);
  2119. X  
  2120. X  _malloc_message("maximum memory alloced with 1 call: %ld bytes",
  2121. X          alloc_one_max);
  2122. X  
  2123. X  _malloc_message("max base 2 allocation loss: %ld bytes (%d%%)",
  2124. X          alloc_max_given - alloc_maximum,
  2125. X          (alloc_max_given == 0 ? 0 :
  2126. X           100 - ((alloc_maximum * 100) / alloc_max_given)));
  2127. X  
  2128. X  _malloc_message("final user memory space: %ld bytes",
  2129. X          alloc_current + free_space_count);
  2130. X  
  2131. X  /* log administration information */
  2132. X  _malloc_message("final admin: basic-blocks %d, divided blocks %d",
  2133. X          bblock_count, dblock_count);
  2134. X  
  2135. X  overhead = HEAP_SIZE - (alloc_current + free_space_count);
  2136. X  
  2137. X  _malloc_message("final heap admin overhead: %ld bytes (%d%%)",
  2138. X          overhead,
  2139. X          (HEAP_SIZE == 0 ? 0 : (overhead * 100) / HEAP_SIZE));
  2140. X}
  2141. X
  2142. X/*
  2143. X * dump the unfreed memory, logs the unfreed information to logger
  2144. X */
  2145. XEXPORT    void    _chunk_dump_not_freed(void)
  2146. X{
  2147. X  bblock_adm_t    *this;
  2148. X  bblock_t    *bblockp;
  2149. X  dblock_t    *dblockp;
  2150. X  char        *mem, unknown;
  2151. X  int        unknown_sizec = 0, unknown_dblockc = 0, unknown_bblockc = 0;
  2152. X  int        sizec = 0, dblockc = 0, bblockc = 0;
  2153. X  
  2154. X  if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  2155. X    _malloc_message("dumping the unfreed pointers");
  2156. X  
  2157. X  /* has anything been alloced yet? */
  2158. X  this = bblock_adm_head;
  2159. X  if (this == NULL)
  2160. X    return;
  2161. X  
  2162. X  /* check out the basic blocks */
  2163. X  for (bblockp = this->ba_block;; bblockp++) {
  2164. X    
  2165. X    /* are we at the end of the bb_admin section */
  2166. X    if (bblockp >= this->ba_block + BB_PER_ADMIN) {
  2167. X      this = this->ba_next;
  2168. X      
  2169. X      /* are we done? */
  2170. X      if (this == NULL)
  2171. X    break;
  2172. X      
  2173. X      bblockp = this->ba_block;
  2174. X    }
  2175. X    
  2176. X    /*
  2177. X     * check for different types
  2178. X     */
  2179. X    switch (bblockp->bb_flags) {
  2180. X      
  2181. X    case BBLOCK_ADMIN:
  2182. X    case BBLOCK_DBLOCK:
  2183. X    case BBLOCK_FREE:
  2184. X    case BBLOCK_USER:
  2185. X      break;
  2186. X      
  2187. X    case BBLOCK_START_USER:
  2188. X      /* find pointer to memory chunk */
  2189. X      mem = BLOCK_POINTER(this->ba_count + (bblockp - this->ba_block));
  2190. X      
  2191. X      /* unknown pointer? */
  2192. X      if (bblockp->bb_line == MALLOC_DEFAULT_LINE
  2193. X      && strcmp(MALLOC_DEFAULT_FILE, bblockp->bb_file) == 0) {
  2194. X    unknown_bblockc++;
  2195. X    unknown_sizec += bblockp->bb_size - pnt_total_adm;
  2196. X    unknown = 1;
  2197. X      }
  2198. X      else
  2199. X    unknown = 0;
  2200. X      
  2201. X      if (! unknown || BIT_IS_SET(_malloc_debug, DEBUG_LOG_UNKNOWN))
  2202. X    _malloc_message("not freed: %#9lx (%8d bytes) from '%s:%u'",
  2203. X            mem  + pnt_below_adm, bblockp->bb_size - pnt_total_adm,
  2204. X            bblockp->bb_file, bblockp->bb_line);
  2205. X      
  2206. X      sizec += bblockp->bb_size - pnt_total_adm;
  2207. X      bblockc++;
  2208. X      break;
  2209. X      
  2210. X    case BBLOCK_DBLOCK_ADMIN:
  2211. X      
  2212. X      for (dblockp = bblockp->bb_slotp->da_block;
  2213. X       dblockp < bblockp->bb_slotp->da_block + DB_PER_ADMIN; dblockp++) {
  2214. X    
  2215. X    /* verify if we have a good bblock pointer and good back pointer */
  2216. X    if (dblockp->db_bblock == NULL && dblockp->db_next == NULL)
  2217. X      continue;
  2218. X    
  2219. X    /* check out dblock pointer and next pointer (if free) */
  2220. X    if (dblockp->db_next == NULL || IS_IN_HEAP(dblockp->db_next))
  2221. X      continue;
  2222. X    
  2223. X    {
  2224. X      bblock_adm_t    *bbap;
  2225. X      bblock_t    *bbp;
  2226. X      
  2227. X      bbap = bblock_adm_head;
  2228. X      
  2229. X      /* check out the basic blocks */
  2230. X      for (bbp = bbap->ba_block;; bbp++) {
  2231. X        
  2232. X        /* are we at the end of the bb_admin section */
  2233. X        if (bbp >= bbap->ba_block + BB_PER_ADMIN) {
  2234. X          bbap = bbap->ba_next;
  2235. X          
  2236. X          /* are we done? */
  2237. X          if (bbap == NULL)
  2238. X        break;
  2239. X          
  2240. X          bbp = bbap->ba_block;
  2241. X        }
  2242. X        
  2243. X        if (bbp->bb_flags != BBLOCK_DBLOCK)
  2244. X          continue;
  2245. X        
  2246. X        if (dblockp >= bbp->bb_dblock
  2247. X        && dblockp < bbp->bb_dblock +
  2248. X        (1 << (BASIC_BLOCK - bbp->bb_bitc)))
  2249. X          break;
  2250. X      }
  2251. X      
  2252. X      if (bbap == NULL) {
  2253. X        malloc_errno = MALLOC_BAD_DBLOCK_POINTER;
  2254. X        _malloc_perror("_chunk_dump_not_freed");
  2255. X        return;
  2256. X      }
  2257. X      
  2258. X      mem = bbp->bb_mem + (dblockp - bbp->bb_dblock) * (1 << bbp->bb_bitc);
  2259. X    }
  2260. X    
  2261. X    /* unknown pointer? */
  2262. X    if (dblockp->db_line == MALLOC_DEFAULT_LINE
  2263. X        && strcmp(MALLOC_DEFAULT_FILE, dblockp->db_file) == 0) {
  2264. X      unknown_dblockc++;
  2265. X      unknown_sizec += dblockp->db_size - pnt_total_adm;
  2266. X      unknown = 1;
  2267. X    }
  2268. X    else
  2269. X      unknown = 0;
  2270. X    
  2271. X    if (! unknown || BIT_IS_SET(_malloc_debug, DEBUG_LOG_UNKNOWN))
  2272. X      _malloc_message("not freed: %#9lx (%8d bytes) from '%s:%u'",
  2273. X              mem  + pnt_below_adm,
  2274. X              dblockp->db_size - pnt_total_adm,
  2275. X              dblockp->db_file, dblockp->db_line);
  2276. X    
  2277. X    sizec += dblockp->db_size - pnt_total_adm;
  2278. X    dblockc++;
  2279. X      }
  2280. X      break;
  2281. X    }
  2282. X  }
  2283. X  
  2284. X  /* copy out size of pointers */
  2285. X  if (bblockc + dblockc > 0) {
  2286. X    _malloc_message("known memory not freed: %d bblock, %d dblock, %d byte%s",
  2287. X            bblockc - unknown_bblockc, dblockc - unknown_dblockc,
  2288. X            sizec - unknown_sizec, (sizec == 1 ? "" : "s"));
  2289. X    
  2290. X    _malloc_message("unknown memory not freed: %d bblock, %d dblock, "
  2291. X            "%d byte%s",
  2292. X            unknown_bblockc, unknown_dblockc, unknown_sizec,
  2293. X            (unknown_sizec == 1 ? "" : "s"));
  2294. X  }
  2295. X}
  2296. X
  2297. X/*
  2298. X * log the heap structure plus information on the blocks if necessary
  2299. X */
  2300. XEXPORT    void    _chunk_log_heap_map(void)
  2301. X{
  2302. X  /* did we map the heap second ago? */
  2303. X  if (! BIT_IS_SET(_malloc_debug, DEBUG_CHECK_HEAP) ||
  2304. X      ! BIT_IS_SET(_malloc_debug, DEBUG_HEAP_CHECK_MAP))
  2305. X    log_heap_map();
  2306. X}
  2307. END_OF_FILE
  2308. if test 66104 -ne `wc -c <'chunk.c'`; then
  2309.     echo shar: \"'chunk.c'\" unpacked with wrong size!
  2310. fi
  2311. # end of 'chunk.c'
  2312. fi
  2313. echo shar: End of archive 2 \(of 5\).
  2314. cp /dev/null ark2isdone
  2315. MISSING=""
  2316. for I in 1 2 3 4 5 ; do
  2317.     if test ! -f ark${I}isdone ; then
  2318.     MISSING="${MISSING} ${I}"
  2319.     fi
  2320. done
  2321. if test "${MISSING}" = "" ; then
  2322.     echo You have unpacked all 5 archives.
  2323.     echo "Do a 'sh ./configure' to configure the library"
  2324.     rm -f ark[1-9]isdone
  2325. else
  2326.     echo You still need to unpack the following archives:
  2327.     echo "        " ${MISSING}
  2328. fi
  2329. ##  End of shell archive.
  2330. exit 0
  2331.