@@ -120,135 +120,151 @@ void v8js_v8_call(v8js_ctx *c, zval **return_value,
120120{
121121 char *tz = NULL ;
122122
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);
124128
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);
129131
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 ();
132136
133- /* Set flags for runtime use */
134- c-> flags = flags ;
137+ /* Catch JS exceptions */
138+ v8::TryCatch try_catch (isolate) ;
135139
136- /* Check if timezone has been changed and notify V8 */
137- tz = getenv ( " TZ " ) ;
140+ /* Set flags for runtime use */
141+ c-> flags = flags ;
138142
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" );
145145
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 ();
150152
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+ }
156156 }
157- }
158157
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+ }
162165
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);
167169
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 --;
174174
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 ();
177181
178- efree (timer_ctx);
182+ time_limit = timer_ctx->time_limit ;
183+ memory_limit = timer_ctx->memory_limit ;
179184
180- if (!V8JSG (fatal_error_abort)) {
181- char exception_string[64 ];
185+ efree (timer_ctx);
182186
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 ];
189189
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+ }
194197
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;
197201 isolate->GetHeapStatistics (&hs);
198202
199203 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+ }
201210 }
202211 }
203- }
204212
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+ }
222220
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+ }
225226
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+ }
228232
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+ }
233252 }
234253
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 ;
240258 }
241259
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+ }
250264 }
251265 }
266+
267+ zval_ptr_dtor (&zv_v8inst);
252268}
253269/* }}} */
254270
0 commit comments