From: Bruno Haible Date: Fri, 21 Mar 2025 18:44:33 +0000 (+0100) Subject: Work around an strtoul() misfeature. X-Git-Tag: v0.25~81 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b8ab4f2bef0ff18cf1ae749c1c81a359a40d0450;p=thirdparty%2Fgettext.git Work around an strtoul() misfeature. * gettext-runtime/src/ngettext.c: Include . (main): When parsing a nonnegative number, disallow leading whitespace and sign. * gettext-tools/tests/tstngettext.c: Include . (worker_thread): When parsing a nonnegative number, disallow leading whitespace and sign. * gnulib-local/lib/markup.c (unescape_string_inplace): When parsing a numeric character entity, disallow leading whitespace and sign, and report a too large number as "non-permitted character" rather than "Numerical result out of range". * gettext-tools/src/msgfmt.c (main): When parsing the '-a' argument, disallow leading whitespace and sign and check whether the value is a power of 2. * gettext-tools/src/read-stringtable.c: Include c-ctype.h. (comment_line_end): When parsing a line number, disallow leading whitespace and sign. --- diff --git a/gettext-runtime/src/ngettext.c b/gettext-runtime/src/ngettext.c index d1316b7d1..baad695d6 100644 --- a/gettext-runtime/src/ngettext.c +++ b/gettext-runtime/src/ngettext.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -168,9 +169,10 @@ There is NO WARRANTY, to the extent permitted by law.\n\ char *endp; unsigned long tmp_val; - errno = 0; - tmp_val = strtoul (count, &endp, 10); - if (errno == 0 && count[0] != '\0' && endp[0] == '\0') + if (isdigit ((unsigned char) count[0]) + && (errno = 0, + tmp_val = strtoul (count, &endp, 10), + errno == 0 && endp[0] == '\0')) n = tmp_val; else /* When COUNT is not valid, use plural. */ diff --git a/gettext-tools/src/msgfmt.c b/gettext-tools/src/msgfmt.c index 89b3d644a..39008c793 100644 --- a/gettext-tools/src/msgfmt.c +++ b/gettext-tools/src/msgfmt.c @@ -282,13 +282,16 @@ main (int argc, char *argv[]) case '\0': /* Long option. */ break; case 'a': - { - char *endp; - size_t new_align = strtoul (optarg, &endp, 0); + if (isdigit ((unsigned char) optarg[0])) + { + char *endp; + size_t new_align = strtoul (optarg, &endp, 0); - if (endp != optarg) - alignment = new_align; - } + if (endp != optarg) + /* Check whether new_align is a power of 2. */ + if (new_align > 0 && (new_align & (new_align - 1)) == 0) + alignment = new_align; + } break; case 'c': check_domain = true; diff --git a/gettext-tools/src/read-stringtable.c b/gettext-tools/src/read-stringtable.c index 602cd3c53..a22afd9d6 100644 --- a/gettext-tools/src/read-stringtable.c +++ b/gettext-tools/src/read-stringtable.c @@ -1,5 +1,5 @@ /* Reading NeXTstep/GNUstep .strings files. - Copyright (C) 2003-2024 Free Software Foundation, Inc. + Copyright (C) 2003-2025 Free Software Foundation, Inc. Written by Bruno Haible , 2003. This program is free software: you can redistribute it and/or modify @@ -37,6 +37,7 @@ #include "xstrerror.h" #include "xerror-handler.h" #include "unistr.h" +#include "c-ctype.h" #include "gettext.h" #define _(str) gettext (str) @@ -557,7 +558,7 @@ comment_line_end (abstract_catalog_reader_ty *catr, if (strlen (line) >= 6 && memcmp (line, "File: ", 6) == 0 && (last_colon = strrchr (line + 6, ':')) != NULL - && *(last_colon + 1) != '\0' + && c_isdigit (*(last_colon + 1)) && (number = strtoul (last_colon + 1, &endp, 10), *endp == '\0')) { /* A "File: :" type comment. */ diff --git a/gettext-tools/tests/tstngettext.c b/gettext-tools/tests/tstngettext.c index c2d0304a5..34c3d04d8 100644 --- a/gettext-tools/tests/tstngettext.c +++ b/gettext-tools/tests/tstngettext.c @@ -1,5 +1,5 @@ /* ngettext - retrieve plural form strings from message catalog and print them. - Copyright (C) 1995-2024 Free Software Foundation, Inc. + Copyright (C) 1995-2025 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -211,9 +212,10 @@ worker_thread (void *arg) char *endp; unsigned long tmp_val; - errno = 0; - tmp_val = strtoul (count, &endp, 10); - if (errno == 0 && count[0] != '\0' && endp[0] == '\0') + if (isdigit ((unsigned char) count[0]) + && (errno = 0, + tmp_val = strtoul (count, &endp, 10), + errno == 0 && endp[0] == '\0')) n = tmp_val; else /* When COUNT is not valid, use plural. */ diff --git a/gnulib-local/lib/markup.c b/gnulib-local/lib/markup.c index f608c2996..a3a961461 100644 --- a/gnulib-local/lib/markup.c +++ b/gnulib-local/lib/markup.c @@ -512,16 +512,14 @@ unescape_string_inplace (markup_parse_context_ty *context, from++; } - errno = 0; - l = strtoul (from, &end, base); - - if (end == from || errno != 0) + if (!(base == 16 ? c_isxdigit (*from) : c_isdigit (*from)) + || (errno = 0, + l = strtoul (from, &end, base), + end == from)) { char *error_text = xasprintf (_("invalid character reference: %s"), - errno != 0 - ? xstrerror (NULL, errno) - : _("not a valid number specification")); + _("not a valid number specification")); emit_error (context, error_text); free (error_text); return false; @@ -535,30 +533,28 @@ unescape_string_inplace (markup_parse_context_ty *context, free (error_text); return false; } + else if (errno == 0 + /* characters XML 1.1 permits */ + && ((0 < l && l <= 0xD7FF) + || (0xE000 <= l && l <= 0xFFFD) || (0x10000 <= l && l <= 0x10FFFF))) + { + char buf[8]; + int length; + length = u8_uctomb ((uint8_t *) buf, l, 8); + memcpy (to, buf, length); + to += length - 1; + from = end; + if (l >= 0x80) /* not ASCII */ + mask |= 0x80; + } else { - /* characters XML 1.1 permits */ - if ((0 < l && l <= 0xD7FF) - || (0xE000 <= l && l <= 0xFFFD) || (0x10000 <= l && l <= 0x10FFFF)) - { - char buf[8]; - int length; - length = u8_uctomb ((uint8_t *) buf, l, 8); - memcpy (to, buf, length); - to += length - 1; - from = end; - if (l >= 0x80) /* not ascii */ - mask |= 0x80; - } - else - { - char *error_text = - xasprintf (_("invalid character reference: %s"), - _("non-permitted character")); - emit_error (context, error_text); - free (error_text); - return false; - } + char *error_text = + xasprintf (_("invalid character reference: %s"), + _("non-permitted character")); + emit_error (context, error_text); + free (error_text); + return false; } }