bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] sha512-buffer: port back to 32-bit-only hosts


From: Bruno Haible
Subject: Re: [PATCH] sha512-buffer: port back to 32-bit-only hosts
Date: Mon, 20 May 2024 13:14:27 +0200

Paul Eggert wrote:
> > uintN_t arithmetic is overflow-free, just like 'unsigned int' arithmetic.
> 
> Not exactly. For example, this:
> 
>    uint16_t a = 46341, b = a * a;
> 
> has undefined behavior on typical platforms with 32-bit int, because 
> 46341*46341 exceeds 2**31 - 1. Although many programmers would consider 
> this an example of uint16_t arithmetic, something else is going on.
> 
> If uintN_t fits in int, a program cannot do uintN_t arithmetic directly, 
> as values are promoted to int before they become arithmetic operands. A 
> program can do only int arithmetic on these values, and the int 
> arithmetic can overflow.
> ...
> Unsigned int, unsigned long int, unsigned long long int, and uintmax_t 
> are the only types where fully portable code can assume wraparound overflow.

Oh, indeed, you're right. And while the gcc and clang UBSAN catches this
(compile with 
-fsanitize=undefined,signed-integer-overflow,shift,integer-divide-by-zero),
'gcc -ftrapv' doesn't. [1]

Fortunately we don't use multiplication on uint16_t frequently. (libunistring
uses uint16_t a lot, but never multiplies two uint16_t.)

Also good to know: A gnulib testdir of all modules, compiled with UBSAN,
passes all tests.

> > instead
> > of using the 'u64' module in order to avoid uint64_t, it would be much
> > simpler to make <stdint.h> define the missing int64_t and uint64_t types
> 
> We could do something along those lines. I'd prefer it, though, if we 
> did that only on platforms where we tested that 'unsigned long long int' 
> is actually 64 bits, since the relevant code is already cautious in this 
> area due to concerns such as the above. Although platforms are currently 
> leery of integers wider than 64 bits, wider integers are commonly 
> supported under the covers now, and I expect it won't be forever before 
> they emerge from the shadows.

Good point. Done as below. It will make our code more future-proof.

[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54848#c2


2024-05-20  Bruno Haible  <bruno@clisp.org>

        stdint: Verify the width of 'long long' before using it as int64_t.
        Suggested by Paul Eggert in
        <https://lists.gnu.org/archive/html/bug-gnulib/2024-05/msg00315.html>.
        * lib/stdint.in.h (gl_int64_t): Verify that the number of bits of
        'long long' is 64 before using it.
        (gl_uint64_t): Verify that the number of bits of 'unsigned long long'
        is 64 before using it.

diff --git a/lib/stdint.in.h b/lib/stdint.in.h
index fea7483b9c..cd3fbdd965 100644
--- a/lib/stdint.in.h
+++ b/lib/stdint.in.h
@@ -80,7 +80,7 @@
 #define _@GUARD_PREFIX@_STDINT_H
 
 /* Get SCHAR_MIN, SCHAR_MAX, UCHAR_MAX, INT_MIN, INT_MAX,
-   LONG_MIN, LONG_MAX, ULONG_MAX, _GL_INTEGER_WIDTH.  */
+   LONG_MIN, LONG_MAX, ULONG_MAX, CHAR_BIT, _GL_INTEGER_WIDTH.  */
 #include <limits.h>
 
 /* Override WINT_MIN and WINT_MAX if gnulib's <wchar.h> or <wctype.h> overrides
@@ -189,6 +189,10 @@ typedef __int64 gl_int64_t;
 #   define int64_t gl_int64_t
 #   define GL_INT64_T
 #  else
+/* Verify that 'long long' has exactly 64 bits.  */
+typedef _gl_verify_int64_bits[
+        _STDINT_MAX (1, sizeof (long long) * CHAR_BIT, 0ll) >> 31 >> 31 == 1
+        ? 1 : -1];
 #   undef int64_t
 typedef long long int gl_int64_t;
 #   define int64_t gl_int64_t
@@ -210,6 +214,11 @@ typedef unsigned __int64 gl_uint64_t;
 #   define uint64_t gl_uint64_t
 #   define GL_UINT64_T
 #  else
+/* Verify that 'unsigned long long' has exactly 64 bits.  */
+typedef _gl_verify_uint64_bits[
+        _STDINT_MAX (0, sizeof (unsigned long long) * CHAR_BIT, 0ull)
+        >> 31 >> 31 >> 1 == 1
+        ? 1 : -1];
 #   undef uint64_t
 typedef unsigned long long int gl_uint64_t;
 #   define uint64_t gl_uint64_t






reply via email to

[Prev in Thread] Current Thread [Next in Thread]