Skip to content

[RISCV] -fstack-clash-protection generate incomplete probes for large outgoing frames in non-entry blocks #195454

Description

@CSharperMantle

This program:

target triple = "riscv64-unknown-linux-gnu"

define void @f(i64 %n) #0 {
entry:
  %v = alloca i32, i64 %n, align 4
  call void @g(ptr %v, [3000 x i64] poison)
  ret void
}

declare void @g(ptr, [3000 x i64])

attributes #0 = { uwtable "frame-pointer"="none" "probe-stack"="inline-asm" }

... generates the following output on Clang 22.1.3 for riscv64-unknown-linux-gnu:

$ clang --version
clang version 22.1.3
Target: loongarch64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$ clang -target riscv64-unknown-linux-gnu -O2 -S -o - /tmp/rv-clash-prot.ll
        .attribute      4, 16
        .attribute      5, "rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0"
        .file   "rv-clash-prot.ll"
        .text
        .globl  f                               # -- Begin function f
        .p2align        1
        .type   f,@function
f:                                      # @f
        .cfi_startproc
# %bb.0:                                # %entry
        addi    sp, sp, -16
        .cfi_def_cfa_offset 16
        sd      zero, 0(sp)
        sd      ra, 8(sp)                       # 8-byte Folded Spill
        sd      s0, 0(sp)                       # 8-byte Folded Spill
        .cfi_offset ra, -8
        .cfi_offset s0, -16
        addi    s0, sp, 16
        .cfi_def_cfa s0, 0
        slli    a0, a0, 2
        addi    a0, a0, 15
        andi    a0, a0, -16
        sub     a0, sp, a0
        lui     a1, 1
.LBB0_1:                                # %entry
                                        # =>This Inner Loop Header: Depth=1
        sub     sp, sp, a1
        sd      zero, 0(sp)
        blt     a0, sp, .LBB0_1
# %bb.2:                                # %entry
        mv      sp, a0
        lui     a1, 5
        sub     t1, sp, a1

        addi    sp, sp, -2048
        addi    sp, sp, -1424
        sd      zero, 0(sp)
        call    g
        lui     a0, 6
        addi    a0, a0, -624
        add     sp, sp, a0
        addi    sp, s0, -16
        .cfi_def_cfa sp, 16
        ld      ra, 8(sp)                       # 8-byte Folded Reload
        ld      s0, 0(sp)                       # 8-byte Folded Reload
        .cfi_restore ra
        .cfi_restore s0
        addi    sp, sp, 16
        .cfi_def_cfa_offset 0
        ret
.Lfunc_end0:
        .size   f, .Lfunc_end0-f
        .cfi_endproc
                                        # -- End function
        .section        ".note.GNU-stack","",@progbits
        .addrsig

Note that the second stack probing loop is incomplete, leaving sp half-updated and thus higher than it should be:

# %bb.2:                                # %entry
        mv      sp, a0
        lui     a1, 5
        sub     t1, sp, a1

        addi    sp, sp, -2048
        addi    sp, sp, -1424
        sd      zero, 0(sp)
        call    g

This is because PrologEpilogInserter only scans SaveBlocks for stack probe insertion, thus all PROBED_STACKALLOC pseudoinstructions in non-entry blocks are discarded. See #195454 (comment)

for (MachineBasicBlock *SaveBlock : SaveBlocks)
TFI.inlineStackProbe(MF, *SaveBlock);

Metadata

Metadata

Assignees

No one assigned

    Type

    Fields

    No fields configured for Bug.

    Projects

    Status
    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions