Fix bug in arm_push_dummy_call by -fsanitize=address
authorYao Qi <yao.qi@linaro.org>
Mon, 16 Nov 2015 14:44:19 +0000 (14:44 +0000)
committerYao Qi <yao.qi@linaro.org>
Mon, 16 Nov 2015 14:44:19 +0000 (14:44 +0000)
When I build GDB with -fsanitize=address, and run testsuite,
some gdb.base/*.exp test triggers the ERROR below,

=================================================================
==7646==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000242810 at pc 0x487844 bp 0x7fffe32e84e0 sp 0x7fffe32e84d8
READ of size 4 at 0x603000242810 thread T0
    #0 0x487843 in push_stack_item /home/yao/SourceCode/gnu/gdb/git/gdb/arm-tdep.c:3405
    #1 0x48998a in arm_push_dummy_call /home/yao/SourceCode/gnu/gdb/git/gdb/arm-tdep.c:3960

In that path, GDB passes value on stack, in an INT_REGISTER_SIZE slot,
but the value contents' length can be less than INT_REGISTER_SIZE, so
the contents will be accessed out of the bound.  This patch adds an
array buf[INT_REGISTER_SIZE], and copy val to buf before writing them
to stack.

gdb:

2015-11-16  Yao Qi  <yao.qi@linaro.org>

* arm-tdep.c (arm_push_dummy_call): New array buf.  Store regval
to buf.  Pass buf instead of val to push_stack_item.

gdb/ChangeLog
gdb/arm-tdep.c

index e48ffa1..2b2409a 100644 (file)
@@ -1,3 +1,8 @@
+2015-11-16  Yao Qi  <yao.qi@linaro.org>
+
+       * arm-tdep.c (arm_push_dummy_call): New array buf.  Store regval
+       to buf.  Pass buf instead of val to push_stack_item.
+
 2015-11-13  Yao Qi  <yao.qi@linaro.org>
 
        PR tdep/19051
index b8f84ce..ef1a007 100644 (file)
@@ -3925,13 +3925,13 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       while (len > 0)
        {
          int partial_len = len < INT_REGISTER_SIZE ? len : INT_REGISTER_SIZE;
+         CORE_ADDR regval
+           = extract_unsigned_integer (val, partial_len, byte_order);
 
          if (may_use_core_reg && argreg <= ARM_LAST_ARG_REGNUM)
            {
              /* The argument is being passed in a general purpose
                 register.  */
-             CORE_ADDR regval
-               = extract_unsigned_integer (val, partial_len, byte_order);
              if (byte_order == BFD_ENDIAN_BIG)
                regval <<= (INT_REGISTER_SIZE - partial_len) * 8;
              if (arm_debug)
@@ -3945,11 +3945,16 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
            }
          else
            {
+             gdb_byte buf[INT_REGISTER_SIZE];
+
+             memset (buf, 0, sizeof (buf));
+             store_unsigned_integer (buf, partial_len, byte_order, regval);
+
              /* Push the arguments onto the stack.  */
              if (arm_debug)
                fprintf_unfiltered (gdb_stdlog, "arg %d @ sp + %d\n",
                                    argnum, nstack);
-             si = push_stack_item (si, val, INT_REGISTER_SIZE);
+             si = push_stack_item (si, buf, INT_REGISTER_SIZE);
              nstack += INT_REGISTER_SIZE;
            }