]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Work around an strtoul() misfeature.
authorBruno Haible <bruno@clisp.org>
Fri, 21 Mar 2025 18:44:33 +0000 (19:44 +0100)
committerBruno Haible <bruno@clisp.org>
Fri, 21 Mar 2025 18:44:33 +0000 (19:44 +0100)
* gettext-runtime/src/ngettext.c: Include <ctype.h>.
(main): When parsing a nonnegative number, disallow leading whitespace and sign.
* gettext-tools/tests/tstngettext.c: Include <ctype.h>.
(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.

gettext-runtime/src/ngettext.c
gettext-tools/src/msgfmt.c
gettext-tools/src/read-stringtable.c
gettext-tools/tests/tstngettext.c
gnulib-local/lib/markup.c

index d1316b7d19a0f57a3f820c5010c22e27822e8507..baad695d6435ee8842b08774ef9d93eea009df74 100644 (file)
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <locale.h>
+#include <ctype.h>
 #include <errno.h>
 
 #include <error.h>
@@ -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.  */
index 89b3d644a9f1f6b175e1041aa7f3a17d27bf72dd..39008c793bf35c74fb180cd15755b52739ceab01 100644 (file)
@@ -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;
index 602cd3c53c60d7ee29cd837ff9a50b59b149b7f5..a22afd9d6535b79559cba99f326d7fe32b45bad2 100644 (file)
@@ -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 <bruno@clisp.org>, 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: <filename>:<number>" type comment.  */
index c2d0304a54f68218d80b1280fbf691abd162309c..34c3d04d858716508e4d64d381d0d18d922b3dea 100644 (file)
@@ -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 <stdlib.h>
 #include <string.h>
 #include <locale.h>
+#include <ctype.h>
 #include <errno.h>
 
 #include <error.h>
@@ -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.  */
index f608c299687663ad9872cbcd629db52e1c8363e2..a3a96146189dfec488957746fec78bba465d49ec 100644 (file)
@@ -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;
                 }
             }