mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
runtime (wasm): scan the system stack
This saves the system stack pointer into a global and uses it to scan. It should fix some use-after-free issues?
This commit is contained in:
@@ -108,6 +108,10 @@ func (*stackState) unwind()
|
||||
func (t *Task) Resume() {
|
||||
// The current task must be saved and restored because this can nest on WASM with JS.
|
||||
prevTask := currentTask
|
||||
if prevTask == nil {
|
||||
// Save the system stack pointer.
|
||||
saveStackPointer()
|
||||
}
|
||||
t.gcData.swap()
|
||||
currentTask = t
|
||||
if !t.state.launched {
|
||||
@@ -123,6 +127,9 @@ func (t *Task) Resume() {
|
||||
}
|
||||
}
|
||||
|
||||
//go:linkname saveStackPointer runtime.saveStackPointer
|
||||
func saveStackPointer()
|
||||
|
||||
//export tinygo_rewind
|
||||
func (*state) rewind()
|
||||
|
||||
|
||||
@@ -73,6 +73,14 @@ func align(ptr uintptr) uintptr {
|
||||
//export tinygo_getCurrentStackPointer
|
||||
func getCurrentStackPointer() uintptr
|
||||
|
||||
// savedStackPointer is used to save the system stack pointer while in a goroutine.
|
||||
var savedStackPointer uintptr
|
||||
|
||||
// saveStackPointer is called by internal/task.state.Resume() to save the stack pointer before entering a goroutine from the system stack.
|
||||
func saveStackPointer() {
|
||||
savedStackPointer = getCurrentStackPointer()
|
||||
}
|
||||
|
||||
// growHeap tries to grow the heap size. It returns true if it succeeds, false
|
||||
// otherwise.
|
||||
func growHeap() bool {
|
||||
|
||||
@@ -29,16 +29,6 @@ type stackChainObject struct {
|
||||
// - The system stack (aka startup stack) is not heap allocated, so even
|
||||
// though it may be referenced it will not be scanned by default.
|
||||
//
|
||||
// Therefore, we only need to scan the system stack.
|
||||
// It is relatively easy to scan the system stack while we're on it: we can
|
||||
// simply read __stack_pointer and __global_base and scan the area in between.
|
||||
// Unfortunately, it's hard to get the system stack pointer while we're on a
|
||||
// goroutine stack. But when we're on a goroutine stack, the system stack is in
|
||||
// the scheduler which means there shouldn't be anything on the system stack
|
||||
// anyway.
|
||||
// ...I hope this assumption holds, otherwise we will need to store the system
|
||||
// stack in a global or something.
|
||||
//
|
||||
// The compiler also inserts code to store all globals in a chain via
|
||||
// stackChainStart. Luckily we don't need to scan these, as these globals are
|
||||
// stored on the goroutine stack and are therefore already getting scanned.
|
||||
@@ -50,9 +40,18 @@ func markStack() {
|
||||
// live.
|
||||
volatile.LoadUint32((*uint32)(unsafe.Pointer(&stackChainStart)))
|
||||
|
||||
// Scan the system stack.
|
||||
var sysSP uintptr
|
||||
if task.OnSystemStack() {
|
||||
markRoots(getCurrentStackPointer(), stackTop)
|
||||
// We are on the system stack.
|
||||
// Use the current stack pointer.
|
||||
sysSP = getCurrentStackPointer()
|
||||
} else {
|
||||
// We are in a goroutine.
|
||||
// Use the saved stack pointer.
|
||||
sysSP = savedStackPointer
|
||||
}
|
||||
markRoots(sysSP, stackTop)
|
||||
}
|
||||
|
||||
// trackPointer is a stub function call inserted by the compiler during IR
|
||||
|
||||
Reference in New Issue
Block a user