Risc-V ILP32E ABI requires only a 4-byte stack alignment, rather than 16
as used on all other Risc-V ABIs.

That means any pointers to data on the stack are only going to be 4-byte
aligned, independent of the underlying representation.

When ubsan generates pointer alignment checks, it uses the basic type
alignment value (found in mode_base_align), and on Risc-V, those are
set to the size of the type, at least for types <= 16 bytes.

This sample code shows the issue:

        int
        bar(unsigned long long *offsetp)
        {
                *offsetp += 8;
                return 0;
        }

Compiled for ilp32e:

        $ cc1 -march=rv32e -mabi=ilp32e -O2 -fsanitize=undefined 
riscv-align-bug.c

The compiler emits:

        bar:
                addi    sp,sp,-16
                sw      ra,12(sp)
                mv      a1,a0
                beq     a0,zero,.L2
                andi    a5,a0,7         <- Checking lower 3 bits for 8-byte 
alignment
                bne     a5,zero,.L2
        .L3:
                ...

Fixing this is relatively straightforward; simply relax the alignment
constrants in the ubsan code to no more than STACK_BOUNDARY bits.

I'm unsure whether to fix the ubsan code or to adjust the alignment
requirements in riscv-modes.def:

        ADJUST_ALIGNMENT (DI, riscv_abi == ABI_ILP32E ? UNITS_PER_WORD : 
mode_base_align[E_DImode]);
        ADJUST_ALIGNMENT (TI, riscv_abi == ABI_ILP32E ? UNITS_PER_WORD : 
mode_base_align[E_TImode]);
        ...

Guidance here would be appreciated.

Signed-off-by: Keith Packard <[email protected]>
---
 gcc/ubsan.cc | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/gcc/ubsan.cc b/gcc/ubsan.cc
index 79a863b46ce..27906dd1704 100644
--- a/gcc/ubsan.cc
+++ b/gcc/ubsan.cc
@@ -1450,6 +1450,13 @@ instrument_mem_ref (tree mem, tree base, 
gimple_stmt_iterator *iter,
       align = min_align_of_type (TREE_TYPE (base));
       if (align <= 1)
        align = 0;
+      /*
+       * Any pointer might reference data on the stack, which is
+       * only constrained to STACK_BOUNDARY. If that is less strict
+       * than the type alignment, relax our checks to that value
+       */
+      if (align > STACK_BOUNDARY / BITS_PER_UNIT)
+       align = STACK_BOUNDARY / BITS_PER_UNIT;
     }
   if (align == 0)
     {
-- 
2.53.0

Reply via email to