59
59
# include <sanitizer/common_interface_defs.h>
60
60
#endif
61
61
62
+ /* Encapsulates the fiber C stack with extension for debugging tools. */
63
+ struct _zend_fiber_stack {
64
+ void * pointer ;
65
+ size_t size ;
66
+
67
+ #ifdef HAVE_VALGRIND
68
+ unsigned int valgrind_stack_id ;
69
+ #endif
70
+
71
+ #ifdef __SANITIZE_ADDRESS__
72
+ const void * asan_pointer ;
73
+ size_t asan_size ;
74
+ #endif
75
+ };
76
+
62
77
/* boost_context_data is our customized definition of struct transfer_t as
63
78
* provided by boost.context in fcontext.hpp:
64
79
*
@@ -102,25 +117,25 @@ static size_t zend_fiber_get_page_size(void)
102
117
return page_size ;
103
118
}
104
119
105
- static bool zend_fiber_stack_allocate ( zend_fiber_stack * stack , size_t size )
120
+ static zend_fiber_stack * zend_fiber_stack_allocate ( size_t size )
106
121
{
107
122
void * pointer ;
108
123
const size_t page_size = zend_fiber_get_page_size ();
109
124
110
125
ZEND_ASSERT (size >= page_size + ZEND_FIBER_GUARD_PAGES * page_size );
111
126
112
- stack -> size = (size + page_size - 1 ) / page_size * page_size ;
113
- const size_t msize = stack -> size + ZEND_FIBER_GUARD_PAGES * page_size ;
127
+ const size_t stack_size = (size + page_size - 1 ) / page_size * page_size ;
128
+ const size_t alloc_size = stack_size + ZEND_FIBER_GUARD_PAGES * page_size ;
114
129
115
130
#ifdef ZEND_WIN32
116
- pointer = VirtualAlloc (0 , msize , MEM_COMMIT , PAGE_READWRITE );
131
+ pointer = VirtualAlloc (0 , alloc_size , MEM_COMMIT , PAGE_READWRITE );
117
132
118
133
if (!pointer ) {
119
134
DWORD err = GetLastError ();
120
135
char * errmsg = php_win32_error_to_msg (err );
121
136
zend_throw_exception_ex (NULL , 0 , "Fiber make context failed: VirtualAlloc failed: [0x%08lx] %s" , err , errmsg [0 ] ? errmsg : "Unknown" );
122
137
php_win32_error_msg_free (errmsg );
123
- return false ;
138
+ return NULL ;
124
139
}
125
140
126
141
# if ZEND_FIBER_GUARD_PAGES
@@ -132,49 +147,48 @@ static bool zend_fiber_stack_allocate(zend_fiber_stack *stack, size_t size)
132
147
zend_throw_exception_ex (NULL , 0 , "Fiber protect stack failed: VirtualProtect failed: [0x%08lx] %s" , err , errmsg [0 ] ? errmsg : "Unknown" );
133
148
php_win32_error_msg_free (errmsg );
134
149
VirtualFree (pointer , 0 , MEM_RELEASE );
135
- return false ;
150
+ return NULL ;
136
151
}
137
152
# endif
138
153
#else
139
- pointer = mmap (NULL , msize , PROT_READ | PROT_WRITE , MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK , -1 , 0 );
154
+ pointer = mmap (NULL , alloc_size , PROT_READ | PROT_WRITE , MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK , -1 , 0 );
140
155
141
156
if (pointer == MAP_FAILED ) {
142
157
zend_throw_exception_ex (NULL , 0 , "Fiber make context failed: mmap failed: %s (%d)" , strerror (errno ), errno );
143
- return false ;
158
+ return NULL ;
144
159
}
145
160
146
161
# if ZEND_FIBER_GUARD_PAGES
147
162
if (mprotect (pointer , ZEND_FIBER_GUARD_PAGES * page_size , PROT_NONE ) < 0 ) {
148
163
zend_throw_exception_ex (NULL , 0 , "Fiber protect stack failed: mmap failed: %s (%d)" , strerror (errno ), errno );
149
- munmap (pointer , msize );
150
- return false ;
164
+ munmap (pointer , alloc_size );
165
+ return NULL ;
151
166
}
152
167
# endif
153
168
#endif
154
169
170
+ zend_fiber_stack * stack = emalloc (sizeof (zend_fiber_stack ));
171
+
155
172
stack -> pointer = (void * ) ((uintptr_t ) pointer + ZEND_FIBER_GUARD_PAGES * page_size );
173
+ stack -> size = stack_size ;
156
174
157
175
#ifdef VALGRIND_STACK_REGISTER
158
176
uintptr_t base = (uintptr_t ) stack -> pointer ;
159
- stack -> valgrind = VALGRIND_STACK_REGISTER (base , base + stack -> size );
177
+ stack -> valgrind_stack_id = VALGRIND_STACK_REGISTER (base , base + stack -> size );
160
178
#endif
161
179
162
180
#ifdef __SANITIZE_ADDRESS__
163
- stack -> prior_pointer = stack -> pointer ;
164
- stack -> prior_size = stack -> size ;
181
+ stack -> asan_pointer = stack -> pointer ;
182
+ stack -> asan_size = stack -> size ;
165
183
#endif
166
184
167
- return true ;
185
+ return stack ;
168
186
}
169
187
170
188
static void zend_fiber_stack_free (zend_fiber_stack * stack )
171
189
{
172
- if (!stack -> pointer ) {
173
- return ;
174
- }
175
-
176
190
#ifdef VALGRIND_STACK_DEREGISTER
177
- VALGRIND_STACK_DEREGISTER (stack -> valgrind );
191
+ VALGRIND_STACK_DEREGISTER (stack -> valgrind_stack_id );
178
192
#endif
179
193
180
194
const size_t page_size = zend_fiber_get_page_size ();
@@ -187,15 +201,15 @@ static void zend_fiber_stack_free(zend_fiber_stack *stack)
187
201
munmap (pointer , stack -> size + ZEND_FIBER_GUARD_PAGES * page_size );
188
202
#endif
189
203
190
- stack -> pointer = NULL ;
204
+ efree ( stack ) ;
191
205
}
192
206
193
207
static ZEND_NORETURN void zend_fiber_trampoline (boost_context_data data )
194
208
{
195
209
zend_fiber_context * from = data .transfer -> context ;
196
210
197
211
#ifdef __SANITIZE_ADDRESS__
198
- __sanitizer_finish_switch_fiber (NULL , & from -> stack . prior_pointer , & from -> stack . prior_size );
212
+ __sanitizer_finish_switch_fiber (NULL , & from -> stack -> asan_pointer , & from -> stack -> asan_size );
199
213
#endif
200
214
201
215
/* Get a hold of the context that resumed us and update it's handle to allow for symmetric coroutines. */
@@ -218,14 +232,16 @@ static ZEND_NORETURN void zend_fiber_trampoline(boost_context_data data)
218
232
219
233
ZEND_API bool zend_fiber_init_context (zend_fiber_context * context , void * kind , zend_fiber_coroutine coroutine , size_t stack_size )
220
234
{
221
- if (UNEXPECTED (!zend_fiber_stack_allocate (& context -> stack , stack_size ))) {
235
+ context -> stack = zend_fiber_stack_allocate (stack_size );
236
+
237
+ if (UNEXPECTED (!context -> stack )) {
222
238
return false;
223
239
}
224
240
225
241
// Stack grows down, calculate the top of the stack. make_fcontext then shifts pointer to lower 16-byte boundary.
226
- void * stack = (void * ) ((uintptr_t ) context -> stack . pointer + context -> stack . size );
242
+ void * stack = (void * ) ((uintptr_t ) context -> stack -> pointer + context -> stack -> size );
227
243
228
- context -> handle = make_fcontext (stack , context -> stack . size , zend_fiber_trampoline );
244
+ context -> handle = make_fcontext (stack , context -> stack -> size , zend_fiber_trampoline );
229
245
ZEND_ASSERT (context -> handle != NULL && "make_fcontext() never returns NULL" );
230
246
231
247
context -> kind = kind ;
@@ -236,7 +252,7 @@ ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, void *kind, z
236
252
237
253
ZEND_API void zend_fiber_destroy_context (zend_fiber_context * context )
238
254
{
239
- zend_fiber_stack_free (& context -> stack );
255
+ zend_fiber_stack_free (context -> stack );
240
256
}
241
257
242
258
ZEND_API void zend_fiber_switch_context (zend_fiber_transfer * transfer )
@@ -278,8 +294,8 @@ ZEND_API void zend_fiber_switch_context(zend_fiber_transfer *transfer)
278
294
void * fake_stack = NULL ;
279
295
__sanitizer_start_switch_fiber (
280
296
from -> status != ZEND_FIBER_STATUS_DEAD ? & fake_stack : NULL ,
281
- to -> stack . prior_pointer ,
282
- to -> stack . prior_size );
297
+ to -> stack -> asan_pointer ,
298
+ to -> stack -> asan_size );
283
299
#endif
284
300
285
301
boost_context_data data = jump_fcontext (to -> handle , transfer );
@@ -292,7 +308,7 @@ ZEND_API void zend_fiber_switch_context(zend_fiber_transfer *transfer)
292
308
to -> handle = data .handle ;
293
309
294
310
#ifdef __SANITIZE_ADDRESS__
295
- __sanitizer_finish_switch_fiber (fake_stack , & to -> stack . prior_pointer , & to -> stack . prior_size );
311
+ __sanitizer_finish_switch_fiber (fake_stack , & to -> stack -> asan_pointer , & to -> stack -> asan_size );
296
312
#endif
297
313
298
314
EG (current_fiber_context ) = from ;
@@ -741,6 +757,11 @@ void zend_fiber_init(void)
741
757
{
742
758
zend_fiber_context * context = ecalloc (1 , sizeof (zend_fiber_context ));
743
759
760
+ #ifdef __SANITIZE_ADDRESS__
761
+ // Main fiber context stack is only accessed if ASan is enabled.
762
+ context -> stack = emalloc (sizeof (zend_fiber_stack ));
763
+ #endif
764
+
744
765
context -> status = ZEND_FIBER_STATUS_RUNNING ;
745
766
746
767
EG (main_fiber_context ) = context ;
@@ -750,5 +771,8 @@ void zend_fiber_init(void)
750
771
751
772
void zend_fiber_shutdown (void )
752
773
{
774
+ #ifdef __SANITIZE_ADDRESS__
775
+ efree (EG (main_fiber_context )-> stack );
776
+ #endif
753
777
efree (EG (main_fiber_context ));
754
778
}
0 commit comments