From: Chet Ramey Date: Fri, 15 Mar 2024 16:55:39 +0000 (-0400) Subject: add more overflow handling for printf builtin; start incorporating C23 stdckdint... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=167a9248f94b51bae59730772bfe6cc6e3b0f4a2;p=thirdparty%2Fbash.git add more overflow handling for printf builtin; start incorporating C23 stdckdint ; rework PRIdMAX replacements --- diff --git a/.gitignore b/.gitignore index 2c10177c..15b219d3 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,7 @@ support/bashbug.sh lsignames.h pathnames.h signames.h +stdckdint.h version.h syntax.c stamp-h diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 8424184a..7ba8ea53 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -8807,3 +8807,47 @@ jobs.c received the signal, too) as notified, since we don't report on it in the JDEAD case if the signal is trapped + 3/13 + ---- +builtins/printf.def + - PF: print an error message if printf returns an error or leaves + ferror(stdout) true + From a report by Paul Eggert + + 3/14 + ---- +builtins/printf.def + - getint: now takes an int argument and returns it if the conversion + overflows an int; changed callers in printf_builtin + - getint: consolidate checks for overflow. This changes the behavior + if the argument overflows an intmax_t: it returns a field width of + 0 (the overflow result) instead of -1, which changes how printf + behaves. This is consistent with the behavior when the argument + overflows an int + - printf_builtin: change check for overflow of [LONG_MIN..LONG_MAX] + for %d/%i to be explicit instead of relying on integer overflow of p + - printstr,printwidestr: print message if field width or precision + overflow, since we don't call printf + - printstr,printwidestr: set field width and precision on integer + overflow the way we do in printf_builtin + From a report by Paul Eggert + +bashtypes.h + - PRIdMAX: move redefinition here after including inttypes.h + +builtins/printf.def,examples/loadables/seq.c,examples/loadables/getconf.h + - remove PRIdMAX redefinitions, since it's now fixed in bashtypes.h + From a report by Paul Eggert + + 3/15 + ---- +include/stdckdint.in.h,include/intprops-internal.h + - new files, from gnulib + +configure.ac + - stdckdint.h: create in the build directory if the system doesn't + provide one by copying ${srcdir}/include/stdckdint.in.h; make + sure we don't create a new one every time, changing the timestamp + +Makefile.in + - CREATED_HEADERS: add stdckdint.h diff --git a/MANIFEST b/MANIFEST index 5efab261..b9aff039 100644 --- a/MANIFEST +++ b/MANIFEST @@ -219,6 +219,7 @@ include/ansi_stdlib.h f include/chartypes.h f include/filecntl.h f include/gettext.h f +include/intprops-internal.h f include/maxpath.h f include/memalloc.h f include/ocache.h f @@ -233,6 +234,7 @@ include/shmbutil.h f include/shtty.h f include/stat-time.h f include/stdc.h f +include/stdckdint.in.h f include/systimes.h f include/timer.h f include/typemax.h f diff --git a/Makefile.in b/Makefile.in index 41443c6d..7499e897 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# Makefile for bash-5.3, version 5.3 +# Makefile for bash-5.3, version 5.4 # # Copyright (C) 1996-2024 Free Software Foundation, Inc. @@ -593,7 +593,7 @@ CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \ examples/loadables/perl/Makefile support/Makefile \ lib/intl/Makefile po/Makefile po/Makefile.in CREATED_HEADERS = signames.h config.h pathnames.h version.h y.tab.h \ - ${DEFDIR}/builtext.h + ${DEFDIR}/builtext.h stdckdint.h OTHER_DOCS = $(srcdir)/CHANGES $(srcdir)/COMPAT $(srcdir)/NEWS $(srcdir)/POSIX \ $(srcdir)/RBASH $(srcdir)/README diff --git a/aclocal.m4 b/aclocal.m4 index 37066ce6..ac42dbf6 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -3,7 +3,7 @@ dnl Bash specific tests dnl dnl Some derived from PDKSH 5.1.3 autoconf tests dnl -dnl Copyright (C) 1987-2023 Free Software Foundation, Inc. +dnl Copyright (C) 1987-2024 Free Software Foundation, Inc. dnl dnl diff --git a/bashhist.c b/bashhist.c index 98e5cabc..fb9935f5 100644 --- a/bashhist.c +++ b/bashhist.c @@ -1,6 +1,6 @@ /* bashhist.c -- bash interface to the GNU history library. */ -/* Copyright (C) 1993-2023 Free Software Foundation, Inc. +/* Copyright (C) 1993-2024 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. diff --git a/bashtypes.h b/bashtypes.h index 01afef4b..9d666d4f 100644 --- a/bashtypes.h +++ b/bashtypes.h @@ -1,6 +1,6 @@ /* bashtypes.h -- Bash system types. */ -/* Copyright (C) 1993-2009 Free Software Foundation, Inc. +/* Copyright (C) 1993-2009,2024 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -35,6 +35,18 @@ # include #endif +/* Fix PRIdMAX on systems where it's broken. */ +#ifdef PRI_MACROS_BROKEN +# undef PRIdMAX +#endif +#ifndef PRIdMAX +# if HAVE_LONG_LONG +# define PRIdMAX "lld" +# else +# define PRIdMAX "ld" +# endif +#endif + #if HAVE_STDINT_H # include #endif diff --git a/builtins/printf.def b/builtins/printf.def index 49757f5c..d4306873 100644 --- a/builtins/printf.def +++ b/builtins/printf.def @@ -89,18 +89,6 @@ $END #include "bashgetopt.h" #include "common.h" -#if defined (PRI_MACROS_BROKEN) -# undef PRIdMAX -#endif - -#if !defined (PRIdMAX) -# if HAVE_LONG_LONG -# define PRIdMAX "lld" -# else -# define PRIdMAX "ld" -# endif -#endif - #if !defined (errno) extern int errno; #endif @@ -154,7 +142,7 @@ extern int errno; char b[2]; \ tw++; \ b[0] = c; b[1] = '\0'; \ - if (vflag) \ + if (vflag) \ vbadd (b, 1); \ else \ putchar (c); \ @@ -178,8 +166,7 @@ extern int errno; if (nw < 0 || (vflag == 0 && ferror (stdout))) \ { \ QUIT; \ - if (vflag) \ - builtin_error ("%s", strerror (errno)); \ + builtin_error ("%s", strerror (errno)); \ PRETURN (EXECUTION_FAILURE); \ } \ tw += nw; \ @@ -203,7 +190,8 @@ extern int asprintf (char **, const char *, ...) __attribute__((__format__ (prin extern int vsnprintf (char *, size_t, const char *, va_list) __attribute__((__format__ (printf, 3, 0))); #endif -static void printf_erange (char *); +static inline void printf_erange (char *); +static inline void report_erange (char *, char *); static int printstr (char *, char *, int, int, int); static int tescape (char *, char *, int *, int *); static char *bexpand (char *, int, int *, int *); @@ -212,7 +200,7 @@ static int vbprintf (const char *, ...) __attribute__((__format__ (printf, 1, 2) static char *mklong (char *, char *, size_t); static int getchr (void); static char *getstr (void); -static int getint (void); +static int getint (int); static intmax_t getintmax (void); static uintmax_t getuintmax (void); @@ -260,11 +248,21 @@ static inline int decodeprec (char *ps) { intmax_t mpr; + int pr; + char *s; + s = ps; /* error checking */ mpr = *ps++ - '0'; while (DIGIT (*ps)) mpr = (mpr * 10) + (*ps++ - '0'); - return (mpr < 0 || mpr > INT_MAX) ? INT_MAX : mpr; + if (mpr < 0 || mpr > INT_MAX) + { +#if 0 + report_erange (s, ps); +#endif + return -1; + } + return (pr = mpr); } int @@ -419,10 +417,9 @@ printf_builtin (WORD_LIST *list) { fmt++; have_fieldwidth = 1; - fieldwidth = getint (); - /* Handle field with overflow by ignoring it. */ - if (fieldwidth == INT_MAX || fieldwidth == INT_MIN) - fieldwidth = 0; + /* Handle field with overflow by ignoring fieldwidth for now. + getint() prints a message. */ + fieldwidth = getint (0); } else while (DIGIT (*fmt)) @@ -436,11 +433,10 @@ printf_builtin (WORD_LIST *list) { fmt++; have_precision = 1; - precision = getint (); - /* Handle precision overflow by ignoring it. "A negative - precision is treated as if it were missing." */ - if (precision == INT_MAX || precision == INT_MIN) - precision = -1; + /* Handle precision overflow by ignoring precision for now. + getint() prints a message. + "A negative precision is treated as if it were missing." */ + precision = getint (-1); } else { @@ -712,8 +708,8 @@ printf_builtin (WORD_LIST *list) long p; intmax_t pp; - p = pp = getintmax (); - if (p != pp) + pp = getintmax (); + if (pp < LONG_MIN || pp > LONG_MAX) { f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2); PF (f, pp); @@ -724,6 +720,7 @@ printf_builtin (WORD_LIST *list) in "long". This also works around some long long and/or intmax_t library bugs in the common case, e.g. glibc 2.2 x86. */ + p = pp; f = mklong (start, "l", 1); PF (f, p); } @@ -811,13 +808,24 @@ printf_builtin (WORD_LIST *list) PRETURN (retval); } -static void +static inline void printf_erange (char *s) { builtin_error (_("%s: %s"), s, strerror(ERANGE)); conversion_error = 1; } +static inline void +report_erange (char *s, char *e) +{ + unsigned char sc; + + sc = *e; + *e = 0; + printf_erange (s); + *e = sc; +} + /* We duplicate a lot of what printf(3) does here. */ /* FMT: format STRING: expanded string argument @@ -830,9 +838,7 @@ printf_erange (char *s) static int printstr (char *fmt, char *string, int len, int fieldwidth, int precision) { -#if 0 char *s; -#endif int padlen, nc, ljust, i; int fw, pr; /* fieldwidth and precision */ intmax_t mfw, mpr; @@ -872,11 +878,18 @@ printstr (char *fmt, char *string, int len, int fieldwidth, int precision) } else if (DIGIT (*fmt)) { + s = fmt; mfw = *fmt++ - '0'; while (DIGIT (*fmt)) mfw = (mfw * 10) + (*fmt++ - '0'); - /* Error if fieldwidth > INT_MAX here? */ - fw = (mfw < 0 || mfw > INT_MAX) ? INT_MAX : mfw; + /* Error if fieldwidth > INT_MAX here */ + if (mfw < 0 || mfw > INT_MAX) + { + report_erange (s, fmt); + fw = 0; + } + else + fw = mfw; } /* get precision, if present. doesn't handle negative precisions */ @@ -890,11 +903,18 @@ printstr (char *fmt, char *string, int len, int fieldwidth, int precision) } else if (DIGIT (*fmt)) { + s = fmt; mpr = *fmt++ - '0'; while (DIGIT (*fmt)) mpr = (mpr * 10) + (*fmt++ - '0'); - /* Error if precision > INT_MAX here? */ - pr = (mpr < 0 || mpr > INT_MAX) ? INT_MAX : mpr; + /* Error if precision > INT_MAX here */ + if (mpr < 0 || mpr > INT_MAX) + { + report_erange (s, fmt); + pr = -1; + } + else + pr = mpr; if (pr < precision && precision < INT_MAX) pr = precision; /* XXX */ } @@ -940,9 +960,7 @@ printstr (char *fmt, char *string, int len, int fieldwidth, int precision) static int printwidestr (char *fmt, wchar_t *wstring, size_t len, int fieldwidth, int precision) { -#if 0 char *s; -#endif char *string; int padlen, nc, ljust, i; int fw, pr; /* fieldwidth and precision */ @@ -986,8 +1004,14 @@ printwidestr (char *fmt, wchar_t *wstring, size_t len, int fieldwidth, int preci mfw = *fmt++ - '0'; while (DIGIT (*fmt)) mfw = (mfw * 10) + (*fmt++ - '0'); - /* Error if fieldwidth > INT_MAX here? */ - fw = (mfw < 0 || mfw > INT_MAX) ? INT_MAX : mfw; + /* Error if fieldwidth > INT_MAX here */ + if (mfw < 0 || mfw > INT_MAX) + { + report_erange (s, fmt); + fw = 0; + } + else + fw = mfw; } /* get precision, if present. doesn't handle negative precisions */ @@ -1004,8 +1028,14 @@ printwidestr (char *fmt, wchar_t *wstring, size_t len, int fieldwidth, int preci mpr = *fmt++ - '0'; while (DIGIT (*fmt)) mpr = (mpr * 10) + (*fmt++ - '0'); - /* Error if precision > INT_MAX here? */ - pr = (mpr < 0 || mpr > INT_MAX) ? INT_MAX : mpr; + /* Error if precision > INT_MAX here */ + if (mpr < 0 || mpr > INT_MAX) + { + report_erange (s, fmt); + pr = -1; + } + else + pr = mpr; if (pr < precision && precision < INT_MAX) pr = precision; /* XXX */ } @@ -1358,10 +1388,11 @@ getstr (void) /* Don't call getintmax here because it may consume an argument on error, and we call this to get field width/precision arguments. */ static int -getint (void) +getint (int overflow_retval) { intmax_t ret; char *ep; + int overflow; if (garglist == 0) return (0); @@ -1371,27 +1402,18 @@ getint (void) errno = 0; ret = strtoimax (garglist->word->word, &ep, 0); + overflow = (errno == ERANGE) || (ret < INT_MIN || ret > INT_MAX); if (*ep) { sh_invalidnum (garglist->word->word); conversion_error = 1; } - else if (errno == ERANGE) + else if (overflow) printf_erange (garglist->word->word); - else if (ret > INT_MAX) - { - printf_erange (garglist->word->word); - ret = INT_MAX; - } - else if (ret < INT_MIN) - { - printf_erange (garglist->word->word); - ret = INT_MIN; - } garglist = garglist->next; - return ((int)ret); + return (overflow ? overflow_retval : (int)ret); } static intmax_t diff --git a/config-top.h b/config-top.h index eaf9337b..29b36993 100644 --- a/config-top.h +++ b/config-top.h @@ -1,6 +1,6 @@ /* config-top.h - various user-settable options not under the control of autoconf. */ -/* Copyright (C) 2002-2021 Free Software Foundation, Inc. +/* Copyright (C) 2002-2024 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. diff --git a/configure b/configure index 20811bdb..26df275d 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.ac for Bash 5.3, version 5.061. +# From configure.ac for Bash 5.3, version 5.062. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for bash 5.3-devel. # @@ -14533,6 +14533,12 @@ if test "x$ac_cv_header_strings_h" = xyes then : printf "%s\n" "#define HAVE_STRINGS_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "stdckdint.h" "ac_cv_header_stdckdint_h" "$ac_includes_default" +if test "x$ac_cv_header_stdckdint_h" = xyes +then : + printf "%s\n" "#define HAVE_STDCKDINT_H 1" >>confdefs.h + fi ac_fn_c_check_header_compile "$LINENO" "regex.h" "ac_cv_header_regex_h" "$ac_includes_default" if test "x$ac_cv_header_regex_h" = xyes @@ -22381,6 +22387,14 @@ ac_config_files="$ac_config_files Makefile builtins/Makefile lib/readline/Makefi ac_config_commands="$ac_config_commands stamp-h" +if test "$ac_cv_header_stdckdint_h" = yes; then + rm -f stdckdint.h +elif cmp ${srcdir}/include/stdckdint.in.h stdckdint.h 2>/dev/null; then + : +else + cp ${srcdir}/include/stdckdint.in.h stdckdint.h +fi + cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure diff --git a/configure.ac b/configure.ac index d4ca74e5..cba38970 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ dnl Process this file with autoconf to produce a configure script. # You should have received a copy of the GNU General Public License # along with this program. If not, see . -AC_REVISION([for Bash 5.3, version 5.061])dnl +AC_REVISION([for Bash 5.3, version 5.062])dnl define(bashvers, 5.3) define(relstatus, devel) @@ -788,6 +788,7 @@ BASH_HEADER_INTTYPES AC_CHECK_HEADERS(unistd.h stdlib.h varargs.h limits.h string.h \ memory.h locale.h termcap.h termio.h termios.h dlfcn.h \ stdbool.h stddef.h stdint.h netdb.h pwd.h grp.h strings.h \ + stdckdint.h \ regex.h syslog.h ulimit.h) AC_CHECK_HEADERS(sys/pte.h sys/stream.h sys/select.h sys/file.h sys/ioctl.h \ sys/mman.h sys/param.h sys/random.h sys/socket.h sys/stat.h \ @@ -1352,4 +1353,12 @@ AC_CONFIG_FILES([Makefile builtins/Makefile lib/readline/Makefile \ dnl Makefile uses this timestamp file to record whether config.h is up to date. AC_CONFIG_COMMANDS([stamp-h], [echo timestamp > stamp-h]) +if test "$ac_cv_header_stdckdint_h" = yes; then + rm -f stdckdint.h +elif cmp ${srcdir}/include/stdckdint.in.h stdckdint.h 2>/dev/null; then + : +else + cp ${srcdir}/include/stdckdint.in.h stdckdint.h +fi + AC_OUTPUT diff --git a/examples/loadables/getconf.h b/examples/loadables/getconf.h index b8b9f102..98cc05e6 100644 --- a/examples/loadables/getconf.h +++ b/examples/loadables/getconf.h @@ -125,12 +125,4 @@ # define WORD_BIT (sizeof (int) * CHAR_BIT) #endif -#if !defined (PRIdMAX) -# if HAVE_LONG_LONG -# define PRIdMAX "lld" -# else -# define PRIdMAX "ld" -# endif -#endif - #endif /* _GETCONF_H */ diff --git a/examples/loadables/seq.c b/examples/loadables/seq.c index 2a2be827..13834b8d 100644 --- a/examples/loadables/seq.c +++ b/examples/loadables/seq.c @@ -35,18 +35,6 @@ extern int errno; #endif -#if defined (PRI_MACROS_BROKEN) -# undef PRIdMAX -#endif - -#if !defined (PRIdMAX) -# if HAVE_LONG_LONG -# define PRIdMAX "lld" -# else -# define PRIdMAX "ld" -# endif -#endif - #if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN) typedef long double floatmax_t; # define FLOATMAX_CONV "L" diff --git a/execute_cmd.h b/execute_cmd.h index f5540999..53fb04fd 100644 --- a/execute_cmd.h +++ b/execute_cmd.h @@ -1,6 +1,6 @@ /* execute_cmd.h - functions from execute_cmd.c. */ -/* Copyright (C) 1993-2017,2022 Free Software Foundation, Inc. +/* Copyright (C) 1993-2017,2022-2024 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. diff --git a/include/intprops-internal.h b/include/intprops-internal.h new file mode 100644 index 00000000..c8a87d2b --- /dev/null +++ b/include/intprops-internal.h @@ -0,0 +1,397 @@ +/* intprops-internal.h -- properties of integer types not visible to users + + Copyright (C) 2001-2024 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +#ifndef _GL_INTPROPS_INTERNAL_H +#define _GL_INTPROPS_INTERNAL_H + +#include + +/* Pacify GCC 13.2 in some calls to _GL_EXPR_SIGNED. */ +#if defined __GNUC__ && 4 < __GNUC__ + (3 <= __GNUC_MINOR__) +# pragma GCC diagnostic ignored "-Wtype-limits" +#endif + +/* Return a value with the common real type of E and V and the value of V. + Do not evaluate E. */ +#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v)) + +/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see + . */ +#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v)) + +/* The extra casts in the following macros work around compiler bugs, + e.g., in Cray C 5.0.3.0. */ + +/* True if the real type T is signed. */ +#define _GL_TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) + +/* Return 1 if the real expression E, after promotion, has a + signed or floating type. Do not evaluate E. */ +#define _GL_EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0) + + +/* Minimum and maximum values for integer types and expressions. */ + +/* The width in bits of the integer type or expression T. + Do not evaluate T. T must not be a bit-field expression. + Padding bits are not supported; this is checked at compile-time below. */ +#define _GL_TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT) + +/* The maximum and minimum values for the type of the expression E, + after integer promotion. E is not evaluated. */ +#define _GL_INT_MINIMUM(e) \ + (_GL_EXPR_SIGNED (e) \ + ? ~ _GL_SIGNED_INT_MAXIMUM (e) \ + : _GL_INT_CONVERT (e, 0)) +#define _GL_INT_MAXIMUM(e) \ + (_GL_EXPR_SIGNED (e) \ + ? _GL_SIGNED_INT_MAXIMUM (e) \ + : _GL_INT_NEGATE_CONVERT (e, 1)) +#define _GL_SIGNED_INT_MAXIMUM(e) \ + (((_GL_INT_CONVERT (e, 1) << (_GL_TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1) + +/* Work around OpenVMS incompatibility with C99. */ +#if !defined LLONG_MAX && defined __INT64_MAX +# define LLONG_MAX __INT64_MAX +# define LLONG_MIN __INT64_MIN +#endif + +/* This include file assumes that signed types are two's complement without + padding bits; the above macros have undefined behavior otherwise. + If this is a problem for you, please let us know how to fix it for your host. + This assumption is tested by the intprops-tests module. */ + +/* Does the __typeof__ keyword work? This could be done by + 'configure', but for now it's easier to do it by hand. */ +#if (2 <= __GNUC__ \ + || (4 <= __clang_major__) \ + || (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \ + || (0x5110 <= __SUNPRO_C && !__STDC__)) +# define _GL_HAVE___TYPEOF__ 1 +#else +# define _GL_HAVE___TYPEOF__ 0 +#endif + +/* Return 1 if the integer type or expression T might be signed. Return 0 + if it is definitely unsigned. T must not be a bit-field expression. + This macro does not evaluate its argument, and expands to an + integer constant expression. */ +#if _GL_HAVE___TYPEOF__ +# define _GL_SIGNED_TYPE_OR_EXPR(t) _GL_TYPE_SIGNED (__typeof__ (t)) +#else +# define _GL_SIGNED_TYPE_OR_EXPR(t) 1 +#endif + +/* Return 1 if - A would overflow in [MIN,MAX] arithmetic. + A should not have side effects, and A's type should be an + integer with minimum value MIN and maximum MAX. */ +#define _GL_INT_NEGATE_RANGE_OVERFLOW(a, min, max) \ + ((min) < 0 ? (a) < - (max) : 0 < (a)) + +/* True if __builtin_add_overflow (A, B, P) and __builtin_sub_overflow + (A, B, P) work when P is non-null. */ +#ifdef __EDG__ +/* EDG-based compilers like nvc 22.1 cannot add 64-bit signed to unsigned + . */ +# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0 +#elif defined __has_builtin +# define _GL_HAS_BUILTIN_ADD_OVERFLOW __has_builtin (__builtin_add_overflow) +/* __builtin_{add,sub}_overflow exists but is not reliable in GCC 5.x and 6.x, + see . */ +#elif 7 <= __GNUC__ +# define _GL_HAS_BUILTIN_ADD_OVERFLOW 1 +#else +# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0 +#endif + +/* True if __builtin_mul_overflow (A, B, P) works when P is non-null. */ +#if defined __clang_major__ && __clang_major__ < 14 +/* Work around Clang bug . */ +# define _GL_HAS_BUILTIN_MUL_OVERFLOW 0 +#else +# define _GL_HAS_BUILTIN_MUL_OVERFLOW _GL_HAS_BUILTIN_ADD_OVERFLOW +#endif + +/* True if __builtin_add_overflow_p (A, B, C) works, and similarly for + __builtin_sub_overflow_p and __builtin_mul_overflow_p. */ +#ifdef __EDG__ +/* In EDG-based compilers like ICC 2021.3 and earlier, + __builtin_add_overflow_p etc. are not treated as integral constant + expressions even when all arguments are. */ +# define _GL_HAS_BUILTIN_OVERFLOW_P 0 +#elif defined __has_builtin +# define _GL_HAS_BUILTIN_OVERFLOW_P __has_builtin (__builtin_mul_overflow_p) +#else +# define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__) +#endif + +#if (!defined _GL_STDCKDINT_H && 202311 <= __STDC_VERSION__ \ + && ! (_GL_HAS_BUILTIN_ADD_OVERFLOW && _GL_HAS_BUILTIN_MUL_OVERFLOW)) +# include +#endif + +/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R. + Return 1 if the result overflows. Arguments should not have side + effects and A, B and *R can be of any integer type other than char, + bool, a bit-precise integer type, or an enumeration type. */ +#if _GL_HAS_BUILTIN_ADD_OVERFLOW +# define _GL_INT_ADD_WRAPV(a, b, r) __builtin_add_overflow (a, b, r) +# define _GL_INT_SUBTRACT_WRAPV(a, b, r) __builtin_sub_overflow (a, b, r) +#elif defined ckd_add && defined ckd_sub && !defined _GL_STDCKDINT_H +# define _GL_INT_ADD_WRAPV(a, b, r) ckd_add (r, + (a), + (b)) +# define _GL_INT_SUBTRACT_WRAPV(a, b, r) ckd_sub (r, + (a), + (b)) +#else +# define _GL_INT_ADD_WRAPV(a, b, r) \ + _GL_INT_OP_WRAPV (a, b, r, +, _GL_INT_ADD_RANGE_OVERFLOW) +# define _GL_INT_SUBTRACT_WRAPV(a, b, r) \ + _GL_INT_OP_WRAPV (a, b, r, -, _GL_INT_SUBTRACT_RANGE_OVERFLOW) +#endif +#if _GL_HAS_BUILTIN_MUL_OVERFLOW +# if ((9 < __GNUC__ + (3 <= __GNUC_MINOR__) \ + || (__GNUC__ == 8 && 4 <= __GNUC_MINOR__)) \ + && !defined __EDG__) +# define _GL_INT_MULTIPLY_WRAPV(a, b, r) __builtin_mul_overflow (a, b, r) +# else + /* Work around GCC bug 91450. */ +# define _GL_INT_MULTIPLY_WRAPV(a, b, r) \ + ((!_GL_SIGNED_TYPE_OR_EXPR (*(r)) && _GL_EXPR_SIGNED (a) && _GL_EXPR_SIGNED (b) \ + && _GL_INT_MULTIPLY_RANGE_OVERFLOW (a, b, 0, (__typeof__ (*(r))) -1)) \ + ? ((void) __builtin_mul_overflow (a, b, r), 1) \ + : __builtin_mul_overflow (a, b, r)) +# endif +#elif defined ckd_mul && !defined _GL_STDCKDINT_H +# define _GL_INT_MULTIPLY_WRAPV(a, b, r) ckd_mul (r, + (a), + (b)) +#else +# define _GL_INT_MULTIPLY_WRAPV(a, b, r) \ + _GL_INT_OP_WRAPV (a, b, r, *, _GL_INT_MULTIPLY_RANGE_OVERFLOW) +#endif + +/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See: + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193 + https://llvm.org/bugs/show_bug.cgi?id=25390 + For now, assume all versions of GCC-like compilers generate bogus + warnings for _Generic. This matters only for compilers that + lack relevant builtins. */ +#if __GNUC__ || defined __clang__ +# define _GL__GENERIC_BOGUS 1 +#else +# define _GL__GENERIC_BOGUS 0 +#endif + +/* Store the low-order bits of A B into *R, where OP specifies + the operation and OVERFLOW the overflow predicate. Return 1 if the + result overflows. Arguments should not have side effects, + and A, B and *R can be of any integer type other than char, bool, a + bit-precise integer type, or an enumeration type. */ +#if 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS +# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \ + (_Generic \ + (*(r), \ + signed char: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + signed char, SCHAR_MIN, SCHAR_MAX), \ + unsigned char: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + unsigned char, 0, UCHAR_MAX), \ + short int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + short int, SHRT_MIN, SHRT_MAX), \ + unsigned short int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + unsigned short int, 0, USHRT_MAX), \ + int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + int, INT_MIN, INT_MAX), \ + unsigned int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + unsigned int, 0, UINT_MAX), \ + long int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + long int, LONG_MIN, LONG_MAX), \ + unsigned long int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + unsigned long int, 0, ULONG_MAX), \ + long long int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ + long long int, LLONG_MIN, LLONG_MAX), \ + unsigned long long int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ + unsigned long long int, 0, ULLONG_MAX))) +#else +/* Store the low-order bits of A B into *R, where OP specifies + the operation and OVERFLOW the overflow predicate. If *R is + signed, its type is ST with bounds SMIN..SMAX; otherwise its type + is UT with bounds U..UMAX. ST and UT are narrower than int. + Return 1 if the result overflows. Arguments should not have side + effects, and A, B and *R can be of any integer type other than + char, bool, a bit-precise integer type, or an enumeration type. */ +# if _GL_HAVE___TYPEOF__ +# define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \ + (_GL_TYPE_SIGNED (__typeof__ (*(r))) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, st, smin, smax) \ + : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, ut, 0, umax)) +# else +# define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \ + (overflow (a, b, smin, smax) \ + ? (overflow (a, b, 0, umax) \ + ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 1) \ + : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) < 0) \ + : (overflow (a, b, 0, umax) \ + ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) >= 0 \ + : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 0))) +# endif + +# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \ + (sizeof *(r) == sizeof (signed char) \ + ? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \ + signed char, SCHAR_MIN, SCHAR_MAX, \ + unsigned char, UCHAR_MAX) \ + : sizeof *(r) == sizeof (short int) \ + ? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \ + short int, SHRT_MIN, SHRT_MAX, \ + unsigned short int, USHRT_MAX) \ + : sizeof *(r) == sizeof (int) \ + ? (_GL_EXPR_SIGNED (*(r)) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + int, INT_MIN, INT_MAX) \ + : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + unsigned int, 0, UINT_MAX)) \ + : _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow)) +# ifdef LLONG_MAX +# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ + (sizeof *(r) == sizeof (long int) \ + ? (_GL_EXPR_SIGNED (*(r)) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + long int, LONG_MIN, LONG_MAX) \ + : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + unsigned long int, 0, ULONG_MAX)) \ + : (_GL_EXPR_SIGNED (*(r)) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ + long long int, LLONG_MIN, LLONG_MAX) \ + : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ + unsigned long long int, 0, ULLONG_MAX))) +# else +# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ + (_GL_EXPR_SIGNED (*(r)) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + long int, LONG_MIN, LONG_MAX) \ + : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + unsigned long int, 0, ULONG_MAX)) +# endif +#endif + +/* Store the low-order bits of A B into *R, where the operation + is given by OP. Use the unsigned type UT for calculation to avoid + overflow problems. *R's type is T, with extrema TMIN and TMAX. + T can be any signed integer type other than char, bool, a + bit-precise integer type, or an enumeration type. + Return 1 if the result overflows. */ +#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \ + (overflow (a, b, tmin, tmax) \ + ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \ + : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0)) + +/* Return 1 if the integer expressions A - B and -A would overflow, + respectively. Arguments should not have side effects, + and can be any signed integer type other than char, bool, a + bit-precise integer type, or an enumeration type. + These macros are tuned for their last input argument being a constant. */ + +#if _GL_HAS_BUILTIN_OVERFLOW_P +# define _GL_INT_NEGATE_OVERFLOW(a) \ + __builtin_sub_overflow_p (0, a, (__typeof__ (- (a))) 0) +#else +# define _GL_INT_NEGATE_OVERFLOW(a) \ + _GL_INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) +#endif + +/* Return the low-order bits of A B, where the operation is given + by OP. Use the unsigned type UT for calculation to avoid undefined + behavior on signed integer overflow, and convert the result to type T. + UT is at least as wide as T and is no narrower than unsigned int, + T is two's complement, and there is no padding or trap representations. + Assume that converting UT to T yields the low-order bits, as is + done in all known two's-complement C compilers. E.g., see: + https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html + + According to the C standard, converting UT to T yields an + implementation-defined result or signal for values outside T's + range. However, code that works around this theoretical problem + runs afoul of a compiler bug in Oracle Studio 12.3 x86. See: + https://lists.gnu.org/r/bug-gnulib/2017-04/msg00049.html + As the compiler bug is real, don't try to work around the + theoretical problem. */ + +#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \ + ((t) ((ut) (a) op (ut) (b))) + +/* Return true if the numeric values A + B, A - B, A * B fall outside + the range TMIN..TMAX. Arguments should not have side effects + and can be any integer type other than char, bool, + a bit-precise integer type, or an enumeration type. + TMIN should be signed and nonpositive. + TMAX should be positive, and should be signed unless TMIN is zero. */ +#define _GL_INT_ADD_RANGE_OVERFLOW(a, b, tmin, tmax) \ + ((b) < 0 \ + ? (((tmin) \ + ? ((_GL_EXPR_SIGNED (_GL_INT_CONVERT (a, (tmin) - (b))) || (b) < (tmin)) \ + && (a) < (tmin) - (b)) \ + : (a) <= -1 - (b)) \ + || ((_GL_EXPR_SIGNED (a) ? 0 <= (a) : (tmax) < (a)) && (tmax) < (a) + (b))) \ + : (a) < 0 \ + ? (((tmin) \ + ? ((_GL_EXPR_SIGNED (_GL_INT_CONVERT (b, (tmin) - (a))) || (a) < (tmin)) \ + && (b) < (tmin) - (a)) \ + : (b) <= -1 - (a)) \ + || ((_GL_EXPR_SIGNED (_GL_INT_CONVERT (a, b)) || (tmax) < (b)) \ + && (tmax) < (a) + (b))) \ + : (tmax) < (b) || (tmax) - (b) < (a)) +#define _GL_INT_SUBTRACT_RANGE_OVERFLOW(a, b, tmin, tmax) \ + (((a) < 0) == ((b) < 0) \ + ? ((a) < (b) \ + ? !(tmin) || -1 - (tmin) < (b) - (a) - 1 \ + : (tmax) < (a) - (b)) \ + : (a) < 0 \ + ? ((!_GL_EXPR_SIGNED (_GL_INT_CONVERT ((a) - (tmin), b)) && (a) - (tmin) < 0) \ + || (a) - (tmin) < (b)) \ + : ((! (_GL_EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \ + && _GL_EXPR_SIGNED (_GL_INT_CONVERT ((tmax) + (b), a))) \ + && (tmax) <= -1 - (b)) \ + || (tmax) + (b) < (a))) +#define _GL_INT_MULTIPLY_RANGE_OVERFLOW(a, b, tmin, tmax) \ + ((b) < 0 \ + ? ((a) < 0 \ + ? (_GL_EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \ + ? (a) < (tmax) / (b) \ + : ((_GL_INT_NEGATE_OVERFLOW (b) \ + ? _GL_INT_CONVERT (b, tmax) >> (_GL_TYPE_WIDTH (+ (b)) - 1) \ + : (tmax) / -(b)) \ + <= -1 - (a))) \ + : _GL_INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (b, tmin)) && (b) == -1 \ + ? (_GL_EXPR_SIGNED (a) \ + ? 0 < (a) + (tmin) \ + : 0 < (a) && -1 - (tmin) < (a) - 1) \ + : (tmin) / (b) < (a)) \ + : (b) == 0 \ + ? 0 \ + : ((a) < 0 \ + ? (_GL_INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (a, tmin)) && (a) == -1 \ + ? (_GL_EXPR_SIGNED (b) ? 0 < (b) + (tmin) : -1 - (tmin) < (b) - 1) \ + : (tmin) / (a) < (b)) \ + : (tmax) / (b) < (a))) + +#endif /* _GL_INTPROPS_INTERNAL_H */ diff --git a/include/stdckdint.in.h b/include/stdckdint.in.h new file mode 100644 index 00000000..91848806 --- /dev/null +++ b/include/stdckdint.in.h @@ -0,0 +1,35 @@ +/* stdckdint.h -- checked integer arithmetic + + Copyright 2022-2024 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +#ifndef _GL_STDCKDINT_H +#define _GL_STDCKDINT_H + +#include "intprops-internal.h" + +/* Store into *R the low-order bits of A + B, A - B, A * B, respectively. + Return 1 if the result overflows, 0 otherwise. + A, B, and *R can have any integer type other than char, bool, a + bit-precise integer type, or an enumeration type. + + These are like the standard macros introduced in C23, except that + arguments should not have side effects. */ + +#define ckd_add(r, a, b) ((bool) _GL_INT_ADD_WRAPV (a, b, r)) +#define ckd_sub(r, a, b) ((bool) _GL_INT_SUBTRACT_WRAPV (a, b, r)) +#define ckd_mul(r, a, b) ((bool) _GL_INT_MULTIPLY_WRAPV (a, b, r)) + +#endif /* _GL_STDCKDINT_H */ diff --git a/mksyntax.c b/mksyntax.c index f3e6ef51..348d632d 100644 --- a/mksyntax.c +++ b/mksyntax.c @@ -2,7 +2,7 @@ * mksyntax.c - construct shell syntax table for fast char attribute lookup. */ -/* Copyright (C) 2000-2009,2012,2022-2023 Free Software Foundation, Inc. +/* Copyright (C) 2000-2009,2012,2022-2024 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. diff --git a/sig.c b/sig.c index d44ce358..d902b5cf 100644 --- a/sig.c +++ b/sig.c @@ -1,6 +1,6 @@ /* sig.c - interface for shell signal handlers and signal initialization. */ -/* Copyright (C) 1994-2022 Free Software Foundation, Inc. +/* Copyright (C) 1994-2024 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. diff --git a/stringlib.c b/stringlib.c index 7c24df62..0130fdaa 100644 --- a/stringlib.c +++ b/stringlib.c @@ -1,6 +1,6 @@ /* stringlib.c - Miscellaneous string functions. */ -/* Copyright (C) 1996-2009,2022-2023 Free Software Foundation, Inc. +/* Copyright (C) 1996-2009,2022-2024 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. diff --git a/tests/printf.right b/tests/printf.right index 29f46f18..8af40aa7 100644 --- a/tests/printf.right +++ b/tests/printf.right @@ -377,11 +377,11 @@ VAR=[] ./printf7.sub: line 25: printf: 21474836470: Result too large VAR=[X] ./printf7.sub: line 31: printf: 9223372036854775825: Result too large -[ ] +[] ./printf7.sub: line 32: printf: 9223372036854775825: Result too large [X] ./printf7.sub: line 34: printf: 9223372036854775825: Result too large -VAR=[ ] +VAR=[] ./printf7.sub: line 37: printf: 9223372036854775825: Result too large VAR=[X] ./printf7.sub: line 43: printf: 21474836470: Result too large @@ -401,4 +401,5 @@ VAR=[] ./printf7.sub: line 61: printf: 9223372036854775825: Result too large VAR=[X] XY +./printf7.sub: line 71: printf: 9223372036854775825: Result too large XY diff --git a/variables.c b/variables.c index 82ceb48a..8473e9f9 100644 --- a/variables.c +++ b/variables.c @@ -1,6 +1,6 @@ /* variables.c -- Functions for hacking shell variables. */ -/* Copyright (C) 1987-2023 Free Software Foundation, Inc. +/* Copyright (C) 1987-2024 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. diff --git a/variables.h b/variables.h index 3d66fa21..ba131925 100644 --- a/variables.h +++ b/variables.h @@ -1,6 +1,6 @@ /* variables.h -- data structures for shell variables. */ -/* Copyright (C) 1987-2023 Free Software Foundation, Inc. +/* Copyright (C) 1987-2024 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell.