pkgsrc-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
pkg/60680: devel/autogen: out-of-bounds write in getdefs, and six other defects
>Number: 60680
>Category: pkg
>Synopsis: devel/autogen: out-of-bounds write in getdefs, and six other defects
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: pkg-manager
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Sep 03 14:50:00 +0000 2026
>Originator: Showta Ishizaki
>Release: pkgsrc-current, devel/autogen Makefile 1.68
>Organization:
>Environment:
System: NetBSD techne.fml.org 11.0 NetBSD 11.0 (GENERIC) #0: Thu Jul 30 15:23:12 UTC 2026 mkrepro%mkrepro.NetBSD.org@localhost:/usr/src/sys/arch/amd64/compile/GENERIC amd64
Architecture: x86_64
Machine: amd64
>Description:
devel/autogen is at 5.18.16, released in August 2018, and upstream has
made no release since. Seven defects in it are either fixed only in git
master, or not fixed anywhere. Four of them are reachable from a
definitions file, which is ordinary input for this program; one is a
CVE; one stops the package's own test suite from linking at all.
getdefs writes past the end of a stack buffer. buildPreamble() copies
a definition name into def_bf and name_bf one character at a time with
no bound, and both buffers are MAXNAMELEN, 256 bytes. A "/*=" block
with a longer name walks off the end. def_bf is additionally too small
for what is later written into it, since the index entry appends the
entry name at a point already advanced past the entry type. Fixed in
git master by 6da941a9, which is a 363-line restructuring that also moves
main() and depends on helpers that do not exist in this release, so the
same fix is written here against the released source. Reported upstream
as Savannah sr #111449.
CVE-2025-8746: save.c calls text_mmap() and starts scanning without
looking at whether the mapping failed. Reported upstream with a patch
as Savannah sr #111319 on 2025-09-23; the maintainer took the item on
2025-10-02 and nothing has happened since. The patch here is that
attachment verbatim, so it drops out cleanly if upstream ever commits it.
compat/pathfind.c passes overlapping regions to strcpy() in three places
in canonicalize_pathname(). strcpy()'s arguments are restrict-qualified,
so this is undefined behaviour; it happens to work with a forward-copying
implementation, and gcc 9 and newer report it as -Wrestrict. Upstream
removed all three in ea80371a, which lifts the walk over the path out of
canonicalize_pathname() into a new strip_up_dirs() and uses memmove().
ea80371a alone does not compile: it leaves a forward declaration reading
"char * path" against a definition reading "char const * path", and
13257631 drops that declaration a year later. git master does not
compile either, because 3a99682d leaves the file one closing brace
short. So all three commits are applied together, through fd0131b9's
file tag; the result is byte-identical to upstream's file at v5.19.98,
the newest point at which it compiles.
autoopts/usage.c builds a format string from an option name length that
nothing bounds, so a definitions file with an option name of about ten
thousand characters truncates the format and produces malformed usage
output. snprintf() is used, so this truncates rather than overruns.
Upstream added the AO_NAME_LIMIT test in 58504a36; that is what is taken
here.
The remaining two are documentation generation. cmd-doc.tlib looks for
a converter named "mdoc2mdoc", which is generated but never installed,
whenever a definitions file asks for mdoc output. Upstream fixed the
ds-format path in 45199acd and 127e11da; those are backported. The two
option-format paths in the same file have the same defect and upstream
has not fixed them, so their fix is written the same way, and is reported
upstream as Savannah sr #111450. The ds-format case is what net/ntp4
hits: it declares ds-format = 'mdoc' in eleven definitions files and
cannot regenerate its manual pages against an installed AutoGen.
Nothing in pkgsrc appears to use option-format = 'mdoc' today, so that
half is a latent defect rather than an observed failure.
>How-To-Repeat:
A definition name longer than MAXNAMELEN aborts getdefs.
$ name=`awk 'BEGIN{for(i=0;i<300;i++)printf "a"}'`
$ printf '/*=gfunc %s\n * some text\n=*/\n' "$name" > t.c
$ getdefs input=t.c output=t.def
error no data for definition in file t.c line 1
Abort trap
$ echo $?
134
The diagnostic is printed either way; without the patch the process then
dies on return from buildPreamble(), where the stack protector catches
the smashed frame. With the patches applied the same input exits 0 and
prints that one line, and an ordinary definition still produces correct
output.
Measured both ways on two platforms, in each case from an installed
package rather than a build tree: NetBSD 11.0/amd64 with gcc 12.5 and
NetBSD 10.1/i386 with gcc 10.5. Without these patches getdefs exits
134 on both; with them it exits 0 on both, still produces correct output
for an ordinary definition, and autogen still runs a template.
>Fix:
Built, installed and tested on NetBSD 11.0/amd64 with gcc 12.5, and the
getdefs behaviour above checked again on NetBSD 10.1/i386.
"make test TEST_TARGET=check" returns 0: autoopts/test passes 24 of 24
and the second suite 43 of 43. Without the defs.in patch the same tree
fails 20 of those 24 on the link, which is what devel/autogen does
today. The installed getdefs takes the input above without aborting,
exits 0, and still produces correct output for an ordinary definition;
autogen itself still runs a template.
The patches were also checked against a pristine 5.18.16 tree with
patch -C -p0, and the diff below was applied to a copy of the current
devel/autogen with patch -C -p0; the result is byte-identical to the
tree I built.
Apply with patch -p0 from devel/.
--- autogen/Makefile 2026-01-07 08:46:26.000000000 +0000
+++ autogen/Makefile 2026-09-02 23:34:29.833725484 +0000
@@ -1,7 +1,7 @@
# $NetBSD: Makefile,v 1.68 2026/01/07 08:46:26 wiz Exp $
DISTNAME= autogen-5.18.16
-PKGREVISION= 17
+PKGREVISION= 18
CATEGORIES= devel
MASTER_SITES= ${MASTER_SITE_GNU:=autogen/rel${PKGVERSION_NOREV}/}
EXTRACT_SUFX= .tar.xz
--- autogen/distinfo 2021-10-26 10:14:18.000000000 +0000
+++ autogen/distinfo 2026-09-03 13:18:18.867982071 +0000
@@ -7,6 +7,13 @@
SHA1 (patch-agen5_Makefile.in) = 154fe94b21d5189fa94cffbf5e2543cf90a97cc2
SHA1 (patch-agen5_fmemopen.c) = 1cc126824f6a07fb9be080f8d143a6f2353bea78
SHA1 (patch-autoopts_mk-tpl-config.sh) = 9c5b1012efeed5db73a4cade08d6a53f410adae2
+SHA1 (patch-autoopts_save.c) = a67dca53d0690df598726bb303b651d3a478d2fc
+SHA1 (patch-autoopts_test_defs.in) = a460d2dd69ca1b4bd5645712638522168e9b7780
+SHA1 (patch-autoopts_tpl_cmd-doc.tlib) = a4e975df5d43b2c947501367f65d2ccc3fd5a314
+SHA1 (patch-autoopts_tpl_cmd-doc.tlib-option-format) = 2f54ebea0400688f67288649134cea7c41a42b58
+SHA1 (patch-autoopts_usage.c) = e53e8e4a7cf87b6f20e4941f4becc56e01b235cb
SHA1 (patch-columns_Makefile.in) = a1da38b3a0a24ac300a4a7baea968642e449efd2
+SHA1 (patch-compat_pathfind.c) = 6305a89c0170b0e9a9aff1e1fa925fee8164bfe1
SHA1 (patch-config_config.rpath) = 791aa6bbe52c681b5461205c2341ce015d638ecf
SHA1 (patch-getdefs_Makefile.in) = c16060d8d69d7c04c9a35ed94af705a39060f8ba
+SHA1 (patch-getdefs_getdefs.c) = b3f692c67ab50f35a891cda48717c06e951a6fb3
--- autogen/patches/patch-autoopts_save.c 1970-01-01 00:00:00.000000000 +0000
+++ autogen/patches/patch-autoopts_save.c 2026-09-03 13:18:18.144494868 +0000
@@ -0,0 +1,19 @@
+$NetBSD$
+
+Check whether text_mmap() failed before scanning what it returned.
+
+CVE-2025-8746. Taken verbatim from the patch on Savannah sr #111319,
+which upstream has not committed.
+
+--- autoopts/save.c.orig 2017-09-11 00:00:00.000000000 +0000
++++ autoopts/save.c
+@@ -492,6 +492,9 @@
+ size_t const name_len = strlen(opts->pzProgName);
+ tmap_info_t map_info;
+ char * text = text_mmap(fname, PROT_READ|PROT_WRITE, MAP_PRIVATE, &map_info);
++ if (TEXT_MMAP_FAILED_ADDR(text))
++ return;
++
+ char * scan = text;
+
+ for (;;) {
--- autogen/patches/patch-autoopts_test_defs.in 1970-01-01 00:00:00.000000000 +0000
+++ autogen/patches/patch-autoopts_test_defs.in 2026-09-03 13:18:18.200293021 +0000
@@ -0,0 +1,18 @@
+$NetBSD$
+
+Give the test programs the libraries configure found.
+
+They link with the compiler, not libtool, so gettext goes unresolved.
+Reported upstream as Savannah sr #111451.
+
+--- autoopts/test/defs.in.orig
++++ autoopts/test/defs.in
+@@ -153,7 +153,7 @@
+ done
+ ;;
+ esac
+- LIB="${lo_lib} ${LIB}"
++ LIB="${lo_lib} ${LIB} @LIBS@"
+
+ AG_L=run_ag\ ao
+ agl_opts="-L${top_builddir}/autoopts/tpl"
--- autogen/patches/patch-autoopts_tpl_cmd-doc.tlib 1970-01-01 00:00:00.000000000 +0000
+++ autogen/patches/patch-autoopts_tpl_cmd-doc.tlib 2026-09-03 13:18:18.255638602 +0000
@@ -0,0 +1,27 @@
+$NetBSD$
+
+Do not look for a converter when the documentation is already mdoc.
+
+Upstream 45199acd and 127e11da, neither of which has been released.
+
+--- autoopts/tpl/cmd-doc.tlib.orig 2017-09-11 00:00:00.000000000 +0000
++++ autoopts/tpl/cmd-doc.tlib
+@@ -228,12 +228,14 @@ DEFINE doc-sections :+
+ FOR doc-section :+][+:
+ IF
+ (define sec-type (string-upcase (get "ds-type")))
++ (define sec-fmt (string-downcase! (get "ds-format" "man")))
+ (define sec-name (name-to-fname sec-type))
+- (define cvt-fn (find-file (string-append
+- (get "ds-format" "man") "2mdoc")))
++ (define cvt-fn "")
++ (if (not (= sec-fmt "mdoc"))
++ (set! cvt-fn (find-file (string-append sec-fmt "2mdoc")))
++ (set! cvt-fn (shell "command -v cat")) )
+ (if (not (defined? 'cvt-fn))
+- (error (sprintf "Cannot locate converter for %s"
+- (get "ds-format" "man"))))
++ (error (sprintf "Cannot locate %s to mdoc converter" sec-fmt)))
+
+ (define sec-file (string-append tmp-dir "/SEC/" sec-name))
+ (access? sec-file R_OK) :+][+:
--- autogen/patches/patch-autoopts_tpl_cmd-doc.tlib-option-format 1970-01-01 00:00:00.000000000 +0000
+++ autogen/patches/patch-autoopts_tpl_cmd-doc.tlib-option-format 2026-09-03 13:18:18.309789619 +0000
@@ -0,0 +1,30 @@
+$NetBSD$
+
+Apply the same fix to the option-format paths.
+
+Still unfixed upstream. Reported as Savannah sr #111450.
+
+--- autoopts/tpl/cmd-doc.tlib.orig 2017-09-11 00:00:00.000000000 +0000
++++ autoopts/tpl/cmd-doc.tlib
+@@ -151,7 +151,9 @@
+ (define target-form (if man-page "man" "mdoc"))
+ (define source-form (get "option-format" "texi"))
+ (define converter (string-append source-form "2" target-form ))
+- (set! tmp-str (find-file converter))
++ (if (= source-form target-form)
++ (set! tmp-str (shell "command -v cat"))
++ (set! tmp-str (find-file converter)) )
+
+ (if (not (defined? 'tmp-str))
+ (error (string-append "cannot locate " converter)))
+@@ -586,7 +588,9 @@
+
+ (if formatted-doc
+ (shell (string-append
+- "fn='" (find-file cvt-cmd)
++ "fn='" (if (= (get "option-format") "mdoc")
++ (shell "command -v cat")
++ (find-file cvt-cmd))
+ "'\ntest -f ${fn} || die '" cvt-cmd " not found'\n"
+ "${fn} <<\\_EndOfMdoc_ || die ${fn} failed in $PWD\n"
+ (out-pop #t)
--- autogen/patches/patch-autoopts_usage.c 1970-01-01 00:00:00.000000000 +0000
+++ autogen/patches/patch-autoopts_usage.c 2026-09-03 13:18:18.365526032 +0000
@@ -0,0 +1,18 @@
+$NetBSD$
+
+Bound the option name length used to build the vendor option format.
+
+Upstream 58504a36, which has not appeared in a release.
+
+--- autoopts/usage.c.orig 2018-08-25 00:00:00.000000000 +0000
++++ autoopts/usage.c
+@@ -732,7 +732,8 @@
+ continue;
+
+ l = strlen(od->pz_Name);
+- if (l > nmlen) nmlen = l;
++ if ((l <= AO_NAME_LIMIT) && (l > nmlen))
++ nmlen = l;
+ } while (od++, (--ct > 0));
+
+ snprintf(vfmt, sizeof(vfmt), vfmtfmt, (unsigned int)nmlen + 4);
--- autogen/patches/patch-compat_pathfind.c 1970-01-01 00:00:00.000000000 +0000
+++ autogen/patches/patch-compat_pathfind.c 2026-09-03 13:18:18.421847995 +0000
@@ -0,0 +1,370 @@
+$NetBSD$
+
+Do not copy overlapping regions with strcpy().
+
+Upstream's own file taken whole at v5.19.98; master does not compile.
+
+--- compat/pathfind.c.orig
++++ compat/pathfind.c
+@@ -1,11 +1,21 @@
+-/* -*- Mode: C -*- */
+
+-/* pathfind.c --- find a FILE MODE along PATH */
++/**
++ * @file pathfind.c
++ * --- find a FILE MODE along PATH
++ */
+
+ /* Author: Gary V Vaughan <gvaughan%oranda.demon.co.uk@localhost> */
+
+ /* Code: */
+
++#ifndef DIRCH
++# if defined(_WIN32) && !defined(__CYGWIN__)
++# define DIRCH '\\'
++# else
++# define DIRCH '/'
++# endif
++#endif
++
+ static char *
+ pathfind( char const * path,
+ char const * fname,
+@@ -24,9 +34,200 @@
+ #else
+
+ static char * make_absolute(char const * string, char const * dot_path);
+-static char * canonicalize_pathname(char * path);
+ static char * extract_colon_unit(char * dir, char const * string, int * p_index);
+
++/*
++ * Multiple `/'s are collapsed to a single `/'.
++ * Leading `./'s are removed.
++ */
++static char const *
++trim_path_leader( char const * path )
++{
++ for (;;) {
++ switch (*path) {
++ case NUL:
++ return NULL;
++
++ case '.':
++ if (path[1] != DIRCH)
++ return path;
++ path += 2;
++ continue;
++
++ case DIRCH:
++ while (path[1] == DIRCH)
++ path++;
++ return path;
++ }
++ }
++}
++
++/**
++ * Remove directory characters at the end of a path.
++ *
++ * @param path the full path
++ * @param cur_size the number of characters in @path we're examining
++ * @return the remaining size
++ */
++static size_t
++strip_trailing_slashes( char const * path, size_t cur_size )
++{
++ while ((cur_size > 0) && (path[cur_size - 1] == DIRCH))
++ cur_size--; // skip any remaining dir separators
++ return cur_size;
++}
++
++/**
++ * Trailing `/.'s are removed.
++ * Trailing `xxx/..'s are removed.
++ * Trailing `/'s are removed.
++ */
++static size_t
++real_path_length( char const * path )
++{
++ size_t res = strlen(path);
++
++ for (;;) {
++ char const * end;
++ res = strip_trailing_slashes(path, res);
++ if (res == 0)
++ return res;
++ end = path + res;
++ // end[-1] cannot be DIRCH
++
++ if (end[-1] != '.')
++ return res;
++ if (res == 1)
++ return 1; // path is '.' by itself
++
++ if (end[-2] == DIRCH) {
++ // path ends with "/." strip and continue
++ //
++ res -= 2;
++ continue;
++ }
++ if (res == 2)
++ // path is not "/." but may be "..". We don't care.
++ //
++ return 2;
++
++ // path is 3 or more characters. Check for "/.."
++ //
++ if (end[-2] != '.')
++ return res;
++ // path ends with ".."
++
++ if (end[-3] != DIRCH)
++ return res;
++
++ // Strip the trailing "/..", the resulting trailing DIRCH-es
++ // and then the last directory name
++ //
++ res = strip_trailing_slashes(path, res - 3);
++ if (res == 0)
++ return 1; // "////.." is "/"
++
++ for (;;) {
++ if (path[res - 1] == DIRCH)
++ break; // found '/' before 'y' in "x///yyy///.."
++
++ if (--res == 0)
++ return res; // "xxx/.." is empty
++ }
++ }
++}
++
++static void
++strip_up_dirs(char * path)
++{
++ static char const up_dir[] = "/../";
++ static size_t const skip_up_dir_sz = sizeof(up_dir) - 1;
++
++ char * scn;
++ restart:
++ scn = path;
++
++ for (;;) {
++ char * upone = scn = strstr(scn, up_dir);
++
++ if (scn == NULL)
++ return;
++
++ upone += skip_up_dir_sz;
++
++ /*
++ * scan backward for DIR character or start of path.
++ * IF start of path, then everything after "/../" is
++ * the canonical path. Otherwise, remove the directory
++ * name, "/" and the two dots.
++ */
++ for (;;) {
++ if (scn <= path) {
++ memmove(path, upone, strlen(upone) + 1);
++ goto restart;
++ }
++ if (*(--scn) == DIRCH)
++ break;
++ }
++ /*
++ * We found a "/", so remove the directory name
++ */
++ memmove(++scn, upone, strlen(upone) + 1);
++ }
++}
++
++/*
++ * Canonicalize PATH, and return a new path. The new path differs from
++ * PATH in that:
++ *
++ * Multiple `/'s are collapsed to a single `/'.
++ * Leading `./'s are removed.
++ * Trailing `/.'s are removed.
++ * Trailing `/..'s are removed.
++ * Trailing `/'s are removed.
++ * Non-leading `../'s and trailing `..'s are handled by removing
++ * portions of the path.
++ */
++static char *
++canonicalize_pathname(char const * path)
++{
++ size_t psz;
++ char * scn;
++ char * res;
++
++ path = trim_path_leader(path);
++ if (path == NULL)
++ goto leave_empty_handed;
++
++ psz = real_path_length(path);
++ if (psz == 0)
++ goto leave_empty_handed;
++
++ res = scn = malloc(psz + 1);
++ memcpy(res, path, psz);
++ res[psz] = '\0';
++
++ /*
++ * Strip no-op dirs
++ */
++ for (;;) {
++ char * noop = strstr(scn, "/./");
++ if (noop == NULL)
++ break;
++ memmove(noop, noop + 2, strlen(noop + 1));
++ scn = noop;
++ }
++
++ strip_up_dirs(res);
++ return res;
++
++ leave_empty_handed:
++ res = malloc(2);
++ res[0] = (*path == DIRCH) ? DIRCH : '.';
++ res[1] = NUL;
++ return res;
++}
++
+ /**
+ * local implementation of pathfind.
+ * @param[in] path colon separated list of directories
+@@ -81,12 +282,11 @@
+ /*
+ * Make sure we can access it in the way we want
+ */
+- if (access(abs_name, mode_bits) >= 0) {
++ if (access(abs_name, mode_bits) >= 0)
+ /*
+ * We can, so normalize the name and return it below
+ */
+ res_path = canonicalize_pathname(abs_name);
+- }
+
+ free(abs_name);
+ break;
+@@ -113,20 +313,20 @@
+ char * result;
+ int result_len;
+
+- if (!dot_path || *string == '/') {
++ if (!dot_path || *string == DIRCH) {
+ result = strdup( string );
+ } else {
+ if (dot_path && dot_path[0]) {
+ result = malloc( 2 + strlen( dot_path ) + strlen( string ) );
+ strcpy( result, dot_path );
+ result_len = (int)strlen(result);
+- if (result[result_len - 1] != '/') {
+- result[result_len++] = '/';
++ if (result[result_len - 1] != DIRCH) {
++ result[result_len++] = DIRCH;
+ result[result_len] = '\0';
+ }
+ } else {
+ result = malloc( 3 + strlen( string ) );
+- result[0] = '.'; result[1] = '/'; result[2] = '\0';
++ result[0] = '.'; result[1] = DIRCH; result[2] = '\0';
+ result_len = 2;
+ }
+
+@@ -137,96 +337,6 @@
+ }
+
+ /*
+- * Canonicalize PATH, and return a new path. The new path differs from
+- * PATH in that:
+- *
+- * Multiple `/'s are collapsed to a single `/'.
+- * Leading `./'s are removed.
+- * Trailing `/.'s are removed.
+- * Trailing `/'s are removed.
+- * Non-leading `../'s and trailing `..'s are handled by removing
+- * portions of the path.
+- */
+-static char *
+-canonicalize_pathname( char *path )
+-{
+- int i, start;
+- char stub_char, *result;
+-
+- /* The result cannot be larger than the input PATH. */
+- result = strdup( path );
+-
+- stub_char = (*path == '/') ? '/' : '.';
+-
+- /* Walk along RESULT looking for things to compact. */
+- i = 0;
+- while (result[i]) {
+- while (result[i] != '\0' && result[i] != '/')
+- i++;
+-
+- start = i++;
+-
+- /* If we didn't find any slashes, then there is nothing left to
+- * do.
+- */
+- if (!result[start])
+- break;
+-
+- /* Handle multiple `/'s in a row. */
+- while (result[i] == '/')
+- i++;
+-
+-#if !defined (apollo)
+- if ((start + 1) != i)
+-#else
+- if ((start + 1) != i && (start != 0 || i != 2))
+-#endif /* apollo */
+- {
+- strcpy( result + start + 1, result + i );
+- i = start + 1;
+- }
+-
+- /* Handle backquoted `/'. */
+- if (start > 0 && result[start - 1] == '\\')
+- continue;
+-
+- /* Check for trailing `/', and `.' by itself. */
+- if ((start && !result[i])
+- || (result[i] == '.' && !result[i+1])) {
+- result[--i] = '\0';
+- break;
+- }
+-
+- /* Check for `../', `./' or trailing `.' by itself. */
+- if (result[i] == '.') {
+- /* Handle `./'. */
+- if (result[i + 1] == '/') {
+- strcpy( result + i, result + i + 1 );
+- i = (start < 0) ? 0 : start;
+- continue;
+- }
+-
+- /* Handle `../' or trailing `..' by itself. */
+- if (result[i + 1] == '.' &&
+- (result[i + 2] == '/' || !result[i + 2])) {
+- while (--start > -1 && result[start] != '/')
+- ;
+- strcpy( result + start + 1, result + i + 2 );
+- i = (start < 0) ? 0 : start;
+- continue;
+- }
+- }
+- }
+-
+- if (!*result) {
+- *result = stub_char;
+- result[1] = '\0';
+- }
+-
+- return result;
+-}
+-
+-/*
+ * Given a string containing units of information separated by colons,
+ * return the next one pointed to by (P_INDEX), or NULL if there are no
+ * more. Advance (P_INDEX) to the character after the colon.
--- autogen/patches/patch-getdefs_getdefs.c 1970-01-01 00:00:00.000000000 +0000
+++ autogen/patches/patch-getdefs_getdefs.c 2026-09-03 13:18:18.477450592 +0000
@@ -0,0 +1,67 @@
+$NetBSD$
+
+Bound the two name copies in buildPreamble().
+
+A long definition name walks off a stack buffer. Upstream 6da941a9 is a
+363-line restructuring that cannot be taken here. Savannah sr #111449.
+
+--- getdefs/getdefs.c.orig 2018-08-27 02:41:23.000000000 +0000
++++ getdefs/getdefs.c
+@@ -374,7 +374,7 @@
+ char * pzDef = *ppzDef;
+ char * pzOut = *ppzOut;
+
+- char def_bf[ MAXNAMELEN ];
++ char def_bf[ MAXNAMELEN * 2 + sizeof(long) ];
+ char name_bf[ MAXNAMELEN ];
+ char * def_str = def_bf;
+ char * pzIfText = NULL;
+@@ -383,9 +383,22 @@
+ * Copy out the name of the entry type
+ */
+ *def_str++ = '`';
+- while (isalnum(*pzDef) || (*pzDef == '_') || (*pzDef == '.')
+- || (*pzDef == '[') || (*pzDef == ']'))
+- *def_str++ = *pzDef++;
++ {
++ char const * scan = pzDef;
++ size_t len;
++
++ while (isalnum(*pzDef) || (*pzDef == '_') || (*pzDef == '.')
++ || (*pzDef == '[') || (*pzDef == ']'))
++ pzDef++;
++
++ len = (size_t)(pzDef - scan);
++ if (len >= MAXNAMELEN) {
++ fprintf(stderr, zNoData, fname, line);
++ return FAILURE;
++ }
++ memcpy(def_str, scan, len);
++ def_str += len;
++ }
+
+ *def_str = NUL;
+
+@@ -395,10 +408,19 @@
+ * Copy out the name for this entry of the above entry type.
+ */
+ {
+- char * name_str = name_bf;
++ char const * scan = pzDef;
++ size_t len;
++
+ while (isalnum(*pzDef) || (*pzDef == '_'))
+- *name_str++ = *pzDef++;
+- *name_str = NUL;
++ pzDef++;
++
++ len = (size_t)(pzDef - scan);
++ if (len >= MAXNAMELEN) {
++ fprintf(stderr, zNoData, fname, line);
++ return FAILURE;
++ }
++ memcpy(name_bf, scan, len);
++ name_bf[len] = NUL;
+ }
+
+ if ( (def_bf[1] == NUL)
Home |
Main Index |
Thread Index |
Old Index