/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /*********************************************************************** ** ** 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; }