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