@@ -120,135 +120,151 @@ void v8js_v8_call(v8js_ctx *c, zval **return_value,
120
120
{
121
121
char *tz = NULL ;
122
122
123
- V8JS_CTX_PROLOGUE (c);
123
+ // hold extra reference on v8 instance as long as we call into V8 (issue #472)
124
+ zend_object *obj = v8js_ctx_to_zend_object (c);
125
+ zval zv_v8inst;
126
+ ZVAL_OBJ (&zv_v8inst, obj);
127
+ Z_ADDREF_P (&zv_v8inst);
124
128
125
- V8JSG (timer_mutex).lock ();
126
- c->time_limit_hit = false ;
127
- c->memory_limit_hit = false ;
128
- V8JSG (timer_mutex).unlock ();
129
+ {
130
+ V8JS_CTX_PROLOGUE (c);
129
131
130
- /* Catch JS exceptions */
131
- v8::TryCatch try_catch (isolate);
132
+ V8JSG (timer_mutex).lock ();
133
+ c->time_limit_hit = false ;
134
+ c->memory_limit_hit = false ;
135
+ V8JSG (timer_mutex).unlock ();
132
136
133
- /* Set flags for runtime use */
134
- c-> flags = flags ;
137
+ /* Catch JS exceptions */
138
+ v8::TryCatch try_catch (isolate) ;
135
139
136
- /* Check if timezone has been changed and notify V8 */
137
- tz = getenv ( " TZ " ) ;
140
+ /* Set flags for runtime use */
141
+ c-> flags = flags ;
138
142
139
- if (tz != NULL ) {
140
- if (c->tz == NULL ) {
141
- c->tz = strdup (tz);
142
- }
143
- else if (strcmp (c->tz , tz) != 0 ) {
144
- c->isolate ->DateTimeConfigurationChangeNotification ();
143
+ /* Check if timezone has been changed and notify V8 */
144
+ tz = getenv (" TZ" );
145
145
146
- free (c->tz );
147
- c->tz = strdup (tz);
148
- }
149
- }
146
+ if (tz != NULL ) {
147
+ if (c->tz == NULL ) {
148
+ c->tz = strdup (tz);
149
+ }
150
+ else if (strcmp (c->tz , tz) != 0 ) {
151
+ c->isolate ->DateTimeConfigurationChangeNotification ();
150
152
151
- if (time_limit > 0 || memory_limit > 0 ) {
152
- // If timer thread is not running then start it
153
- if (!V8JSG (timer_thread)) {
154
- // If not, start timer thread
155
- V8JSG (timer_thread) = new std::thread (v8js_timer_thread, ZEND_MODULE_GLOBALS_BULK (v8js));
153
+ free (c->tz );
154
+ c->tz = strdup (tz);
155
+ }
156
156
}
157
- }
158
157
159
- /* Always pass the timer to the stack so there can be follow-up changes to
160
- * the time & memory limit. */
161
- v8js_timer_push (time_limit, memory_limit, c);
158
+ if (time_limit > 0 || memory_limit > 0 ) {
159
+ // If timer thread is not running then start it
160
+ if (!V8JSG (timer_thread)) {
161
+ // If not, start timer thread
162
+ V8JSG (timer_thread) = new std::thread (v8js_timer_thread, ZEND_MODULE_GLOBALS_BULK (v8js));
163
+ }
164
+ }
162
165
163
- /* Execute script */
164
- c->in_execution ++;
165
- v8::MaybeLocal<v8::Value> result = v8_call (c->isolate );
166
- c->in_execution --;
166
+ /* Always pass the timer to the stack so there can be follow-up changes to
167
+ * the time & memory limit. */
168
+ v8js_timer_push (time_limit, memory_limit, c);
167
169
168
- /* Pop our context from the stack and read (possibly updated) limits
169
- * into local variables. */
170
- V8JSG (timer_mutex).lock ();
171
- v8js_timer_ctx *timer_ctx = V8JSG (timer_stack).front ();
172
- V8JSG (timer_stack).pop_front ();
173
- V8JSG (timer_mutex).unlock ();
170
+ /* Execute script */
171
+ c->in_execution ++;
172
+ v8::MaybeLocal<v8::Value> result = v8_call (c->isolate );
173
+ c->in_execution --;
174
174
175
- time_limit = timer_ctx->time_limit ;
176
- memory_limit = timer_ctx->memory_limit ;
175
+ /* Pop our context from the stack and read (possibly updated) limits
176
+ * into local variables. */
177
+ V8JSG (timer_mutex).lock ();
178
+ v8js_timer_ctx *timer_ctx = V8JSG (timer_stack).front ();
179
+ V8JSG (timer_stack).pop_front ();
180
+ V8JSG (timer_mutex).unlock ();
177
181
178
- efree (timer_ctx);
182
+ time_limit = timer_ctx->time_limit ;
183
+ memory_limit = timer_ctx->memory_limit ;
179
184
180
- if (!V8JSG (fatal_error_abort)) {
181
- char exception_string[64 ];
185
+ efree (timer_ctx);
182
186
183
- if (c->time_limit_hit ) {
184
- // Execution has been terminated due to time limit
185
- sprintf (exception_string, " Script time limit of %lu milliseconds exceeded" , time_limit);
186
- zend_throw_exception (php_ce_v8js_time_limit_exception, exception_string, 0 );
187
- return ;
188
- }
187
+ if (!V8JSG (fatal_error_abort)) {
188
+ char exception_string[64 ];
189
189
190
- if (memory_limit && !c->memory_limit_hit ) {
191
- // Re-check memory limit (very short executions might never be hit by timer thread)
192
- v8::HeapStatistics hs;
193
- isolate->GetHeapStatistics (&hs);
190
+ if (c->time_limit_hit ) {
191
+ // Execution has been terminated due to time limit
192
+ sprintf (exception_string, " Script time limit of %lu milliseconds exceeded" , time_limit);
193
+ zend_throw_exception (php_ce_v8js_time_limit_exception, exception_string, 0 );
194
+ zval_ptr_dtor (&zv_v8inst);
195
+ return ;
196
+ }
194
197
195
- if (hs.used_heap_size () > memory_limit) {
196
- isolate->LowMemoryNotification ();
198
+ if (memory_limit && !c->memory_limit_hit ) {
199
+ // Re-check memory limit (very short executions might never be hit by timer thread)
200
+ v8::HeapStatistics hs;
197
201
isolate->GetHeapStatistics (&hs);
198
202
199
203
if (hs.used_heap_size () > memory_limit) {
200
- c->memory_limit_hit = true ;
204
+ isolate->LowMemoryNotification ();
205
+ isolate->GetHeapStatistics (&hs);
206
+
207
+ if (hs.used_heap_size () > memory_limit) {
208
+ c->memory_limit_hit = true ;
209
+ }
201
210
}
202
211
}
203
- }
204
212
205
- if (c->memory_limit_hit ) {
206
- // Execution has been terminated due to memory limit
207
- sprintf (exception_string, " Script memory limit of %lu bytes exceeded" , memory_limit);
208
- zend_throw_exception (php_ce_v8js_memory_limit_exception, exception_string, 0 );
209
- return ;
210
- }
211
-
212
- if (!try_catch.CanContinue ()) {
213
- // At this point we can't re-throw the exception
214
- return ;
215
- }
216
-
217
- /* There was pending exception left from earlier executions -> throw to PHP */
218
- if (Z_TYPE (c->pending_exception ) == IS_OBJECT) {
219
- zend_throw_exception_object (&c->pending_exception );
220
- ZVAL_NULL (&c->pending_exception );
221
- }
213
+ if (c->memory_limit_hit ) {
214
+ // Execution has been terminated due to memory limit
215
+ sprintf (exception_string, " Script memory limit of %lu bytes exceeded" , memory_limit);
216
+ zend_throw_exception (php_ce_v8js_memory_limit_exception, exception_string, 0 );
217
+ zval_ptr_dtor (&zv_v8inst);
218
+ return ;
219
+ }
222
220
223
- /* Handle runtime JS exceptions */
224
- if (try_catch.HasCaught ()) {
221
+ if (!try_catch.CanContinue ()) {
222
+ // At this point we can't re-throw the exception
223
+ zval_ptr_dtor (&zv_v8inst);
224
+ return ;
225
+ }
225
226
226
- /* Pending exceptions are set only in outer caller, inner caller exceptions are always rethrown */
227
- if (c->in_execution < 1 ) {
227
+ /* There was pending exception left from earlier executions -> throw to PHP */
228
+ if (Z_TYPE (c->pending_exception ) == IS_OBJECT) {
229
+ zend_throw_exception_object (&c->pending_exception );
230
+ ZVAL_NULL (&c->pending_exception );
231
+ }
228
232
229
- /* Report immediately if report_uncaught is true */
230
- if (c->report_uncaught ) {
231
- v8js_throw_script_exception (c->isolate , &try_catch);
232
- return ;
233
+ /* Handle runtime JS exceptions */
234
+ if (try_catch.HasCaught ()) {
235
+
236
+ /* Pending exceptions are set only in outer caller, inner caller exceptions are always rethrown */
237
+ if (c->in_execution < 1 ) {
238
+
239
+ /* Report immediately if report_uncaught is true */
240
+ if (c->report_uncaught ) {
241
+ v8js_throw_script_exception (c->isolate , &try_catch);
242
+ zval_ptr_dtor (&zv_v8inst);
243
+ return ;
244
+ }
245
+
246
+ /* Exception thrown from JS, preserve it for future execution */
247
+ if (result.IsEmpty ()) {
248
+ v8js_create_script_exception (&c->pending_exception , c->isolate , &try_catch);
249
+ zval_ptr_dtor (&zv_v8inst);
250
+ return ;
251
+ }
233
252
}
234
253
235
- /* Exception thrown from JS, preserve it for future execution */
236
- if (result.IsEmpty ()) {
237
- v8js_create_script_exception (&c->pending_exception , c->isolate , &try_catch);
238
- return ;
239
- }
254
+ /* Rethrow back to JS */
255
+ try_catch.ReThrow ();
256
+ zval_ptr_dtor (&zv_v8inst);
257
+ return ;
240
258
}
241
259
242
- /* Rethrow back to JS */
243
- try_catch.ReThrow ();
244
- return ;
245
- }
246
-
247
- /* Convert V8 value to PHP value */
248
- if (return_value && !result.IsEmpty ()) {
249
- v8js_to_zval (result.ToLocalChecked (), *return_value, flags, c->isolate );
260
+ /* Convert V8 value to PHP value */
261
+ if (return_value && !result.IsEmpty ()) {
262
+ v8js_to_zval (result.ToLocalChecked (), *return_value, flags, c->isolate );
263
+ }
250
264
}
251
265
}
266
+
267
+ zval_ptr_dtor (&zv_v8inst);
252
268
}
253
269
/* }}} */
254
270
0 commit comments