38
38
#ifdef HAVE_SYS_TIME_H
39
39
#include <sys/time.h>
40
40
#endif
41
+ #ifdef HAVE_UNISTD_H
42
+ #include <unistd.h>
43
+ #endif
41
44
42
45
ZEND_API void (* zend_execute_ex )(zend_execute_data * execute_data );
43
46
ZEND_API void (* zend_execute_internal )(zend_execute_data * execute_data , zval * return_value );
@@ -169,9 +172,7 @@ void init_executor(void) /* {{{ */
169
172
zend_objects_store_init (& EG (objects_store ), 1024 );
170
173
171
174
EG (full_tables_cleanup ) = 0 ;
172
- #ifdef ZEND_WIN32
173
175
EG (timed_out ) = 0 ;
174
- #endif
175
176
176
177
EG (exception ) = NULL ;
177
178
EG (prev_exception ) = NULL ;
@@ -1183,8 +1184,47 @@ ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name,
1183
1184
}
1184
1185
/* }}} */
1185
1186
1187
+ static void zend_set_timeout_ex (zend_long seconds , int reset_signals );
1188
+
1186
1189
ZEND_API void zend_timeout (int dummy ) /* {{{ */
1187
1190
{
1191
+ EG (timed_out ) = 0 ;
1192
+ zend_set_timeout_ex (0 , 1 );
1193
+ zend_error_noreturn (E_ERROR , "Maximum execution time of %pd second%s exceeded" , EG (timeout_seconds ), EG (timeout_seconds ) == 1 ? "" : "s" );
1194
+ }
1195
+ /* }}} */
1196
+
1197
+ #ifndef ZEND_WIN32
1198
+ static void zend_timeout_handler (int dummy ) /* {{{ */
1199
+ {
1200
+ #ifndef ZTS
1201
+ if (EG (timed_out )) {
1202
+ /* Die on hard timeout */
1203
+ const char * error_filename = NULL ;
1204
+ uint error_lineno = 0 ;
1205
+ char * log_buffer = NULL ;
1206
+
1207
+ if (zend_is_compiling ()) {
1208
+ error_filename = ZSTR_VAL (zend_get_compiled_filename ());
1209
+ error_lineno = zend_get_compiled_lineno ();
1210
+ } else if (zend_is_executing ()) {
1211
+ error_filename = zend_get_executed_filename ();
1212
+ if (error_filename [0 ] == '[' ) { /* [no active file] */
1213
+ error_filename = NULL ;
1214
+ error_lineno = 0 ;
1215
+ } else {
1216
+ error_lineno = zend_get_executed_lineno ();
1217
+ }
1218
+ }
1219
+ if (!error_filename ) {
1220
+ error_filename = "Unknown" ;
1221
+ }
1222
+
1223
+ zend_spprintf (& log_buffer , 0 , "\nFatal error: Maximum execution time of %pd+%pd seconds exceeded (terminated) in %s on line %d\n" , EG (timeout_seconds ), EG (hard_timeout ), error_filename , error_lineno );
1224
+ write (2 , log_buffer , strlen (log_buffer ));
1225
+ _exit (1 );
1226
+ }
1227
+ #endif
1188
1228
1189
1229
if (zend_on_timeout ) {
1190
1230
#ifdef ZEND_SIGNALS
@@ -1199,9 +1239,17 @@ ZEND_API void zend_timeout(int dummy) /* {{{ */
1199
1239
zend_on_timeout (EG (timeout_seconds ));
1200
1240
}
1201
1241
1202
- zend_error_noreturn (E_ERROR , "Maximum execution time of %pd second%s exceeded" , EG (timeout_seconds ), EG (timeout_seconds ) == 1 ? "" : "s" );
1242
+ EG (timed_out ) = 1 ;
1243
+
1244
+ #ifndef ZTS
1245
+ if (EG (hard_timeout ) > 0 ) {
1246
+ /* Set hard timeout */
1247
+ zend_set_timeout_ex (EG (hard_timeout ), 1 );
1248
+ }
1249
+ #endif
1203
1250
}
1204
1251
/* }}} */
1252
+ #endif
1205
1253
1206
1254
#ifdef ZEND_WIN32
1207
1255
VOID CALLBACK tq_timer_cb (PVOID arg , BOOLEAN timed_out )
@@ -1224,11 +1272,9 @@ VOID CALLBACK tq_timer_cb(PVOID arg, BOOLEAN timed_out)
1224
1272
#define SIGPROF 27
1225
1273
#endif
1226
1274
1227
- void zend_set_timeout (zend_long seconds , int reset_signals ) /* {{{ */
1275
+ static void zend_set_timeout_ex (zend_long seconds , int reset_signals ) /* {{{ */
1228
1276
{
1229
1277
1230
- EG (timeout_seconds ) = seconds ;
1231
-
1232
1278
#ifdef ZEND_WIN32
1233
1279
if (!seconds ) {
1234
1280
return ;
@@ -1239,7 +1285,6 @@ void zend_set_timeout(zend_long seconds, int reset_signals) /* {{{ */
1239
1285
delete and recreate. */
1240
1286
if (NULL != tq_timer ) {
1241
1287
if (!DeleteTimerQueueTimer (NULL , tq_timer , NULL )) {
1242
- EG (timed_out ) = 0 ;
1243
1288
tq_timer = NULL ;
1244
1289
zend_error_noreturn (E_ERROR , "Could not delete queued timer" );
1245
1290
return ;
@@ -1249,12 +1294,10 @@ void zend_set_timeout(zend_long seconds, int reset_signals) /* {{{ */
1249
1294
1250
1295
/* XXX passing NULL means the default timer queue provided by the system is used */
1251
1296
if (!CreateTimerQueueTimer (& tq_timer , NULL , (WAITORTIMERCALLBACK )tq_timer_cb , (VOID * )& EG (timed_out ), seconds * 1000 , 0 , WT_EXECUTEONLYONCE )) {
1252
- EG (timed_out ) = 0 ;
1253
1297
tq_timer = NULL ;
1254
1298
zend_error_noreturn (E_ERROR , "Could not queue new timer" );
1255
1299
return ;
1256
1300
}
1257
- EG (timed_out ) = 0 ;
1258
1301
#else
1259
1302
# ifdef HAVE_SETITIMER
1260
1303
{
@@ -1277,22 +1320,39 @@ void zend_set_timeout(zend_long seconds, int reset_signals) /* {{{ */
1277
1320
1278
1321
if (reset_signals ) {
1279
1322
# ifdef ZEND_SIGNALS
1280
- zend_signal (signo , zend_timeout );
1323
+ zend_signal (signo , zend_timeout_handler );
1281
1324
# else
1282
1325
sigset_t sigset ;
1283
-
1284
- signal (signo , zend_timeout );
1326
+ # ifdef HAVE_SIGACTION
1327
+ struct sigaction act ;
1328
+
1329
+ act .sa_handler = zend_timeout_handler ;
1330
+ sigemptyset (& act .sa_mask );
1331
+ act .sa_flags = SA_RESETHAND | SA_NODEFER ;
1332
+ sigaction (signo , & act , NULL );
1333
+ # else
1334
+ signal (signo , zend_timeout_handler );
1335
+ # endif /* HAVE_SIGACTION */
1285
1336
sigemptyset (& sigset );
1286
1337
sigaddset (& sigset , signo );
1287
1338
sigprocmask (SIG_UNBLOCK , & sigset , NULL );
1288
- # endif
1339
+ # endif /* ZEND_SIGNALS */
1289
1340
}
1290
1341
}
1291
1342
# endif /* HAVE_SETITIMER */
1292
1343
#endif
1293
1344
}
1294
1345
/* }}} */
1295
1346
1347
+ void zend_set_timeout (zend_long seconds , int reset_signals ) /* {{{ */
1348
+ {
1349
+
1350
+ EG (timeout_seconds ) = seconds ;
1351
+ zend_set_timeout_ex (seconds , reset_signals );
1352
+ EG (timed_out ) = 0 ;
1353
+ }
1354
+ /* }}} */
1355
+
1296
1356
void zend_unset_timeout (void ) /* {{{ */
1297
1357
{
1298
1358
#ifdef ZEND_WIN32
@@ -1320,6 +1380,7 @@ void zend_unset_timeout(void) /* {{{ */
1320
1380
#endif
1321
1381
}
1322
1382
# endif
1383
+ EG (timed_out ) = 0 ;
1323
1384
#endif
1324
1385
}
1325
1386
/* }}} */
0 commit comments