[Bug gdb/34369] New: [gdb] value_as_mpz does not sign-extend integers whose DW_AT_bit_size is smaller than their storage size
firmiana402 at gmail dot com via Gdb-prs <[email protected]>
| Newsgroups | gmane.comp.gdb.bugs.discuss |
|---|---|
| Message-ID | <[email protected]/bugzilla/> |
https://sourceware.org/bugzilla/show_bug.cgi?id=34369
Bug ID: 34369
Summary: [gdb] value_as_mpz does not sign-extend integers whose
DW_AT_bit_size is smaller than their storage size
Product: gdb
Version: HEAD
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: gdb
Assignee: unassigned at sourceware dot org
Reporter: firmiana402 at gmail dot com
Target Milestone: ---
For a signed base type whose logical bit size is smaller than
its storage size (DW_AT_bit_size differs from 8 * byte_size —
e.g. GCC's _BitInt(31), stored in 4 bytes), value_as_mpz reads
the value at the full storage width and only masks off the high
bits; it never sign-extends at the logical bit size. A negative
such value is therefore read back as a large positive number.
The relevant code is in value_as_mpz (gdb/value.c):
result.read (val->contents (), byte_order, type->is_unsigned ());
/* Shift off any low bits, if needed. */
if (bit_off != 0)
result >>= bit_off;
/* Mask off any high bits, if needed. */
if (bit_size)
result.mask (bit_size);
gdb_mpz::read interprets the sign using the full buffer width
(its sign bit is at buf.size () * 8 - 1, i.e. bit 31 for a 4-byte
type), and mask (bit_size) only clears bits at and above
bit_size. Nothing sign-extends from the logical sign bit
(bit_size - 1). For a signed _BitInt(31) holding raw 0x7fffffff
— which is -1 in 31-bit two's complement — value_as_mpz returns
+2147483647.
GDB's other integer read path handles this correctly:
value_as_long goes through unpack_long, which routes
bit_size_differs_p types to unpack_bits_as_long (gdb/value.c).
That helper masks and then sign-extends at the logical bit size
for signed types:
if (bitsize < 8 * (int) sizeof (val))
{
valmask = (((ULONGEST) 1) << bitsize) - 1;
val &= valmask;
if (!field_type->is_unsigned ())
{
if (val & (valmask ^ (valmask >> 1)))
val |= ~valmask;
}
}
So value_as_mpz is inconsistent with value_as_long / unpack_long
for exactly these types: the byte-based path sign-extends, the
mpz path does not.
## Impact
value_as_mpz is how the typed DWARF integer binary operators read
their operands: scalar_binop (gdb/valarith.c) does
gdb_mpz v1 = value_as_mpz (arg1); gdb_mpz v2 = value_as_mpz
(arg2); before computing. So arithmetic and comparisons on a
negative narrow-bit signed value — for instance a _BitInt(31)
produced by DW_OP_convert — are evaluated with a wrong, large
positive operand, which changes the result.
--
You are receiving this mail because:
You are on the CC list for the bug.