Hi Basil,

"Basil L. Contovounesios" <[email protected]> writes:

> When compiling my project with Clang, ASan, and Gnulib's stdint-h,
> I find that PTRDIFF_MAX and SIZE_MAX expand to 1.
>
> This does not happen if I either
> - remove stdint-h from bootstrap.conf; or
> - disable ASan; or
> - use GCC.
>
> I am reproducing the issue in a dummy project as follows:
> 0. git clone 'https://git.sr.ht/~blc/foo' && cd foo
> 1. ./test gcc
> 2. ./test gcc --enable-asan
> 3. ./test clang
> 4. ./test clang --enable-asan
>
> Steps 1-3 end in
>   bar> 13 `Hello, World!'
> as expected, whereas step 4 ends in
>   foo> Overflow 13 > 1
> where 13 (the length of "Hello, World!") exceeds 1 (PTRDIFF_MAX).
>
> This happens in the following function in src/foo.c:
>
>   bool
>   foo_string (char const str[const static 1])
>   {
>     size_t const len = strlen (str);
>     bool ok = len <= (uintmax_t) PTRDIFF_MAX;
>     if (ok)
>       bar_string (str, len);
>     else
>       fprintf (stderr, "foo> Overflow %zu > %td\n", len, PTRDIFF_MAX);
>     return ok;
>   }
>
> The files under src/ should be straightforward; the only complexities
> should be in configure.ac (where I define a macro inspired by
> gl_COMPILER_OPTION_IF and AX_CHECK_LINK_FLAG) and the 'test' script
> which tries to set up ASan and all of its run time options for either
> GCC or Clang.
>
> Note that configure.ac enables UBSan as well if available, but disabling
> that by passing --disable-ubsan to the 'test' script makes no observable
> difference in the behaviour of the 'foo' program.
>
> I have tried removing other header modules from bootstrap.conf,
> but only the removal of stdint-h resolves the issue.
>
> That's as far as I've been able to troubleshoot for now;
> let me know if you have any further suggestions.

Thanks for the reproduction steps. Do you see the same as me when
running these commands:

    $ grep '^BITSIZEOF_PTRDIFF_T' Makefile
    BITSIZEOF_PTRDIFF_T = 0
    $ grep -FA5 'checking for bit size of ptrdiff_t' config.log 
     configure:9072: checking for bit size of ptrdiff_t
     configure:9078: clang -std=gnu23 -o conftest -Og -g3 -ggdb3 -gdwarf-5 
-fdebug-macro -fsanitize=address -fsanitize=undefined  -shared-libasan 
-fsanitize=address -fsanitize=undefined conftest.c  >&5
     configure:9078: $? = 0
     configure:9078: ./conftest
     ./conftest: error while loading shared libraries: libclang_rt.asan.so: 
cannot open shared object file: No such file or directory
     configure:9078: $? = 127

If so, then this expression from stdint.in.h:

    #  define PTRDIFF_MAX  \
        _STDINT_MAX (1, @BITSIZEOF_PTRDIFF_T@, 0@PTRDIFF_T_SUFFIX@)

Turns into:

    #  define PTRDIFF_MAX  \
        _STDINT_MAX (1, 0, 0l)

Here is what that expands to using a test program:

     $ cat main.c 
     #include <stdio.h>
     #include <inttypes.h>
     # define _STDINT_MAX(signed, bits, zero) \
         (((((zero) + 1) << ((bits) ? (bits) - 1 - (signed) : 0)) - 1) * 2 + 1)
     int
     main (void)
     {
       printf ("%ju\n", (uintmax_t) _STDINT_MAX (1, 0, 0l));
       return 0;
     }
     $ gcc main.c
     $ ./a.out 
     1

> By the way, does it make sense to update the Info node
> "(gnulib) Writing reliable code" to mention any of
> _FORTIFY_SOURCE=3, GCC's -fhardened, or -fsanitize-trap=all in
> place of the now-deprecated -fsanitize-undefined-trap-on-error?

That sounds reasonable to me, but I would have to look into what those
mean. Source fortification nice, but I forget the difference between the
levels.

Collin

Reply via email to