/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /*********************************************************************** ** ** Name: dbmalloc.c ** ** Description: Testing malloc (OBSOLETE) ** ** Modification History: ** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. ** The debug mode will print all of the printfs associated with this test. ** The regress mode will be the default mode. Since the regress tool limits ** the output to a one line status:PASS or FAIL,all of the printf statements ** have been handled with an if (debug_mode) statement. ***********************************************************************/ #include #include #include #include #include "nspr.h" void usage ( void ) { fprintf(stderr, "Usage: dbmalloc ('-m'|'-s') '-f' num_fails ('-d'|'-n') filename [...]\n"); exit(0); } typedef struct node_struct { struct node_struct *next, *prev; int line; char value[4]; } node_t, *node_pt; node_pt get_node(const char *line) { node_pt rv; int l = strlen(line); rv = (node_pt)PR_MALLOC(sizeof(node_t) + l + 1 - 4); if( (node_pt)0 == rv ) { return (node_pt)0; } memcpy(&rv->value[0], line, l+1); rv->next = rv->prev = (node_pt)0; return rv; } void dump ( const char *name, node_pt node, int mf, int debug ) { if( (node_pt)0 != node->prev ) { dump(name, node->prev, mf, debug); } if( 0 != debug ) { printf("[%s]: %6d: %s", name, node->line, node->value); } if( node->line == mf ) { fprintf(stderr, "[%s]: Line %d was allocated!\n", name, node->line); } if( (node_pt)0 != node->next ) { dump(name, node->next, mf, debug); } return; } void release ( node_pt node ) { if( (node_pt)0 != node->prev ) { release(node->prev); } if( (node_pt)0 != node->next ) { release(node->next); } PR_DELETE(node); } int t2 ( const char *name, int mf, int debug ) { int rv; FILE *fp; int l = 0; node_pt head = (node_pt)0; char buffer[ BUFSIZ ]; fp = fopen(name, "r"); if( (FILE *)0 == fp ) { fprintf(stderr, "[%s]: Cannot open \"%s.\"\n", name, name); return -1; } /* fgets mallocs a buffer, first time through. */ if( (char *)0 == fgets(buffer, BUFSIZ, fp) ) { fprintf(stderr, "[%s]: \"%s\" is empty.\n", name, name); (void)fclose(fp); return -1; } rewind(fp); if( PR_SUCCESS != PR_ClearMallocCount() ) { fprintf(stderr, "[%s]: Cannot clear malloc count.\n", name); (void)fclose(fp); return -1; } if( PR_SUCCESS != PR_SetMallocCountdown(mf) ) { fprintf(stderr, "[%s]: Cannot set malloc countdown to %d\n", name, mf); (void)fclose(fp); return -1; } while( fgets(buffer, BUFSIZ, fp) ) { node_pt n; node_pt *w = &head; if( (strlen(buffer) == (BUFSIZ-1)) && (buffer[BUFSIZ-2] != '\n') ) { buffer[BUFSIZ-2] == '\n'; } l++; n = get_node(buffer); if( (node_pt)0 == n ) { printf("[%s]: Line %d: malloc failure!\n", name, l); continue; } n->line = l; while( 1 ) { int comp; if( (node_pt)0 == *w ) { *w = n; break; } comp = strcmp((*w)->value, n->value); if( comp < 0 ) { w = &(*w)->next; } else { w = &(*w)->prev; } } } (void)fclose(fp); dump(name, head, mf, debug); rv = PR_GetMallocCount(); PR_ClearMallocCountdown(); release(head); return rv; } int nf = 0; int debug = 0; void test ( const char *name ) { int n, i; extern int nf, debug; printf("[%s]: starting test 0\n", name); n = t2(name, 0, debug); if( -1 == n ) { return; } printf("[%s]: test 0 had %ld allocations.\n", name, n); if( 0 >= n ) { return; } for( i = 0; i < nf; i++ ) { int which = rand() % n; if( 0 == which ) { printf("[%s]: starting test %d -- no allocation should fail\n", name, i+1); } else { printf("[%s]: starting test %d -- allocation %d should fail\n", name, i+1, which); } (void)t2(name, which, debug); printf("[%s]: test %d done.\n", name, i+1); } return; } int main(int argc, char **argv) { int okay = 0; int multithread = 0; struct threadlist { struct threadlist *next; PRThread *thread; } *threadhead = (struct threadlist *)0; extern int nf, debug; srand(time(0)); PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); PR_STDIO_INIT(); printf("[main]: We %s using the debugging malloc.\n", PR_IsDebuggingMalloc() ? "ARE" : "ARE NOT"); while( argv++, --argc ) { if( '-' == argv[0][0] ) { switch( argv[0][1] ) { case 'f': nf = atoi(argv[0][2] ? &argv[0][2] : --argc ? *++argv : "0"); break; case 'd': debug = 1; break; case 'n': debug = 0; break; case 'm': multithread = 1; break; case 's': multithread = 0; break; default: usage(); break; } } else { FILE *fp = fopen(*argv, "r"); if( (FILE *)0 == fp ) { fprintf(stderr, "Cannot open \"%s.\"\n", *argv); continue; } okay++; (void)fclose(fp); if( multithread ) { struct threadlist *n; n = (struct threadlist *)malloc(sizeof(struct threadlist)); if( (struct threadlist *)0 == n ) { fprintf(stderr, "This is getting tedious. \"%s\"\n", *argv); continue; } n->next = threadhead; n->thread = PR_CreateThread(PR_USER_THREAD, (void (*)(void *))test, *argv, PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); if( (PRThread *)0 == n->thread ) { fprintf(stderr, "Can't create thread for \"%s.\"\n", *argv); continue; } else { threadhead = n; } } else { test(*argv); } } } if( okay == 0 ) { usage(); } else while( (struct threadlist *)0 != threadhead ) { struct threadlist *x = threadhead->next; (void)PR_JoinThread(threadhead->thread); PR_DELETE(threadhead); threadhead = x; } return 0; }