@@ -123,42 +123,21 @@ psm_stack_manipulation! {
123
123
old_stack_limit: Option <usize >,
124
124
}
125
125
126
- impl Drop for StackRestoreGuard {
127
- fn drop( & mut self ) {
128
- unsafe {
129
- // FIXME: check the error code and decide what to do with it.
130
- // Perhaps a debug_assertion?
131
- libc:: munmap( self . new_stack, self . stack_bytes) ;
126
+ impl StackRestoreGuard {
127
+ #[ cfg( target_arch = "wasm32" ) ]
128
+ unsafe fn new( stack_bytes: usize , _page_size: usize ) -> StackRestoreGuard {
129
+ let layout = std:: alloc:: Layout :: from_size_align( stack_bytes, 16 ) . unwrap( ) ;
130
+ let ptr = std:: alloc:: alloc( layout) ;
131
+ assert!( !ptr. is_null( ) , "unable to allocate stack" ) ;
132
+ StackRestoreGuard {
133
+ new_stack: ptr as * mut _,
134
+ stack_bytes,
135
+ old_stack_limit: get_stack_limit( ) ,
132
136
}
133
- set_stack_limit( self . old_stack_limit) ;
134
137
}
135
- }
136
-
137
- fn _grow<F : FnOnce ( ) >( stack_size: usize , callback: F ) {
138
- // Calculate a number of pages we want to allocate for the new stack.
139
- // For maximum portability we want to produce a stack that is aligned to a page and has
140
- // a size that’s a multiple of page size. Furthermore we want to allocate two extras pages
141
- // for the stack guard. To achieve that we do our calculations in number of pages and
142
- // convert to bytes last.
143
- // FIXME: consider caching the page size.
144
- let page_size = unsafe { libc:: sysconf( libc:: _SC_PAGE_SIZE) } as usize ;
145
- let requested_pages = stack_size
146
- . checked_add( page_size - 1 )
147
- . expect( "unreasonably large stack requested" ) / page_size;
148
- let stack_pages = std:: cmp:: max( 1 , requested_pages) + 2 ;
149
- let stack_bytes = stack_pages. checked_mul( page_size)
150
- . expect( "unreasonably large stack requesteed" ) ;
151
138
152
- // Next, there are a couple of approaches to how we allocate the new stack. We take the
153
- // most obvious path and use `mmap`. We also `mprotect` a guard page into our
154
- // allocation.
155
- //
156
- // We use a guard pattern to ensure we deallocate the allocated stack when we leave
157
- // this function and also try to uphold various safety invariants required by `psm`
158
- // (such as not unwinding from the callback we pass to it).
159
- //
160
- // Other than that this code has no meaningful gotchas.
161
- unsafe {
139
+ #[ cfg( not( target_arch = "wasm32" ) ) ]
140
+ unsafe fn new( stack_bytes: usize , page_size: usize ) -> StackRestoreGuard {
162
141
let new_stack = libc:: mmap(
163
142
std:: ptr:: null_mut( ) ,
164
143
stack_bytes,
@@ -199,6 +178,55 @@ psm_stack_manipulation! {
199
178
drop( guard) ;
200
179
panic!( "unable to set stack permissions" )
201
180
}
181
+ guard
182
+ }
183
+ }
184
+
185
+ impl Drop for StackRestoreGuard {
186
+ fn drop( & mut self ) {
187
+ #[ cfg( target_arch = "wasm32" ) ]
188
+ unsafe {
189
+ std:: alloc:: dealloc(
190
+ self . new_stack as * mut u8 ,
191
+ std:: alloc:: Layout :: from_size_align_unchecked( self . stack_bytes, 16 ) ,
192
+ ) ;
193
+ }
194
+ #[ cfg( not( target_arch = "wasm32" ) ) ]
195
+ unsafe {
196
+ // FIXME: check the error code and decide what to do with it.
197
+ // Perhaps a debug_assertion?
198
+ libc:: munmap( self . new_stack, self . stack_bytes) ;
199
+ }
200
+ set_stack_limit( self . old_stack_limit) ;
201
+ }
202
+ }
203
+
204
+ fn _grow<F : FnOnce ( ) >( stack_size: usize , callback: F ) {
205
+ // Calculate a number of pages we want to allocate for the new stack.
206
+ // For maximum portability we want to produce a stack that is aligned to a page and has
207
+ // a size that’s a multiple of page size. Furthermore we want to allocate two extras pages
208
+ // for the stack guard. To achieve that we do our calculations in number of pages and
209
+ // convert to bytes last.
210
+ let page_size = page_size( ) ;
211
+ let requested_pages = stack_size
212
+ . checked_add( page_size - 1 )
213
+ . expect( "unreasonably large stack requested" ) / page_size;
214
+ let stack_pages = std:: cmp:: max( 1 , requested_pages) + 2 ;
215
+ let stack_bytes = stack_pages. checked_mul( page_size)
216
+ . expect( "unreasonably large stack requesteed" ) ;
217
+
218
+ // Next, there are a couple of approaches to how we allocate the new stack. We take the
219
+ // most obvious path and use `mmap`. We also `mprotect` a guard page into our
220
+ // allocation.
221
+ //
222
+ // We use a guard pattern to ensure we deallocate the allocated stack when we leave
223
+ // this function and also try to uphold various safety invariants required by `psm`
224
+ // (such as not unwinding from the callback we pass to it).
225
+ //
226
+ // Other than that this code has no meaningful gotchas.
227
+ unsafe {
228
+ let guard = StackRestoreGuard :: new( stack_bytes, page_size) ;
229
+ let above_guard_page = guard. new_stack. add( page_size) ;
202
230
set_stack_limit( Some ( above_guard_page as usize ) ) ;
203
231
let panic = psm:: on_stack( above_guard_page as * mut _, stack_size, move || {
204
232
std:: panic:: catch_unwind( std:: panic:: AssertUnwindSafe ( callback) ) . err( )
@@ -209,6 +237,14 @@ psm_stack_manipulation! {
209
237
}
210
238
}
211
239
}
240
+
241
+ fn page_size( ) -> usize {
242
+ // FIXME: consider caching the page size.
243
+ #[ cfg( not( target_arch = "wasm32" ) ) ]
244
+ unsafe { libc:: sysconf( libc:: _SC_PAGE_SIZE) as usize }
245
+ #[ cfg( target_arch = "wasm32" ) ]
246
+ { 65536 }
247
+ }
212
248
}
213
249
214
250
no {
0 commit comments