[PATCH] Use 1U everywhere in elf/elf.h.
Petr Machata
pmachata@redhat.com
Tue Mar 24 21:04:00 GMT 2015
"Carlos O'Donell" <carlos@redhat.com> writes:
> On 03/06/2015 05:28 PM, Roland McGrath wrote:
>>> I would like to write a test case for it, but I can't get anything to
>>> trigger the original reported failure by readelf when running with
>>> -fsanitize=undefined.
>>>
>>> Therefore I can't at present even get a reproducer nor write a regression
>>> test, but I know what what we have for SHF_EXCLUDE is wrong.
>>
>> A regression test for a reported manifest issue is of course worthwhile.
>> But I was talking about a generic test that verifies at compile time what
>> the types actually are rather than some particular characteristic of behavior.
>
> How?
>
> I mean I could use C++ and the associated RTTI to do the comparison at
> runtime and thus produce a detailed analysis of the types.
>
> Is that what you're thinking too?
Would something like the following be acceptable? It builds on
known-elf.h/known-elf.awk that I've earlier today proposed for
contribution to elfutils.
#include <elfutils/known-elf.h>
#include <elf.h>
#define TEST_FITS(VALUE, NAME, W) \
_Static_assert ((VALUE) == 0 || __builtin_log2 ((VALUE)) < W, \
NAME " doesn't fit in " #W " bits");
#define ELF_ONE_KNOWN_AT(NAME, VALUE) TEST_FITS (VALUE, #VALUE, 32) // uint32_t
ELF_ALL_KNOWN_AT
#undef ELF_ONE_KNOWN_AT
#define ELF_ONE_KNOWN_DT(NAME, VALUE) TEST_FITS (VALUE, #VALUE, 32) // Elf32_Sword
ELF_ALL_KNOWN_DT
#define ELF_ONE_KNOWN_DT_ARCH(ARCH) ELF_ALL_KNOWN_DT_##ARCH
ELF_ALL_KNOWN_DT_ARCHES
#undef ELF_ONE_KNOWN_DT_ARCH
#undef ELF_ONE_KNOWN_DT
#define ELF_ONE_KNOWN_ELFOSABI(NAME, VALUE) TEST_FITS (VALUE, #VALUE, 8) // unsigned char
ELF_ALL_KNOWN_ELFOSABI
#undef ELF_ONE_KNOWN_ELFOSABI
#define ELF_ONE_KNOWN_STV(NAME, VALUE) TEST_FITS (VALUE, #VALUE, 2) // unsigned char & 0x3
ELF_ALL_KNOWN_STV
#undef ELF_ALL_KNOWN_STV
// etc...
If I tweak it to admit only 7 bits for ELFOSABI:
$ gcc ble.c -std=c11 -Wall
ble.c:5:3: error: static assertion failed: "ELFOSABI_STANDALONE doesn\'t fit in 7 bits"
_Static_assert ((VALUE) == 0 || __builtin_log2 ((VALUE)) < W, \
^
ble.c:19:45: note: in expansion of macro ‘TEST_FITS’
#define ELF_ONE_KNOWN_ELFOSABI(NAME, VALUE) TEST_FITS(VALUE, #VALUE, 7) // unsigned char
^
/home/petr/proj/dwgrep/64/libzwerg/known-elf.h:193:3: note: in expansion of macro ‘ELF_ONE_KNOWN_ELFOSABI’
ELF_ONE_KNOWN_ELFOSABI (STANDALONE, ELFOSABI_STANDALONE) \
^
ble.c:20:1: note: in expansion of macro ‘ELF_ALL_KNOWN_ELFOSABI’
ELF_ALL_KNOWN_ELFOSABI
The way this would catch the original bug is that GCC refuses to
compile-time evaluate 1 << 31. I'm not sure, but it seems that's
because it's UB--change it to 1U or 1L and GCC compile-time evaluates it
happily. So the compilation would fail, indicating that 1 << 31 is not
a compile-time constant.
Porting back to C<11, the static assert can be emulated by the
negative-sized char array thick. Then the likes of 1 << 31 that are not
compile-time constants lead to actual calls to log2, which we catch as
link errors. Not as nice as compile-time error, but also works.
If C++ is acceptable, it should be easy to replace the __builtin_log2
and _Static_assert with a bit of (portable, if C++98 is considered that)
template metaprogramming.
Thanks,
Petr
More information about the Libc-alpha
mailing list