@@ -35,11 +35,16 @@ type state struct {
35
35
type stackState struct {
36
36
// asyncify is the stack pointer of the asyncify stack.
37
37
// This starts from the bottom and grows upwards.
38
- asyncifysp uintptr
38
+ asyncifysp unsafe. Pointer
39
39
40
40
// asyncify is stack pointer of the C stack.
41
41
// This starts from the top and grows downwards.
42
- csp uintptr
42
+ csp unsafe.Pointer
43
+
44
+ // Pointer to the first (lowest address) of the stack. It must never be
45
+ // overwritten. It can be checked from time to time to see whether a stack
46
+ // overflow happened in the past.
47
+ canaryPtr * uintptr
43
48
}
44
49
45
50
// start creates and starts a new goroutine with the given function and arguments.
@@ -63,12 +68,18 @@ func (s *state) initialize(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
63
68
s .args = args
64
69
65
70
// Create a stack.
66
- stack := make ([]uintptr , stackSize / unsafe .Sizeof (uintptr (0 )))
71
+ stack := runtime_alloc (stackSize , nil )
72
+
73
+ // Set up the stack canary, a random number that should be checked when
74
+ // switching from the task back to the scheduler. The stack canary pointer
75
+ // points to the first word of the stack. If it has changed between now and
76
+ // the next stack switch, there was a stack overflow.
77
+ s .canaryPtr = (* uintptr )(stack )
78
+ * s .canaryPtr = stackCanary
67
79
68
80
// Calculate stack base addresses.
69
- s .asyncifysp = uintptr (unsafe .Pointer (& stack [0 ]))
70
- s .csp = uintptr (unsafe .Pointer (& stack [0 ])) + uintptr (len (stack ))* unsafe .Sizeof (uintptr (0 ))
71
- stack [0 ] = stackCanary
81
+ s .asyncifysp = unsafe .Add (stack , unsafe .Sizeof (uintptr (0 )))
82
+ s .csp = unsafe .Add (stack , stackSize )
72
83
}
73
84
74
85
//go:linkname runqueuePushBack runtime.runqueuePushBack
@@ -85,14 +96,11 @@ func Current() *Task {
85
96
// Pause suspends the current task and returns to the scheduler.
86
97
// This function may only be called when running on a goroutine stack, not when running on the system stack.
87
98
func Pause () {
88
- // This is mildly unsafe but this is also the only place we can do this.
89
- if * (* uintptr )(unsafe .Pointer (currentTask .state .asyncifysp )) != stackCanary {
99
+ if * currentTask .state .canaryPtr != stackCanary {
90
100
runtimePanic ("stack overflow" )
91
101
}
92
102
93
103
currentTask .state .unwind ()
94
-
95
- * (* uintptr )(unsafe .Pointer (currentTask .state .asyncifysp )) = stackCanary
96
104
}
97
105
98
106
//export tinygo_unwind
@@ -113,7 +121,7 @@ func (t *Task) Resume() {
113
121
}
114
122
currentTask = prevTask
115
123
t .gcData .swap ()
116
- if t .state .asyncifysp > t .state .csp {
124
+ if uintptr ( t .state .asyncifysp ) > uintptr ( t .state .csp ) {
117
125
runtimePanic ("stack overflow" )
118
126
}
119
127
}
0 commit comments