/* Copyright (c) 1995,1996-1998 Nick Ing-Simmons. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. */ /* modified by dougm for use with 5.004_04 future versions may be made special for the mod_perl environment */ #include #include #include #include "patchlevel.h" #if ((PATCHLEVEL == 4) && (SUBVERSION <= 76)) #define PL_sv_arenaroot sv_arenaroot #endif typedef long used_proc _((void *, SV *, long)); typedef struct hash_s *hash_ptr; #define MAX_HASH 1009 static hash_ptr pile = NULL; static void LangDumpVec(char *who, int count, SV **data) { int i; PerlIO_printf(PerlIO_stderr(), "%s (%d):\n", who, count); for (i = 0; i < count; i++) { SV *sv = data[i]; if (sv) { PerlIO_printf(PerlIO_stderr(), "%2d ", i); sv_dump(sv); } } } struct hash_s { struct hash_s *link; SV *sv; char *tag; }; static char *lookup(hash_ptr *ht, SV *sv, void *tag) { unsigned hash = ((unsigned long) sv) % MAX_HASH; hash_ptr p = ht[hash]; while (p) { if (p->sv == sv) { char *old = p->tag; p->tag = (char *) tag; return old; } p = p->link; } if ((p = pile)) pile = p->link; else p = (hash_ptr) malloc(sizeof(struct hash_s)); p->link = ht[hash]; p->sv = sv; p->tag = (char *)tag; ht[hash] = p; return NULL; } static void check_arenas() { SV *sva; for (sva = PL_sv_arenaroot; sva; sva = (SV *) SvANY(sva)) { SV *sv = sva + 1; SV *svend = &sva[SvREFCNT(sva)]; while (sv < svend) { if (SvROK(sv) && ((IV) SvANY(sv)) & 1) { warn("Odd SvANY for %p @ %p[%d]",sv,sva,(sv-sva)); abort(); } ++sv; } } } static long int sv_apply_to_used(void *p, used_proc *proc, long int n) { SV *sva; for (sva = PL_sv_arenaroot; sva; sva = (SV *) SvANY(sva)) { SV *sv = sva + 1; SV *svend = &sva[SvREFCNT(sva)]; while (sv < svend) { if (SvTYPE(sv) != SVTYPEMASK) { n = (*proc) (p, sv, n); } ++sv; } } return n; } static char * t_old = "old"; static char * t_new = "new"; static long note_sv(void *p, SV *sv, long int n) { lookup((struct hash_s **)p, sv, t_old); return n+1; } static long note_used(hash_ptr **x) { hash_ptr *ht; Newz(603, ht, MAX_HASH, hash_ptr); *x = ht; return sv_apply_to_used(ht, note_sv, 0); } static long check_sv(void *p, SV *sv, long hwm) { char *state = lookup((struct hash_s **)p, sv, t_new); if (state != t_old) { PerlIO_printf(PerlIO_stderr(), "%s %p : ", state ? state : t_new, sv); sv_dump(sv); } return hwm+1; } static long check_used(hash_ptr **x) { hash_ptr *ht = *x; long count = sv_apply_to_used(ht, check_sv, 0); long i; for (i = 0; i < MAX_HASH; i++) { hash_ptr p = ht[i]; while (p) { hash_ptr t = p; p = t->link; if (t->tag != t_new) { LangDumpVec(t->tag ? t->tag : "NUL", 1, &t->sv); } t->link = pile; pile = t; } } free(ht); *x = NULL; return count; } MODULE = Apache::Leak PACKAGE = Apache::Leak PROTOTYPES: Enable IV NoteSV(obj) hash_ptr * obj = NO_INIT CODE: RETVAL = note_used(&obj); OUTPUT: obj RETVAL IV CheckSV(obj) hash_ptr * obj CODE: RETVAL = check_used(&obj); OUTPUT: RETVAL void check_arenas()