https://sourceware.org/bugzilla/show_bug.cgi?id=26773
Bug ID: 26773 Summary: sleb128 values near INT64_MAX/MIN not correctly read Product: elfutils Version: unspecified Status: NEW Severity: normal Priority: P2 Component: libdw Assignee: unassigned at sourceware dot org Reporter: mark at klomp dot org CC: elfutils-devel at sourceware dot org, tromey at sourceware dot org Target Milestone: --- sleb128 values near INT64_MAX/MIN are not correctly read since: commit 65a211f9028304757df8f4fa7cb3cc77d1501420 Author: Mark Wielaard <m...@redhat.com> Date: Wed Apr 22 12:28:30 2015 +0200 libdw: Undefined behavior in get_sleb128_step. gcc -fsanitize=undefined pointed out that for too big sleb128 values we could shift into the sign bit. So for sleb128 values that have to fit in a (signed) int64_t variable reduce the max number of steps by one. https://bugzilla.redhat.com/show_bug.cgi?id=1170810#c29 Signed-off-by: Mark Wielaard <m...@redhat.com> The idea was the we didn't want to shift 1 << (9 * 7) since that would shift 63 places in a signed value (which is undefined behavior). Where 9 is the number of bytes/steps (counting from zero). But sleb128 values near INT64_MIN/MAX are represented by 10 bytes. Where the 10th byte doesn't have its high bit set to indicate it is the last one. So for sleb128 values that use 10 bytes we fail to read all and return INT64_MAX. The reason we haven't seen this before is because normally using data8 is cheaper for representing such values (if we know the type is signed). But with DWARF5 we might be able to share the value between DIEs using DW_FORM_implicit_const (which is represented in the abbrev itself using an sleb128). An example that triggers this is: #include <stdint.h> int foo () { int64_t maxA, maxB, maxC; maxA = maxB = maxC = INT64_MAX - 16; /* 9223372036854775791 */ int64_t minA, minB, minC; minA = minB = minC = INT64_MIN + 16; /* -9223372036854775792 */ return (maxA + maxB + maxC + minA + minB + minC); } compiled with gcc -gdwarf-5 -g -O2 -c consts.c $ eu-readelf --debug-dump=abbrev consts.o DWARF section [ 6] '.debug_abbrev' at offset 0x114: [ Code] Abbreviation section at offset 0: [ 1] offset: 0, children: no, tag: base_type attr: byte_size, form: data1, offset: 0 attr: encoding, form: data1, offset: 0x2 attr: name, form: strp, offset: 0x4 [ 2] offset: 11, children: no, tag: variable attr: name, form: strp, offset: 0xb attr: decl_file, form: implicit_const (1), offset: 0xd attr: decl_line, form: implicit_const (5), offset: 0x10 attr: decl_column, form: data1, offset: 0x13 attr: type, form: ref4, offset: 0x15 attr: const_value, form: implicit_const (9223372036854775807), offset: 0x17 Abbreviation section at offset 40: [ 3] offset: 40, children: no, tag: variable attr: name, form: strp, offset: 0x28 attr: decl_file, form: implicit_const (1), offset: 0x2a attr: decl_line, form: implicit_const (8), offset: 0x2d attr: decl_column, form: data1, offset: 0x30 attr: type, form: ref4, offset: 0x32 attr: const_value, form: implicit_const (9223372036854775807), offset: 0x34 attr: call_origin, form: ??? (0), offset: 0x3f attr: ??? (0), form: block4, offset: 0x41 [...] Note how both values are read as INT64_MAX and that after (what is supposed to be the negative value -9223372036854775792) the rest of the abbrev is read wrongly: $ eu-readelf --debug-dump=info consts.o DWARF section [ 4] '.debug_info' at offset 0x46: [Offset] Compilation unit at offset 0: Version: 5, Abbreviation section offset: 0, Address size: 8, Offset size: 4 Unit type: compile (1) eu-readelf: cannot get tag of DIE at offset [c] in section '.debug_info': invalid DWARF We have to allow reading 10-byte sleb128 values without triggering undefined behavior. -- You are receiving this mail because: You are on the CC list for the bug.