heaptrc.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1993-98 by the Free Pascal development team.
  5. Heap tracer
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit heaptrc;
  13. interface
  14. Procedure DumpHeap;
  15. Procedure MarkHeap;
  16. { define EXTRA to add more
  17. tests :
  18. - keep all memory after release and
  19. check by CRC value if not changed after release
  20. WARNING this needs extremely much memory (PM) }
  21. type
  22. FillExtraInfoType = procedure(p : pointer);
  23. { allows to add several longint value that can help
  24. to debug :
  25. see for instance ppheap.pas unit of the compiler source PM }
  26. Procedure SetExtraInfo( size : longint;func : FillExtraInfoType);
  27. Procedure SetHeapTraceOutput(const name : string);
  28. const
  29. { tracing level
  30. splitted in two if memory is released !! }
  31. {$ifdef EXTRA}
  32. tracesize = 16;
  33. {$else EXTRA}
  34. tracesize = 8;
  35. {$endif EXTRA}
  36. quicktrace : boolean=true;
  37. { calls halt() on error by default !! }
  38. HaltOnError : boolean = true;
  39. { set this to true if you suspect that memory
  40. is freed several times }
  41. {$ifdef EXTRA}
  42. keepreleased : boolean=true;
  43. add_tail : boolean = true;
  44. {$else EXTRA}
  45. keepreleased : boolean=false;
  46. add_tail : boolean = false;
  47. {$endif EXTRA}
  48. { put crc in sig
  49. this allows to test for writing into that part }
  50. usecrc : boolean = true;
  51. implementation
  52. type
  53. plongint = ^longint;
  54. const
  55. { allows to add custom info in heap_mem_info }
  56. extra_info_size : longint = 0;
  57. exact_info_size : longint = 0;
  58. { function to fill this info up }
  59. fill_extra_info : FillExtraInfoType = nil;
  60. error_in_heap : boolean = false;
  61. type
  62. pheap_mem_info = ^theap_mem_info;
  63. { warning the size of theap_mem_info
  64. must be a multiple of 8
  65. because otherwise you will get
  66. problems when releasing the usual memory part !!
  67. sizeof(theap_mem_info = 16+tracesize*4 so
  68. tracesize must be even !! PM }
  69. theap_mem_info = record
  70. previous,
  71. next : pheap_mem_info;
  72. size : longint;
  73. sig : longint;
  74. {$ifdef EXTRA}
  75. release_sig : longint;
  76. next_valid : pheap_mem_info;
  77. {$endif EXTRA}
  78. calls : array [1..tracesize] of longint;
  79. extra_info : record
  80. end;
  81. end;
  82. var
  83. ptext : ^text;
  84. ownfile : text;
  85. {$ifdef EXTRA}
  86. error_file : text;
  87. heap_valid_first,
  88. heap_valid_last : pheap_mem_info;
  89. {$endif EXTRA}
  90. heap_mem_root : pheap_mem_info;
  91. getmem_cnt,
  92. freemem_cnt : longint;
  93. getmem_size,
  94. freemem_size : longint;
  95. getmem8_size,
  96. freemem8_size : longint;
  97. {*****************************************************************************
  98. Crc 32
  99. *****************************************************************************}
  100. var
  101. {$ifdef Delphi}
  102. Crc32Tbl : array[0..255] of longword;
  103. {$else Delphi}
  104. Crc32Tbl : array[0..255] of longint;
  105. {$endif Delphi}
  106. procedure MakeCRC32Tbl;
  107. var
  108. {$ifdef Delphi}
  109. crc : longword;
  110. {$else Delphi}
  111. crc : longint;
  112. {$endif Delphi}
  113. i,n : byte;
  114. begin
  115. for i:=0 to 255 do
  116. begin
  117. crc:=i;
  118. for n:=1 to 8 do
  119. if odd(crc) then
  120. crc:=(crc shr 1) xor $edb88320
  121. else
  122. crc:=crc shr 1;
  123. Crc32Tbl[i]:=crc;
  124. end;
  125. end;
  126. {$ifopt R+}
  127. {$define Range_check_on}
  128. {$endif opt R+}
  129. {$R- needed here }
  130. Function UpdateCrc32(InitCrc:longint;var InBuf;InLen:Longint):longint;
  131. var
  132. i : longint;
  133. p : pchar;
  134. begin
  135. p:=@InBuf;
  136. for i:=1 to InLen do
  137. begin
  138. InitCrc:=Crc32Tbl[byte(InitCrc) xor byte(p^)] xor (InitCrc shr 8);
  139. inc(longint(p));
  140. end;
  141. UpdateCrc32:=InitCrc;
  142. end;
  143. Function calculate_sig(p : pheap_mem_info) : longint;
  144. var
  145. crc : longint;
  146. pl : plongint;
  147. begin
  148. crc:=$ffffffff;
  149. crc:=UpdateCrc32(crc,p^.size,sizeof(longint));
  150. crc:=UpdateCrc32(crc,p^.calls,tracesize*sizeof(longint));
  151. if extra_info_size>0 then
  152. crc:=UpdateCrc32(crc,p^.extra_info,exact_info_size);
  153. if add_tail then
  154. begin
  155. { Check also 4 bytes just after allocation !! }
  156. pl:=pointer(p)+extra_info_size+sizeof(theap_mem_info)+p^.size;
  157. crc:=UpdateCrc32(crc,pl^,sizeof(longint));
  158. end;
  159. calculate_sig:=crc;
  160. end;
  161. {$ifdef EXTRA}
  162. Function calculate_release_sig(p : pheap_mem_info) : longint;
  163. var
  164. crc : longint;
  165. pl : plongint;
  166. begin
  167. crc:=$ffffffff;
  168. crc:=UpdateCrc32(crc,p^.size,sizeof(longint));
  169. crc:=UpdateCrc32(crc,p^.calls,tracesize*sizeof(longint));
  170. if extra_info_size>0 then
  171. crc:=UpdateCrc32(crc,p^.extra_info,exact_info_size);
  172. { Check the whole of the whole allocation }
  173. pl:=pointer(p)+extra_info_size+sizeof(theap_mem_info);
  174. crc:=UpdateCrc32(crc,pl^,p^.size);
  175. { Check also 4 bytes just after allocation !! }
  176. if add_tail then
  177. begin
  178. { Check also 4 bytes just after allocation !! }
  179. pl:=pointer(p)+extra_info_size+sizeof(theap_mem_info)+p^.size;
  180. crc:=UpdateCrc32(crc,pl^,sizeof(longint));
  181. end;
  182. calculate_release_sig:=crc;
  183. end;
  184. {$endif EXTRA}
  185. {$ifdef Range_check_on}
  186. {$R+}
  187. {$undef Range_check_on}
  188. {$endif Range_check_on}
  189. {*****************************************************************************
  190. Helpers
  191. *****************************************************************************}
  192. procedure call_stack(pp : pheap_mem_info;var ptext : text);
  193. var
  194. i : longint;
  195. begin
  196. writeln(ptext,'Call trace for block 0x',hexstr(longint(pp+sizeof(theap_mem_info)),8),' size ',pp^.size);
  197. for i:=1 to tracesize do
  198. if pp^.calls[i]<>0 then
  199. writeln(ptext,' 0x',hexstr(pp^.calls[i],8));
  200. for i:=0 to (exact_info_size div 4)-1 do
  201. writeln(ptext,'info ',i,'=',plongint(@pp^.extra_info+4*i)^);
  202. end;
  203. procedure call_free_stack(pp : pheap_mem_info;var ptext : text);
  204. var
  205. i : longint;
  206. begin
  207. writeln(ptext,'Call trace for block 0x',hexstr(longint(pp+sizeof(theap_mem_info)),8),' size ',pp^.size);
  208. for i:=1 to tracesize div 2 do
  209. if pp^.calls[i]<>0 then
  210. writeln(ptext,' 0x',hexstr(pp^.calls[i],8));
  211. writeln(ptext,' was released at ');
  212. for i:=(tracesize div 2)+1 to tracesize do
  213. if pp^.calls[i]<>0 then
  214. writeln(ptext,' 0x',hexstr(pp^.calls[i],8));
  215. for i:=0 to (exact_info_size div 4)-1 do
  216. writeln(ptext,'info ',i,'=',plongint(@pp^.extra_info+4*i)^);
  217. end;
  218. procedure dump_already_free(p : pheap_mem_info;var ptext : text);
  219. begin
  220. Writeln(ptext,'Marked memory at ',HexStr(longint(p+sizeof(theap_mem_info)),8),' released');
  221. call_free_stack(p,ptext);
  222. Writeln(ptext,'freed again at');
  223. dump_stack(ptext,get_caller_frame(get_frame));
  224. end;
  225. procedure dump_error(p : pheap_mem_info;var ptext : text);
  226. begin
  227. Writeln(ptext,'Marked memory at ',HexStr(longint(p+sizeof(theap_mem_info)),8),' invalid');
  228. Writeln(ptext,'Wrong signature $',hexstr(p^.sig,8)
  229. ,' instead of ',hexstr(calculate_sig(p),8));
  230. dump_stack(ptext,get_caller_frame(get_frame));
  231. end;
  232. {$ifdef EXTRA}
  233. procedure dump_change_after(p : pheap_mem_info;var ptext : text);
  234. var pp : pchar;
  235. i : longint;
  236. begin
  237. Writeln(ptext,'Marked memory at ',HexStr(longint(p+sizeof(theap_mem_info)),8),' invalid');
  238. Writeln(ptext,'Wrong release CRC $',hexstr(p^.release_sig,8)
  239. ,' instead of ',hexstr(calculate_release_sig(p),8));
  240. Writeln(ptext,'This memory was changed after call to freemem !');
  241. call_free_stack(p,ptext);
  242. pp:=pchar(p)+sizeof(theap_mem_info)+extra_info_size;
  243. for i:=0 to p^.size-1 do
  244. if byte(pp[i])<>$F0 then
  245. Writeln(ptext,'offset',i,':$',hexstr(i,8),'"',pp[i],'"');
  246. end;
  247. {$endif EXTRA}
  248. procedure dump_wrong_size(p : pheap_mem_info;size : longint;var ptext : text);
  249. var
  250. i : longint;
  251. begin
  252. Writeln(ptext,'Marked memory at ',HexStr(longint(p+sizeof(theap_mem_info)),8),' invalid');
  253. Writeln(ptext,'Wrong size : ',p^.size,' allocated ',size,' freed');
  254. dump_stack(ptext,get_caller_frame(get_frame));
  255. for i:=0 to (exact_info_size div 4)-1 do
  256. writeln(ptext,'info ',i,'=',plongint(@p^.extra_info+4*i)^);
  257. call_stack(p,ptext);
  258. end;
  259. function is_in_getmem_list (p : pointer) : boolean;
  260. var
  261. i : longint;
  262. pp : pheap_mem_info;
  263. begin
  264. is_in_getmem_list:=false;
  265. pp:=heap_mem_root;
  266. i:=0;
  267. while pp<>nil do
  268. begin
  269. if ((pp^.sig<>$DEADBEEF) or usecrc) and
  270. ((pp^.sig<>calculate_sig(pp)) or not usecrc) and
  271. (pp^.sig <> $AAAAAAAA) then
  272. begin
  273. writeln(ptext^,'error in linked list of heap_mem_info');
  274. RunError(204);
  275. end;
  276. if pp=p then
  277. is_in_getmem_list:=true;
  278. pp:=pp^.previous;
  279. inc(i);
  280. if i>getmem_cnt-freemem_cnt then
  281. writeln(ptext^,'error in linked list of heap_mem_info');
  282. end;
  283. end;
  284. {*****************************************************************************
  285. TraceGetMem
  286. *****************************************************************************}
  287. procedure TraceGetMem(var p:pointer;size:longint);
  288. var
  289. i,bp : longint;
  290. pl : plongint;
  291. begin
  292. inc(getmem_size,size);
  293. inc(getmem8_size,((size+7) div 8)*8);
  294. { Do the real GetMem, but alloc also for the info block }
  295. bp:=size+sizeof(theap_mem_info)+extra_info_size;
  296. if add_tail then
  297. bp:=bp+sizeof(longint);
  298. SysGetMem(p,bp);
  299. { Create the info block }
  300. pheap_mem_info(p)^.sig:=$DEADBEEF;
  301. pheap_mem_info(p)^.size:=size;
  302. if add_tail then
  303. begin
  304. pl:=pointer(p)+bp-sizeof(longint);
  305. pl^:=$DEADBEEF;
  306. end;
  307. bp:=get_caller_frame(get_frame);
  308. for i:=1 to tracesize do
  309. begin
  310. pheap_mem_info(p)^.calls[i]:=get_caller_addr(bp);
  311. bp:=get_caller_frame(bp);
  312. end;
  313. { insert in the linked list }
  314. if heap_mem_root<>nil then
  315. heap_mem_root^.next:=pheap_mem_info(p);
  316. pheap_mem_info(p)^.previous:=heap_mem_root;
  317. pheap_mem_info(p)^.next:=nil;
  318. {$ifdef EXTRA}
  319. pheap_mem_info(p)^.next_valid:=nil;
  320. if assigned(heap_valid_last) then
  321. heap_valid_last^.next_valid:=pheap_mem_info(p);
  322. heap_valid_last:=pheap_mem_info(p);
  323. if not assigned(heap_valid_first) then
  324. heap_valid_first:=pheap_mem_info(p);
  325. {$endif EXTRA}
  326. heap_mem_root:=p;
  327. if assigned(fill_extra_info) then
  328. fill_extra_info(@pheap_mem_info(p)^.extra_info);
  329. { update the pointer }
  330. if usecrc then
  331. pheap_mem_info(p)^.sig:=calculate_sig(pheap_mem_info(p));
  332. inc(p,sizeof(theap_mem_info)+extra_info_size);
  333. inc(getmem_cnt);
  334. end;
  335. {*****************************************************************************
  336. TraceFreeMem
  337. *****************************************************************************}
  338. procedure TraceFreeMem(var p:pointer;size:longint);
  339. var i,bp, ppsize : longint;
  340. pp,pp2 : pheap_mem_info;
  341. begin
  342. inc(freemem_size,size);
  343. inc(freemem8_size,((size+7) div 8)*8);
  344. ppsize:= size + sizeof(theap_mem_info)+extra_info_size;
  345. if add_tail then
  346. ppsize:=ppsize+sizeof(longint);
  347. dec(p,sizeof(theap_mem_info)+extra_info_size);
  348. pp:=pheap_mem_info(p);
  349. if not quicktrace and not(is_in_getmem_list(p)) then
  350. RunError(204);
  351. if pp^.sig=$AAAAAAAA then
  352. begin
  353. error_in_heap:=true;
  354. dump_already_free(pp,ptext^);
  355. if haltonerror then halt(1);
  356. end
  357. else if ((pp^.sig<>$DEADBEEF) or usecrc) and
  358. ((pp^.sig<>calculate_sig(pp)) or not usecrc) then
  359. begin
  360. error_in_heap:=true;
  361. dump_error(pp,ptext^);
  362. {$ifdef EXTRA}
  363. dump_error(pp,error_file);
  364. {$endif EXTRA}
  365. { don't release anything in this case !! }
  366. if haltonerror then halt(1);
  367. exit;
  368. end
  369. else if pp^.size<>size then
  370. begin
  371. error_in_heap:=true;
  372. dump_wrong_size(pp,size,ptext^);
  373. {$ifdef EXTRA}
  374. dump_wrong_size(pp,size,error_file);
  375. {$endif EXTRA}
  376. if haltonerror then halt(1);
  377. { don't release anything in this case !! }
  378. exit;
  379. end;
  380. { now it is released !! }
  381. pp^.sig:=$AAAAAAAA;
  382. if not keepreleased then
  383. begin
  384. if pp^.next<>nil then
  385. pp^.next^.previous:=pp^.previous;
  386. if pp^.previous<>nil then
  387. pp^.previous^.next:=pp^.next;
  388. if pp=heap_mem_root then
  389. heap_mem_root:=heap_mem_root^.previous;
  390. end
  391. else
  392. begin
  393. bp:=get_caller_frame(get_frame);
  394. for i:=(tracesize div 2)+1 to tracesize do
  395. begin
  396. pp^.calls[i]:=get_caller_addr(bp);
  397. bp:=get_caller_frame(bp);
  398. end;
  399. end;
  400. inc(freemem_cnt);
  401. { release the normal memory at least !! }
  402. { this way we keep all info about all released memory !! }
  403. if keepreleased then
  404. begin
  405. {$ifndef EXTRA}
  406. dec(ppsize,sizeof(theap_mem_info)+extra_info_size);
  407. inc(p,sizeof(theap_mem_info)+extra_info_size);
  408. {$else EXTRA}
  409. inc(p,sizeof(theap_mem_info)+extra_info_size);
  410. fillchar(p^,size,#240); { $F0 will lead to GFP if used as pointer ! }
  411. { We want to check if the memory was changed after release !! }
  412. pp^.release_sig:=calculate_release_sig(pp);
  413. if pp=heap_valid_first then
  414. begin
  415. heap_valid_first:=pp^.next_valid;
  416. if pp=heap_valid_last then
  417. heap_valid_last:=nil;
  418. exit;
  419. end;
  420. pp2:=heap_valid_first;
  421. while assigned(pp2) do
  422. begin
  423. if pp2^.next_valid=pp then
  424. begin
  425. pp2^.next_valid:=pp^.next_valid;
  426. if pp=heap_valid_last then
  427. heap_valid_last:=pp2;
  428. exit;
  429. end
  430. else
  431. pp2:=pp2^.next_valid;
  432. end;
  433. exit;
  434. {$endif EXTRA}
  435. end;
  436. SysFreeMem(p,ppsize);
  437. end;
  438. {*****************************************************************************
  439. Check pointer
  440. *****************************************************************************}
  441. {$ifdef go32v2}
  442. var
  443. __stklen : cardinal;external name '__stklen';
  444. __stkbottom : cardinal;external name '__stkbottom';
  445. edata : cardinal; external name 'edata';
  446. {$endif go32v2}
  447. var
  448. heap_at_init : pointer;
  449. procedure CheckPointer(p : pointer);[public, alias : 'FPC_CHECKPOINTER'];
  450. var
  451. i : longint;
  452. pp : pheap_mem_info;
  453. get_ebp,stack_top : cardinal;
  454. data_end : cardinal;
  455. label
  456. _exit;
  457. begin
  458. asm
  459. pushal
  460. end;
  461. if p=nil then
  462. goto _exit;
  463. i:=0;
  464. {$ifdef go32v2}
  465. if cardinal(p)<$1000 then
  466. runerror(216);
  467. asm
  468. movl %ebp,get_ebp
  469. leal edata,%eax
  470. movl %eax,data_end
  471. end;
  472. stack_top:=__stkbottom+__stklen;
  473. { allow all between start of code and end of data }
  474. if cardinal(p)<=data_end then
  475. goto _exit;
  476. { .bss section }
  477. if cardinal(p)<=cardinal(heap_at_init) then
  478. goto _exit;
  479. { stack can be above heap !! }
  480. if (cardinal(p)>=get_ebp) and (cardinal(p)<=stack_top) then
  481. goto _exit;
  482. {$endif go32v2}
  483. { I don't know where the stack is in other OS !! }
  484. if p>=heapptr then
  485. runerror(216);
  486. { first try valid list faster }
  487. {$ifdef EXTRA}
  488. pp:=heap_valid_first;
  489. while pp<>nil do
  490. begin
  491. { inside this valid block ! }
  492. if (cardinal(p)>=cardinal(pp)+sizeof(theap_mem_info)+extra_info_size) and
  493. (cardinal(p)<=cardinal(pp)+sizeof(theap_mem_info)+extra_info_size+pp^.size) then
  494. begin
  495. { check allocated block }
  496. if ((pp^.sig=$DEADBEEF) and not usecrc) or
  497. ((pp^.sig=calculate_sig(pp)) and usecrc) then
  498. goto _exit;
  499. end
  500. else
  501. pp:=pp^.next_valid;
  502. inc(i);
  503. if i>getmem_cnt-freemem_cnt then
  504. begin
  505. writeln(ptext^,'error in linked list of heap_mem_info');
  506. halt(1);
  507. end;
  508. end;
  509. i:=0;
  510. {$endif EXTRA}
  511. pp:=heap_mem_root;
  512. while pp<>nil do
  513. begin
  514. { inside this block ! }
  515. if (cardinal(p)>=cardinal(pp)+sizeof(theap_mem_info)+extra_info_size) and
  516. (cardinal(p)<=cardinal(pp)+sizeof(theap_mem_info)+extra_info_size+pp^.size) then
  517. { allocated block }
  518. if ((pp^.sig=$DEADBEEF) and not usecrc) or
  519. ((pp^.sig=calculate_sig(pp)) and usecrc) then
  520. goto _exit
  521. else
  522. begin
  523. writeln(ptext^,'pointer $',hexstr(longint(p),8),' points into invalid memory block');
  524. dump_error(pp,ptext^);
  525. runerror(204);
  526. end;
  527. pp:=pp^.previous;
  528. inc(i);
  529. if i>getmem_cnt then
  530. begin
  531. writeln(ptext^,'error in linked list of heap_mem_info');
  532. halt(1);
  533. end;
  534. end;
  535. writeln(ptext^,'pointer $',hexstr(longint(p),8),' does not point to valid memory block');
  536. runerror(204);
  537. _exit:
  538. asm
  539. popal
  540. end;
  541. end;
  542. {*****************************************************************************
  543. Dump Heap
  544. *****************************************************************************}
  545. procedure dumpheap;
  546. var
  547. pp : pheap_mem_info;
  548. i : longint;
  549. begin
  550. pp:=heap_mem_root;
  551. Writeln(ptext^,'Heap dump by heaptrc unit');
  552. Writeln(ptext^,getmem_cnt, ' memory blocks allocated : ',getmem_size,'/',getmem8_size);
  553. Writeln(ptext^,freemem_cnt,' memory blocks freed : ',freemem_size,'/',freemem8_size);
  554. Writeln(ptext^,getmem_cnt-freemem_cnt,' unfreed memory blocks : ',getmem_size-freemem_size);
  555. Writeln(ptext^,'True heap size : ',system.HeapSize);
  556. Writeln(ptext^,'True free heap : ',MemAvail);
  557. Writeln(ptext^,'Should be : ',system.HeapSize-(getmem8_size-freemem8_size)-
  558. (getmem_cnt-freemem_cnt)*(sizeof(theap_mem_info)+extra_info_size));
  559. i:=getmem_cnt-freemem_cnt;
  560. while pp<>nil do
  561. begin
  562. if i<0 then
  563. begin
  564. Writeln(ptext^,'Error in heap memory list');
  565. Writeln(ptext^,'More memory blocks than expected');
  566. exit;
  567. end;
  568. if ((pp^.sig=$DEADBEEF) and not usecrc) or
  569. ((pp^.sig=calculate_sig(pp)) and usecrc) then
  570. begin
  571. { this one was not released !! }
  572. if exitcode<>203 then
  573. call_stack(pp,ptext^);
  574. dec(i);
  575. end
  576. else if pp^.sig<>$AAAAAAAA then
  577. begin
  578. dump_error(pp,ptext^);
  579. {$ifdef EXTRA}
  580. dump_error(pp,error_file);
  581. {$endif EXTRA}
  582. error_in_heap:=true;
  583. end
  584. {$ifdef EXTRA}
  585. else if pp^.release_sig<>calculate_release_sig(pp) then
  586. begin
  587. dump_change_after(pp,ptext^);
  588. dump_change_after(pp,error_file);
  589. error_in_heap:=true;
  590. end
  591. {$endif EXTRA}
  592. ;
  593. pp:=pp^.previous;
  594. end;
  595. end;
  596. procedure markheap;
  597. var
  598. pp : pheap_mem_info;
  599. begin
  600. pp:=heap_mem_root;
  601. while pp<>nil do
  602. begin
  603. pp^.sig:=$AAAAAAAA;
  604. pp:=pp^.previous;
  605. end;
  606. end;
  607. {*****************************************************************************
  608. Install MemoryManager
  609. *****************************************************************************}
  610. const
  611. TraceManager:TMemoryManager=(
  612. Getmem : TraceGetMem;
  613. Freemem : TraceFreeMem
  614. );
  615. var
  616. SaveExit : pointer;
  617. procedure TraceExit;
  618. begin
  619. ExitProc:=SaveExit;
  620. { no dump if error
  621. because this gives long long listings }
  622. if (exitcode<>0) and (erroraddr<>nil) then
  623. begin
  624. Writeln(ptext^,'No heap dump by heaptrc unit');
  625. Writeln(ptext^,'Exitcode = ',exitcode);
  626. if ptext<>@stderr then
  627. begin
  628. ptext:=@stderr;
  629. close(ownfile);
  630. end;
  631. exit;
  632. end;
  633. if not error_in_heap then
  634. Dumpheap;
  635. if error_in_heap and (exitcode=0) then
  636. exitcode:=203;
  637. {$ifdef EXTRA}
  638. Close(error_file);
  639. {$endif EXTRA}
  640. if ptext<>@stderr then
  641. begin
  642. ptext:=@stderr;
  643. close(ownfile);
  644. end;
  645. end;
  646. Procedure SetHeapTraceOutput(const name : string);
  647. begin
  648. if ptext<>@stderr then
  649. begin
  650. ptext:=@stderr;
  651. close(ownfile);
  652. end;
  653. assign(ownfile,name);
  654. {$I-}
  655. append(ownfile);
  656. if IOResult<>0 then
  657. Rewrite(ownfile);
  658. {$I+}
  659. ptext:=@ownfile;
  660. end;
  661. procedure SetExtraInfo( size : longint;func : fillextrainfotype);
  662. begin
  663. if getmem_cnt>0 then
  664. begin
  665. writeln(ptext^,'Setting extra info is only possible at start !! ');
  666. dumpheap;
  667. end
  668. else
  669. begin
  670. { the total size must stay multiple of 8 !! }
  671. exact_info_size:=size;
  672. extra_info_size:=((size+7) div 8)*8;
  673. fill_extra_info:=func;
  674. end;
  675. end;
  676. begin
  677. MakeCRC32Tbl;
  678. SetMemoryManager(TraceManager);
  679. ptext:=@stderr;
  680. {$ifdef EXTRA}
  681. Assign(error_file,'heap.err');
  682. Rewrite(error_file);
  683. {$endif EXTRA}
  684. SaveExit:=ExitProc;
  685. ExitProc:=@TraceExit;
  686. Heap_at_init:=HeapPtr;
  687. end.
  688. {
  689. $Log$
  690. Revision 1.16 1999-05-23 00:07:17 pierre
  691. * support for heap allocated before TraceGetMem is used in
  692. FPC_CHECKPOINTER
  693. * faster CHECKPOINTER routine (list of valid blocks only !)
  694. Revision 1.15 1999/05/18 22:15:55 pierre
  695. * allow for .bss section below heaporg in go32v2 code
  696. Revision 1.14 1999/05/16 23:56:09 pierre
  697. * allow nil pointer in FPC_CHECKPOINTER !!
  698. Revision 1.13 1999/05/12 16:49:29 pierre
  699. + with EXTRA memory is filled with $F0 and checked at end
  700. Revision 1.12 1999/05/11 12:52:42 pierre
  701. + extra's with -dEXTRA, uses a CRC check for released memory
  702. Revision 1.11 1999/03/26 19:10:34 peter
  703. * show also allocation stack for a wrong size
  704. Revision 1.10 1999/02/16 17:20:26 pierre
  705. * no heap dump if program has an heap error !
  706. Revision 1.9 1999/01/22 12:39:22 pierre
  707. + added text arg for dump_stack
  708. Revision 1.8 1998/12/15 23:49:51 michael
  709. + Removed underscores in heaptrc unit
  710. Revision 1.7 1998/11/16 12:20:13 peter
  711. * write extra info also for wrong size
  712. Revision 1.6 1998/11/06 08:46:01 pierre
  713. * size is now also checked
  714. + added halt_on_error variable (default true)
  715. to stop at first error in getmem/freemem
  716. Revision 1.5 1998/10/09 11:59:31 pierre
  717. * changed default to keepreleased=false
  718. (allows to compile pp in one call without reaching the
  719. 64Mb limit of Windows 95 dos box)
  720. * corrected so typo errors
  721. Revision 1.4 1998/10/08 14:49:05 pierre
  722. + added possibility for more info
  723. Revision 1.3 1998/10/06 17:09:13 pierre
  724. + added trace of first dispose for errors
  725. Revision 1.2 1998/10/02 10:35:38 peter
  726. + quicktrace
  727. Revision 1.1 1998/10/01 14:54:20 peter
  728. + first version
  729. }