From 65879393f04e14a9ab8797a8e66e0ec8d94108b5 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Tue, 14 Oct 2014 13:36:20 +1030 Subject: [PATCH] Avoid undefined behaviour with signed expressions PR 17453 bfd/ * libbfd.c (COERCE16, COERCE32, COERCE64): Use unsigned types. (EIGHT_GAZILLION): Delete. binutils/ * dwarf.c (read_leb128): Avoid signed overflow. (read_debug_line_header): Likewise. gas/ * config/tc-i386.c (fits_in_signed_long): Use unsigned param and expression to avoid signed overflow. (fits_in_signed_byte, fits_in_unsigned_byte, fits_in_unsigned_word, fits_in_signed_word, fits_in_unsigned_long): Similarly. * expr.c (operand <'-'>): Avoid signed overflow. * read.c (s_comm_internal): Likewise. --- bfd/ChangeLog | 6 ++++++ bfd/libbfd.c | 7 +++---- binutils/ChangeLog | 6 ++++++ binutils/dwarf.c | 8 ++------ gas/ChangeLog | 10 ++++++++++ gas/config/tc-i386.c | 25 ++++++++++++------------- gas/expr.c | 3 ++- gas/read.c | 2 +- gas/write.c | 2 +- 9 files changed, 43 insertions(+), 26 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index be3ae38..f9e81d3 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,9 @@ +2014-10-14 Alan Modra + + PR 17453 + * libbfd.c (COERCE16, COERCE32, COERCE64): Use unsigned types. + (EIGHT_GAZILLION): Delete. + 2014-10-13 Alan Modra PR 17467 diff --git a/bfd/libbfd.c b/bfd/libbfd.c index 6676dff..d98a9d2 100644 --- a/bfd/libbfd.c +++ b/bfd/libbfd.c @@ -548,11 +548,10 @@ DESCRIPTION .*/ /* Sign extension to bfd_signed_vma. */ -#define COERCE16(x) (((bfd_signed_vma) (x) ^ 0x8000) - 0x8000) -#define COERCE32(x) (((bfd_signed_vma) (x) ^ 0x80000000) - 0x80000000) -#define EIGHT_GAZILLION ((bfd_int64_t) 1 << 63) +#define COERCE16(x) (((bfd_vma) (x) ^ 0x8000) - 0x8000) +#define COERCE32(x) (((bfd_vma) (x) ^ 0x80000000) - 0x80000000) #define COERCE64(x) \ - (((bfd_int64_t) (x) ^ EIGHT_GAZILLION) - EIGHT_GAZILLION) + (((bfd_uint64_t) (x) ^ ((bfd_uint64_t) 1 << 63)) - ((bfd_uint64_t) 1 << 63)) bfd_vma bfd_getb16 (const void *p) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index b6800f1..0b297cb 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,6 +1,12 @@ 2014-10-14 Alan Modra PR 17453 + * dwarf.c (read_leb128): Avoid signed overflow. + (read_debug_line_header): Likewise. + +2014-10-14 Alan Modra + + PR 17453 * readelf.c (process_program_headers): Correct fscanf format used for interpreter. diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 3f4095a..ee982de 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -259,7 +259,7 @@ read_leb128 (unsigned char *data, *length_return = num_read; if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40)) - result |= -1L << shift; + result |= (dwarf_vma) -1 << shift; return result; } @@ -2661,14 +2661,10 @@ read_debug_line_header (struct dwarf_section * section, linfo->li_max_ops_per_insn = 1; SAFE_BYTE_GET_AND_INC (linfo->li_default_is_stmt, hdrptr, 1, end); - SAFE_BYTE_GET_AND_INC (linfo->li_line_base, hdrptr, 1, end); + SAFE_SIGNED_BYTE_GET_AND_INC (linfo->li_line_base, hdrptr, 1, end); SAFE_BYTE_GET_AND_INC (linfo->li_line_range, hdrptr, 1, end); SAFE_BYTE_GET_AND_INC (linfo->li_opcode_base, hdrptr, 1, end); - /* Sign extend the line base field. */ - linfo->li_line_base <<= 24; - linfo->li_line_base >>= 24; - * end_of_sequence = data + linfo->li_length + initial_length_size; return hdrptr; } diff --git a/gas/ChangeLog b/gas/ChangeLog index 5eb4813..1b4fda9 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,15 @@ 2014-10-14 Alan Modra + PR 17453 + * config/tc-i386.c (fits_in_signed_long): Use unsigned param and + expression to avoid signed overflow. + (fits_in_signed_byte, fits_in_unsigned_byte, fits_in_unsigned_word, + fits_in_signed_word, fits_in_unsigned_long): Similarly. + * expr.c (operand <'-'>): Avoid signed overflow. + * read.c (s_comm_internal): Likewise. + +2014-10-14 Alan Modra + * config/tc-sparc.c (sparc_md_end): Fix unused variable warnings. 2014-10-09 Jose E. Marchesi diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 68ca7e4..38e9781 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -1946,47 +1946,46 @@ mode_from_disp_size (i386_operand_type t) } static INLINE int -fits_in_signed_byte (offsetT num) +fits_in_signed_byte (addressT num) { - return (num >= -128) && (num <= 127); + return num + 0x80 <= 0xff; } static INLINE int -fits_in_unsigned_byte (offsetT num) +fits_in_unsigned_byte (addressT num) { - return (num & 0xff) == num; + return num <= 0xff; } static INLINE int -fits_in_unsigned_word (offsetT num) +fits_in_unsigned_word (addressT num) { - return (num & 0xffff) == num; + return num <= 0xffff; } static INLINE int -fits_in_signed_word (offsetT num) +fits_in_signed_word (addressT num) { - return (-32768 <= num) && (num <= 32767); + return num + 0x8000 <= 0xffff; } static INLINE int -fits_in_signed_long (offsetT num ATTRIBUTE_UNUSED) +fits_in_signed_long (addressT num ATTRIBUTE_UNUSED) { #ifndef BFD64 return 1; #else - return (!(((offsetT) -1 << 31) & num) - || (((offsetT) -1 << 31) & num) == ((offsetT) -1 << 31)); + return num + 0x80000000 <= 0xffffffff; #endif } /* fits_in_signed_long() */ static INLINE int -fits_in_unsigned_long (offsetT num ATTRIBUTE_UNUSED) +fits_in_unsigned_long (addressT num ATTRIBUTE_UNUSED) { #ifndef BFD64 return 1; #else - return (num & (((offsetT) 2 << 31) - 1)) == num; + return num <= 0xffffffff; #endif } /* fits_in_unsigned_long() */ diff --git a/gas/expr.c b/gas/expr.c index eb7255f..0ccfbd3 100644 --- a/gas/expr.c +++ b/gas/expr.c @@ -1021,7 +1021,8 @@ operand (expressionS *expressionP, enum expr_mode mode) /* input_line_pointer -> char after operand. */ if (c == '-') { - expressionP->X_add_number = - expressionP->X_add_number; + expressionP->X_add_number + = - (addressT) expressionP->X_add_number; /* Notice: '-' may overflow: no warning is given. This is compatible with other people's assemblers. Sigh. */ diff --git a/gas/read.c b/gas/read.c index 2d5fdf1..9fd0335 100644 --- a/gas/read.c +++ b/gas/read.c @@ -1704,7 +1704,7 @@ s_comm_internal (int param, temp = get_absolute_expr (&exp); size = temp; - size &= ((offsetT) 2 << (stdoutput->arch_info->bits_per_address - 1)) - 1; + size &= ((addressT) 2 << (stdoutput->arch_info->bits_per_address - 1)) - 1; if (exp.X_op == O_absent) { as_bad (_("missing size expression")); diff --git a/gas/write.c b/gas/write.c index 0657b56..263b002 100644 --- a/gas/write.c +++ b/gas/write.c @@ -2309,7 +2309,7 @@ relax_align (register relax_addressT address, /* Address now. */ relax_addressT mask; relax_addressT new_address; - mask = ~((~0) << alignment); + mask = ~((relax_addressT) ~0 << alignment); new_address = (address + mask) & (~mask); #ifdef LINKER_RELAXING_SHRINKS_ONLY if (linkrelax) -- 2.7.4