/* -*- 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; }