mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-17 19:23:25 +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() {
|
func (t *Task) Resume() {
|
||||||
// The current task must be saved and restored because this can nest on WASM with JS.
|
// The current task must be saved and restored because this can nest on WASM with JS.
|
||||||
prevTask := currentTask
|
prevTask := currentTask
|
||||||
|
if prevTask == nil {
|
||||||
|
// Save the system stack pointer.
|
||||||
|
saveStackPointer()
|
||||||
|
}
|
||||||
t.gcData.swap()
|
t.gcData.swap()
|
||||||
currentTask = t
|
currentTask = t
|
||||||
if !t.state.launched {
|
if !t.state.launched {
|
||||||
@@ -123,6 +127,9 @@ func (t *Task) Resume() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:linkname saveStackPointer runtime.saveStackPointer
|
||||||
|
func saveStackPointer()
|
||||||
|
|
||||||
//export tinygo_rewind
|
//export tinygo_rewind
|
||||||
func (*state) rewind()
|
func (*state) rewind()
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,14 @@ func align(ptr uintptr) uintptr {
|
|||||||
//export tinygo_getCurrentStackPointer
|
//export tinygo_getCurrentStackPointer
|
||||||
func getCurrentStackPointer() uintptr
|
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
|
// growHeap tries to grow the heap size. It returns true if it succeeds, false
|
||||||
// otherwise.
|
// otherwise.
|
||||||
func growHeap() bool {
|
func growHeap() bool {
|
||||||
|
|||||||
@@ -29,16 +29,6 @@ type stackChainObject struct {
|
|||||||
// - The system stack (aka startup stack) is not heap allocated, so even
|
// - The system stack (aka startup stack) is not heap allocated, so even
|
||||||
// though it may be referenced it will not be scanned by default.
|
// 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
|
// 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
|
// stackChainStart. Luckily we don't need to scan these, as these globals are
|
||||||
// stored on the goroutine stack and are therefore already getting scanned.
|
// stored on the goroutine stack and are therefore already getting scanned.
|
||||||
@@ -50,9 +40,18 @@ func markStack() {
|
|||||||
// live.
|
// live.
|
||||||
volatile.LoadUint32((*uint32)(unsafe.Pointer(&stackChainStart)))
|
volatile.LoadUint32((*uint32)(unsafe.Pointer(&stackChainStart)))
|
||||||
|
|
||||||
|
// Scan the system stack.
|
||||||
|
var sysSP uintptr
|
||||||
if task.OnSystemStack() {
|
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
|
// trackPointer is a stub function call inserted by the compiler during IR
|
||||||
|
|||||||
Reference in New Issue
Block a user