Skip to content

[WIP] Fix shadow stack synchronization issue in LLVM optimizations#2

Draft
Copilot wants to merge 1 commit intorelease/16.xfrom
copilot/fix-shadow-stack-sync-issue
Draft

[WIP] Fix shadow stack synchronization issue in LLVM optimizations#2
Copilot wants to merge 1 commit intorelease/16.xfrom
copilot/fix-shadow-stack-sync-issue

Conversation

Copy link
Copy Markdown

Copilot AI commented Jan 26, 2026

  • Identify where to insert a WebAssembly pass that spills pointer locals around calls at O2
  • Implement minimal spill pass to sync pointer locals to the stack before calls
  • Add targeted WebAssembly codegen test for shadow stack spill behavior
  • Re-run relevant WebAssembly codegen tests to confirm behavior
Original prompt

目前我的研究发现,使用默认优化时,llvm会保留将local值写回C栈(或者在wasm的语义下叫作Shadow Stack, 即以__stack__pointer为栈底指针的linear memory区域)的功能(可能对于函数传参的情况不完整?我不确定);在O2优化之后,同步机制就被破坏了,这是由于llvm里的一些优化,如mem2reg,破坏了一些东西,导致: 1. 可能是维护shadow stack的llvm ir缺失了 2. 可能是最后wasm生成器,无法从优化后的llvm ir里识别到,某一处需要插一个维护shadow stack的操作 这些功能将Shadow Stack同步功能破坏掉,导致无法正确写回,进而导致boehm gc失效。

换句话说,一个变量通过堆分配拿到的指针,只存在local寄存器里,没往linear memory的shadow stack(即(__stack_pointer + n)的内存区域)里同步。注意并不是在local里寄存的__stack_pointer本身没有向global同步。
举例:
对于函数cons:
// 链表节点结构体
typedef struct Node {
int value;
struct Node* next;
} Node;

// 创建新节点并添加到链表头部
Node* cons(int x, Node* xs) {
Node* n = GC_malloc(sizeof(Node));
n->value = x;
n->next = xs;
GC_gcollect();
return n;
}

下面是O0情况下的被编译成的wasm指令,可以看到新的node被存储到了__stack_pointer + n的区域
(func $cons (type 8) (param i32 i32) (result i32)
(local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)
global.get $__stack_pointer
local.set 2
i32.const 16
local.set 3
local.get 2
local.get 3
i32.sub
local.set 4
local.get 4
global.set $__stack_pointer
local.get 4
local.get 0
i32.store offset=12
local.get 4
local.get 1
i32.store offset=8
i32.const 8
local.set 5
local.get 5
call $GC_malloc
local.set 6
local.get 4
local.get 6
i32.store offset=4
local.get 4
i32.load offset=12
local.set 7
local.get 4
i32.load offset=4
local.set 8
local.get 8
local.get 7
i32.store
local.get 4
i32.load offset=8
local.set 9
local.get 4
i32.load offset=4
local.set 10
local.get 10
local.get 9
i32.store offset=4
call $GC_gcollect
local.get 4
i32.load offset=4
local.set 11
i32.const 16
local.set 12
local.get 4
local.get 12
i32.add
local.set 13
local.get 13
global.set $__stack_pointer
local.get 11
return)
但是在O2优化下,分配的local变量不会被同步到stack区域内,而只是存储在local里。
我现在希望能够在O2优化下也保留这个同步功能。请为我实现这个功能。
可以参考仓库:WebAssembly/binaryen仓库的SpillPointer.cpp。
目标仓库:PLUTOFX/llvm-project


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants