From 95793c3150b8dedd7169f4fa9faa61856d64f013 Mon Sep 17 00:00:00 2001 From: Landon Curt Noll Date: Sun, 17 Aug 2025 02:18:10 -0700 Subject: [PATCH] checkpoint on string realloc bug fix attempt In preparation to fix issue #47, we: Fix a minor typo in `Makefile.config`. Move `stringindex(char *format, char *test)` from `str.c` into `codegen.c` as static function. Expand `STR_TABLECHUNK` from `1<<10` to `1<<16`. Identify with an XXX comment, a problematic `realloc()` call in the `addstr(STRINGHEAD *hp, char *str)` function of `str.c`. Move the `charstr(int ch)` in `str.c` above the only function that uses it, `addliteral(char *str)`, and make it a static function. Improved comments about return values for `str.c` functions that work on STRINGHEAD pointers. --- Makefile.config | 2 +- codegen.c | 36 +++++++++++++++++- str.c | 98 ++++++++++++++++++++----------------------------- str.h | 4 +- 4 files changed, 77 insertions(+), 63 deletions(-) diff --git a/Makefile.config b/Makefile.config index 7b05eae..a541d9d 100644 --- a/Makefile.config +++ b/Makefile.config @@ -1358,7 +1358,7 @@ COMMON_LDFLAGS= ${EXTRA_LDFLAGS} # For more info see: https://github.com/google/sanitizers/wiki/AddressSanitizer # See also: https://developer.apple.com/documentation/xcode/diagnosing-memory-thread-and-crash-issues-early # -# The following Address Sanitizer (ASAN) are common to both REHL9.2 (Linux) and macOS 14.0. +# The following Address Sanitizer (ASAN) are common to both RHEL9.2 (Linux) and macOS 14.0. # # By default, the Address Sanitizer is NOT enabled, not compiled into calc. # To enable the Address Sanitizer, uncomment the appropriate lines in Makefile.local !!! diff --git a/codegen.c b/codegen.c index 3a442c6..694e66f 100644 --- a/codegen.c +++ b/codegen.c @@ -1,7 +1,7 @@ /* * codegen - module to generate opcodes from the input tokens * - * Copyright (C) 1999-2007,2017,2021-2023 David I. Bell and Ernest Bowen + * Copyright (C) 1999-2007,2017,2021-2023,2025 David I. Bell and Ernest Bowen * * Primary author: David I. Bell * @@ -2425,6 +2425,40 @@ getfilename(char *name, size_t namelen, bool *once) } +/* + * Useful routine to return the index of one string within another one + * which has the format: "str1\000str2\000str3\000...strn\0\0". Index starts + * at one for the first string. Returns zero if the string being checked + * is not contained in the formatted string. + * + * Be sure to use \000 instead of \0. ANSI-C compilers interpret "foo\0foo..." + * as "foo\017oo...". + * + * given: + * format string formatted into substrings + * test string to be found in formatted string + */ +S_FUNC long +stringindex(char *format, char *test) +{ + long index; /* found index */ + size_t len; /* length of current piece of string */ + size_t testlen; /* length of test string */ + + testlen = strlen(test); + index = 1; + while (*format) { + len = strlen(format); + if ((len == testlen) && (*format == *test) && + (strcmp(format, test) == 0)) + return index; + format += (len + 1); + index++; + } + return 0; +} + + /* * Read the show command to display useful information */ diff --git a/str.c b/str.c index 394eb29..fcdf017 100644 --- a/str.c +++ b/str.c @@ -1,7 +1,7 @@ /* * str - string list routines * - * Copyright (C) 1999-2007,2021-2023 David I. Bell and Ernest Bowen + * Copyright (C) 1999-2007,2021-2023,2025 David I. Bell and Ernest Bowen * * Primary author: David I. Bell * @@ -42,7 +42,7 @@ #include "banned.h" /* include after system header <> includes */ -#define STR_TABLECHUNK (1<<10) /* how often to reallocate string table */ +#define STR_TABLECHUNK (1<<16) /* how often to reallocate string literal table */ #define STR_CHUNK (1<<16) /* size of string storage allocation */ #define OCTET_VALUES 256 /* number of different values in a OCTET */ #define STR_UNIQUE (1<<7) /* size of string to allocate separately */ @@ -97,6 +97,10 @@ initstr(STRINGHEAD *hp) * given: * hp header of string storage * str string to be added + * + * returns: + * != NULL ==> pointer to newly added string + * NULL ==> unable to add string */ char * addstr(STRINGHEAD *hp, char *str) @@ -113,6 +117,10 @@ addstr(STRINGHEAD *hp, char *str) /* alloc + 1 guard paranoia */ newsize = len + STR_CHUNK + hp->h_used + hp->h_avail + 1; /* alloc + 1 guard paranoia */ + /* + * XXX - doing a realloc can cause problems if the larger list has to be + * relocated due the recalloc() call and stuff point to old location + */ list = (char *)realloc(hp->h_list, newsize + 1); if (list == NULL) return NULL; @@ -130,35 +138,6 @@ addstr(STRINGHEAD *hp, char *str) } -/* - * Return a null-terminated string which consists of a single character. - * The table is initialized on the first call. - */ -char * -charstr(int ch) -{ - char *cp; - int i; - - if (chartable == NULL) { - /* alloc + 1 guard paranoia */ - cp = (char *)malloc((OCTET_VALUES + 1)*2); - if (cp == NULL) { - math_error("Cannot allocate character table"); - not_reached(); - } - for (i = 0; i < OCTET_VALUES; i++) { - *cp++ = (char)i; - *cp++ = '\0'; - } - chartable = cp - (OCTET_VALUES*2); - *cp++ = '\0'; /* guard paranoia */ - *cp++ = '\0'; /* guard paranoia */ - } - return &chartable[(ch & 0xff) * 2]; -} - - /* * Find a string with the specified name and return its number in the * string list. The first string is numbered zero. Minus one is returned @@ -166,7 +145,11 @@ charstr(int ch) * * given: * hp header of string storage - * str string to be added + * str string to be searched for + * + * returns: + * >= 0 ==> index of string + * -1 ==> unable to find string */ int findstr(STRINGHEAD *hp, char *str) @@ -200,6 +183,10 @@ findstr(STRINGHEAD *hp, char *str) * given: * hp header of string storage * n string index + * + * returns: + * non-empty string ==> string at index n + * "" ==> no strings or string at index n */ char * namestr(STRINGHEAD *hp, long n) @@ -219,36 +206,31 @@ namestr(STRINGHEAD *hp, long n) /* - * Useful routine to return the index of one string within another one - * which has the format: "str1\000str2\000str3\000...strn\0\0". Index starts - * at one for the first string. Returns zero if the string being checked - * is not contained in the formatted string. - * - * Be sure to use \000 instead of \0. ANSI-C compilers interpret "foo\0foo..." - * as "foo\017oo...". - * - * given: - * format string formatted into substrings - * test string to be found in formatted string + * Return a null-terminated string which consists of a single character. + * The table is initialized on the first call. */ -long -stringindex(char *format, char *test) +S_FUNC char * +charstr(int ch) { - long index; /* found index */ - size_t len; /* length of current piece of string */ - size_t testlen; /* length of test string */ + char *cp; + int i; - testlen = strlen(test); - index = 1; - while (*format) { - len = strlen(format); - if ((len == testlen) && (*format == *test) && - (strcmp(format, test) == 0)) - return index; - format += (len + 1); - index++; + if (chartable == NULL) { + /* alloc + 1 guard paranoia */ + cp = (char *)malloc((OCTET_VALUES + 1)*2); + if (cp == NULL) { + math_error("Cannot allocate character table"); + not_reached(); + } + for (i = 0; i < OCTET_VALUES; i++) { + *cp++ = (char)i; + *cp++ = '\0'; + } + chartable = cp - (OCTET_VALUES*2); + *cp++ = '\0'; /* guard paranoia */ + *cp++ = '\0'; /* guard paranoia */ } - return 0; + return &chartable[(ch & 0xff) * 2]; } diff --git a/str.h b/str.h index 35e75fa..45f1fd1 100644 --- a/str.h +++ b/str.h @@ -1,7 +1,7 @@ /* * str - string list routines * - * Copyright (C) 1999-2007,2014 David I. Bell + * Copyright (C) 1999-2007,2014,2025 David I. Bell * * Calc is open software; you can redistribute it and/or modify it under * the terms of the version 2.1 of the GNU Lesser General Public License @@ -59,9 +59,7 @@ E_FUNC void initstr(STRINGHEAD *hp); E_FUNC char *addstr(STRINGHEAD *hp, char *str); E_FUNC char *namestr(STRINGHEAD *hp, long n); E_FUNC int findstr(STRINGHEAD *hp, char *str); -E_FUNC char *charstr(int ch); E_FUNC char *addliteral(char *str); -E_FUNC long stringindex(char *str1, char *str2); E_FUNC STRING *stralloc(void); E_FUNC long addstring(char *str, size_t len); E_FUNC STRING *charstring(int ch);