This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] Use 1U everywhere in elf/elf.h.
- From: Petr Machata <pmachata at redhat dot com>
- To: "Carlos O'Donell" <carlos at redhat dot com>
- Cc: Roland McGrath <roland at hack dot frob dot com>, GNU C Library <libc-alpha at sourceware dot org>, Andreas Schwab <schwab at linux-m68k dot org>
- Date: Tue, 24 Mar 2015 22:03:48 +0100
- Subject: Re: [PATCH] Use 1U everywhere in elf/elf.h.
- Authentication-results: sourceware.org; auth=none
- References: <54F9E0CE dot 8070303 at redhat dot com> <20150306180147 dot 7EA492C3B32 at topped-with-meat dot com> <54FA28D8 dot 1080209 at redhat dot com> <20150306222818 dot 643092C3B39 at topped-with-meat dot com> <54FB4511 dot 2020008 at redhat dot com>
"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