From c8c56f7fb8a64c2a2d31d956eec3371e01b26073 Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Wed, 1 May 2019 13:17:20 +0200 Subject: [PATCH] [PATCH #40] Fixed memory leaks under 3 different conditions when the deftype command is used. Added more argument validation. Enhanced error reporting. Implemented facility to free allocations associated with user-defined types --- src/frontend/typesdef.c | 284 ++++++++++++++++++++++++++++------------ 1 file changed, 201 insertions(+), 83 deletions(-) diff --git a/src/frontend/typesdef.c b/src/frontend/typesdef.c index 95ee5b453..13703b2df 100644 --- a/src/frontend/typesdef.c +++ b/src/frontend/typesdef.c @@ -15,12 +15,14 @@ Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group #include "typesdef.h" -#define NUMTYPES 128+4 /* If this is too little we can use a list. */ +#define NUMTYPES (128 + 4) /* If this is too little we can use a list. */ #define NUMPLOTTYPES 512 /* Since there may be more than 1 pat/type. */ struct type { char *t_name; char *t_abbrev; + bool f_name_is_alloc; /* Flag that name was allocated */ + bool f_abbrev_is_alloc; /* Flag that abbrev was allocated */ }; /* The stuff for plot names. */ @@ -28,61 +30,63 @@ struct type { struct plotab { char *p_name; char *p_pattern; + bool f_name_is_alloc; /* Flag that name was allocated */ + bool f_pattern_is_alloc; /* Flag that pattern was allocated */ }; /* note: This should correspond to SV_ defined in sim.h */ static struct type types[NUMTYPES] = { - { "notype", NULL } , - { "time", "s" } , - { "frequency", "Hz" } , - { "voltage", "V" } , - { "current", "A" } , - { "voltage-density", "V/sqrt(Hz)" } , - { "current-density", "A/sqrt(Hz)" } , - { "voltage^2-density", "(V^2)/Hz" } , - { "current^2-density", "(A^2)/Hz" } , - { "voltage^2", "(V^2)" } , - { "current^2", "(A^2)" } , - { "pole", NULL } , - { "zero", NULL } , - { "s-param", NULL } , - { "temp-sweep", "Celsius" } , /* Added by HT */ - { "res-sweep", "Ohms" } , /* Added by HT */ - { "impedance", "Ohms" } , /* Added by A.Roldan */ - { "admittance", "Mhos" } , /* Added by A.Roldan */ - { "power", "W" } , /* Added by A.Roldan */ - { "phase", "Degree" } , /* Added by A.Roldan */ - { "decibel", "dB" } , /* Added by A.Roldan */ - { "capacitance", "F" } , - { "charge", "C" } , - { "temperature", "Celsius" } , + { "notype", NULL, FALSE, FALSE }, + { "time", "s", FALSE, FALSE }, + { "frequency", "Hz", FALSE, FALSE }, + { "voltage", "V", FALSE, FALSE }, + { "current", "A", FALSE, FALSE }, + { "voltage-density", "V/sqrt(Hz)", FALSE, FALSE }, + { "current-density", "A/sqrt(Hz)", FALSE, FALSE }, + { "voltage^2-density", "(V^2)/Hz", FALSE, FALSE }, + { "current^2-density", "(A^2)/Hz", FALSE, FALSE }, + { "voltage^2", "(V^2)", FALSE, FALSE }, + { "current^2", "(A^2)", FALSE, FALSE }, + { "pole", NULL, FALSE, FALSE }, + { "zero", NULL, FALSE, FALSE }, + { "s-param", NULL, FALSE, FALSE }, + { "temp-sweep", "Celsius", FALSE, FALSE }, /* Added by HT */ + { "res-sweep", "Ohms", FALSE, FALSE }, /* Added by HT */ + { "impedance", "Ohms", FALSE, FALSE }, /* Added by A.Roldan */ + { "admittance", "Mhos", FALSE, FALSE }, /* Added by A.Roldan */ + { "power", "W", FALSE, FALSE }, /* Added by A.Roldan */ + { "phase", "Degree", FALSE, FALSE }, /* Added by A.Roldan */ + { "decibel", "dB", FALSE, FALSE }, /* Added by A.Roldan */ + { "capacitance", "F", FALSE, FALSE }, + { "charge", "C", FALSE, FALSE }, + { "temperature", "Celsius", FALSE, FALSE } }; /* The stuff for plot names. */ static struct plotab plotabs[NUMPLOTTYPES] = { - { "tran", "transient" } , - { "op", "op" } , - { "tf", "function" }, - { "dc", "d.c." } , - { "dc", "dc" } , - { "dc", "transfer" } , - { "ac", "a.c." } , - { "ac", "ac" } , - { "pz", "pz" } , - { "pz", "p.z." } , - { "pz", "pole-zero"} , - { "disto", "disto" } , - { "dist", "dist" } , - { "noise", "noise" } , - { "sens", "sens" } , - { "sens", "sensitivity" } , - { "sens2", "sens2" } , - { "sp", "s.p." } , - { "sp", "sp" } , - { "harm", "harm" }, - { "spect", "spect" }, - { "pss", "periodic" }, + { "tran", "transient", FALSE, FALSE }, + { "op", "op", FALSE, FALSE }, + { "tf", "function", FALSE, FALSE }, + { "dc", "d.c.", FALSE, FALSE }, + { "dc", "dc", FALSE, FALSE }, + { "dc", "transfer", FALSE, FALSE }, + { "ac", "a.c.", FALSE, FALSE }, + { "ac", "ac", FALSE, FALSE }, + { "pz", "pz", FALSE, FALSE }, + { "pz", "p.z.", FALSE, FALSE }, + { "pz", "pole-zero", FALSE}, + { "disto", "disto", FALSE, FALSE }, + { "dist", "dist", FALSE, FALSE }, + { "noise", "noise", FALSE, FALSE }, + { "sens", "sens", FALSE, FALSE }, + { "sens", "sensitivity", FALSE, FALSE }, + { "sens2", "sens2", FALSE, FALSE }, + { "sp", "s.p.", FALSE, FALSE }, + { "sp", "sp", FALSE, FALSE }, + { "harm", "harm", FALSE, FALSE }, + { "spect", "spect", FALSE, FALSE }, + { "pss", "periodic", FALSE, FALSE } }; @@ -92,59 +96,173 @@ static struct plotab plotabs[NUMPLOTTYPES] = { * parse things like abbrev(name) and to label axes with M, instead * of numbers. It may be ommitted. * Also, the command "deftype p plottype pattern ..." will assign plottype as - * the name to any plot with one of the patterns in its Name: field. + * the name to any plot with one of the patterns as its p_name field. + * + * Parameter + * wl: A linked list of strings of words providing arguments to the + * deftype command. + * + * Remarks + * The caller must ensure that there are 3 words in the linked + * list with the v subcommand or the function will cause access violations + * as it tries to access the required arguments. With the p subcommand, + * only 2 arguments are strictly required, but the function will not + * do anything useful unless at least 3 are provided. */ - void com_dftype(wordlist *wl) { - char *name, *abb; - int i; + /* Identify the subcommand and partially validate it */ + const char * const subcmd_word = wl->wl_word; + const char subcmd_char = *subcmd_word; + if (subcmd_char == '\0' || subcmd_word[1] != '\0') { + (void) fprintf(cp_err, "Error: invalid subcommand \"%s\".\n", + subcmd_word); + return; + } - switch (*wl->wl_word) { + switch (subcmd_char) { case 'v': - case 'V': + case 'V': { wl = wl->wl_next; - name = wl->wl_word; + const char * const name = wl->wl_word; /* type name */ wl = wl->wl_next; - abb = wl->wl_word; - for (i = 0; i < NUMTYPES && types[i].t_name; i++) - if (cieq(types[i].t_name, name)) - break; - if (i >= NUMTYPES) { - fprintf(cp_err, "Error: too many types defined\n"); + const char * const abb = wl->wl_word; /* abbreviation */ + + /* Test for invalid arguments */ + if ((wl = wl->wl_next) != (wordlist *) NULL) { + (void) fprintf(cp_err, "Error: extraneous argument%s supplied " + "with the v subcommand: \"%s\"", + wl->wl_next == (wordlist *) NULL ? "" : "s", + wl->wl_word); + wl = wl->wl_next; + for ( ; wl != (wordlist *) NULL; wl = wl->wl_next) { + (void) fprintf(cp_err, ", \"%s\"", wl->wl_word); + } + (void) fprintf(cp_err, "\n"); return; } - if (!types[i].t_name) - types[i].t_name = copy(name); - types[i].t_abbrev = copy(abb); - break; - case 'p': - case 'P': - wl = wl->wl_next; - name = copy(wl->wl_word); - wl = wl->wl_next; - for (; wl; wl = wl->wl_next) { - char *pattern = wl->wl_word; - for (i = 0; i < NUMPLOTTYPES && plotabs[i].p_pattern; i++) - if (cieq(plotabs[i].p_pattern, pattern)) - break; - if (i >= NUMPLOTTYPES) { - fprintf(cp_err, "Error: too many plot abs\n"); - return; + int i; + + /* Sequentially scan :( the defined types until the desired type + * name is found or all names have been checked. */ + for (i = 0; i < NUMTYPES && types[i].t_name; i++) + if (cieq(types[i].t_name, name)) + break; /* match found at index i */ + if (i == NUMTYPES) { /* array is full */ + fprintf(cp_err, "Error: too many types (%d) defined\n", + NUMTYPES); + return; + } + + { + struct type * const type_cur = types + i; + /* If reached the end of the list of defined types, + * define a new type */ + if (type_cur->t_name == (char *) NULL) { + type_cur->t_name = copy(name); + type_cur->f_name_is_alloc = TRUE; } - if (!plotabs[i].p_pattern) - plotabs[i].p_pattern = copy(pattern); - plotabs[i].p_name = name; + else { /* already exists, so may be abbrev to free */ + /* If the abbreviation has already been defined via an + * allocated buffer, free the allocation */ + if (type_cur->t_abbrev != (char *) NULL && + type_cur->f_abbrev_is_alloc) { + txfree((void *) type_cur->t_abbrev); + } + } + + /* Set the new abbreviation */ + type_cur->t_abbrev = copy(abb); + type_cur->f_abbrev_is_alloc = TRUE; } break; + } + case 'p': + case 'P': { + wl = wl->wl_next; + char * const name = copy(wl->wl_word); /* plot type name */ + bool f_name_used = FALSE; /* flag that name copy alloc is used */ - default: - fprintf(cp_err, "Error: missing 'p' or 'v' argument\n"); + /* For each pattern supplied in the command, locate it in the + * list of known patterns or add it if it does not exist and + * the list is not full. */ + for (wl = wl->wl_next; wl; wl = wl->wl_next) { + char *pattern = wl->wl_word; + int i; + for (i = 0; i < NUMPLOTTYPES && plotabs[i].p_pattern; i++) + if (cieq(plotabs[i].p_pattern, pattern)) + break; /* match found at index i */ + if (i == NUMPLOTTYPES) { /* array is full */ + if (!f_name_used) { + /* Free the name copy that was never used */ + txfree((void *) name); + } + fprintf(cp_err, "Error: too many plot abs (%d) defined.\n", + NUMPLOTTYPES); + return; + } + + { + struct plotab * const plotab_cur = plotabs + i; + /* If reached the end of the list of defined patterns, + * define a new one */ + if (plotab_cur->p_pattern == (char *) NULL) { + plotab_cur->p_pattern = copy(pattern); + plotab_cur->f_pattern_is_alloc = TRUE; + } + + /* Assign the name for the pattern. Freeing the old + * name, if present, is complicated by the fact that + * the same name allocation is used for all matching + * patterns. */ + else { + char * const p_name_old = plotab_cur->p_name; + if (p_name_old != (char *) NULL && + plotab_cur->f_name_is_alloc) { + /* Alloc exists. Must free if this is the only use. + * Find usage count to make this decision. */ + int j; + int n_use = 0; + for (j = 0; j < NUMPLOTTYPES; j++) { + const char * const p_name_cur = plotabs[j].p_name; + + /* Test for end of list */ + if (p_name_cur == (char *) NULL) { /* end */ + break; + } + + /* More entries, so check for the allocation of + * the old name */ + if (p_name_cur == p_name_old) { /* match */ + n_use++; + } + } /* end of loop over plot types */ + + /* Now can free if the usage count is exactly one, + * that use being the current one */ + if (n_use == 1) { + txfree((void *) p_name_old); + } + } /* end of case that there was an existing name here */ + } /* end of case that there was an old pattern */ + + /* Assign the (new) name */ + plotab_cur->p_name = name; + plotab_cur->f_name_is_alloc = TRUE; + } /* end of block for assigning pattern and abbrev */ + f_name_used = TRUE; /* flag that the allocated name was used */ + } /* end of loop over patterns */ break; } -} + default: + fprintf(cp_err, "Error: invalid subcommand '%c'. " + "Expecting 'p' or 'v'.\n", subcmd_char); + break; + } /* end of switch over subcommands */ +} /* end of function com_dftype */ + /* Return the abbreviation associated with a number. */