[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