Browse code

Support for timeouts.

Török Edvin authored on 2010/03/22 23:57:27
Showing 1 changed files
... ...
@@ -20,6 +20,10 @@
20 20
  *  MA 02110-1301, USA.
21 21
  */
22 22
 #define DEBUG_TYPE "clamavjit"
23
+#include <pthread.h>
24
+#ifndef _WIN32
25
+#include <sys/time.h>
26
+#endif
23 27
 #include "ClamBCModule.h"
24 28
 #include "llvm/ADT/DenseMap.h"
25 29
 #include "llvm/ADT/BitVector.h"
... ...
@@ -60,6 +64,7 @@
60 60
 #include <cstdlib>
61 61
 #include <csetjmp>
62 62
 #include <new>
63
+#include <cerrno>
63 64
 
64 65
 #include "llvm/Config/config.h"
65 66
 #if !ENABLE_THREADS
... ...
@@ -1303,20 +1308,17 @@ static void addFunctionProtos(struct CommonFunctions *CF, ExecutionEngine *EE, M
1303 1303
 
1304 1304
 }
1305 1305
 
1306
-int cli_vm_execute_jit(const struct cli_all_bc *bcs, struct cli_bc_ctx *ctx,
1307
-		       const struct cli_bc_func *func)
1306
+struct bc_thread {
1307
+    void *code;
1308
+    struct cli_bc_ctx *ctx;
1309
+    int finished;
1310
+    pthread_mutex_t  mutex;
1311
+    pthread_cond_t cond;
1312
+};
1313
+
1314
+static int bytecode_thread_execute(intptr_t code, struct cli_bc_ctx *ctx)
1308 1315
 {
1309
-    // no locks needed here, since LLVM automatically acquires a JIT lock
1310
-    // if needed.
1311 1316
     jmp_buf env;
1312
-    void *code = bcs->engine->compiledFunctions[func];
1313
-    if (!code) {
1314
-	errs() << MODULE << "Unable to find compiled function\n";
1315
-	if (func->numArgs)
1316
-	    errs() << MODULE << "Function has "
1317
-		<< (unsigned)func->numArgs << " arguments, it must have 0 to be called as entrypoint\n";
1318
-	return CL_EBYTECODE;
1319
-    }
1320 1317
     // execute;
1321 1318
     if (setjmp(env) == 0) {
1322 1319
 	// setup exception handler to longjmp back here
... ...
@@ -1329,7 +1331,86 @@ int cli_vm_execute_jit(const struct cli_all_bc *bcs, struct cli_bc_ctx *ctx,
1329 1329
     errs().changeColor(raw_ostream::RED, true) << MODULE
1330 1330
 	<< "*** JITed code intercepted runtime error!\n";
1331 1331
     errs().resetColor();
1332
-    return CL_EBYTECODE;
1332
+    return 1;
1333
+}
1334
+
1335
+static void* bytecode_thread(void* dummy)
1336
+{
1337
+    int ret;
1338
+    struct bc_thread *thr = (struct bc_thread*)dummy;
1339
+    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
1340
+    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
1341
+    ret = bytecode_thread_execute((intptr_t)thr->code, thr->ctx);
1342
+    pthread_mutex_lock(&thr->mutex);
1343
+    thr->finished = 1;
1344
+    pthread_cond_signal(&thr->cond);
1345
+    pthread_mutex_unlock(&thr->mutex);
1346
+    return ret ? dummy : NULL;
1347
+}
1348
+extern "C" const char *cli_strerror(int errnum, char* buf, size_t len);
1349
+int cli_vm_execute_jit(const struct cli_all_bc *bcs, struct cli_bc_ctx *ctx,
1350
+		       const struct cli_bc_func *func)
1351
+{
1352
+    char buf[1024];
1353
+    int ret;
1354
+    void *threadret;
1355
+    pthread_t thread;
1356
+    struct timeval tv0, tv1;
1357
+    struct timespec abstimeout;
1358
+    int timedout = 0;
1359
+    // no locks needed here, since LLVM automatically acquires a JIT lock
1360
+    // if needed.
1361
+    void *code = bcs->engine->compiledFunctions[func];
1362
+    if (!code) {
1363
+	errs() << MODULE << "Unable to find compiled function\n";
1364
+	if (func->numArgs)
1365
+	    errs() << MODULE << "Function has "
1366
+		<< (unsigned)func->numArgs << " arguments, it must have 0 to be called as entrypoint\n";
1367
+	return CL_EBYTECODE;
1368
+    }
1369
+    struct bc_thread bcthr = {
1370
+	code, ctx, 0,
1371
+	PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER
1372
+    };
1373
+    gettimeofday(&tv0, NULL);
1374
+    pthread_mutex_lock(&bcthr.mutex);
1375
+    ret = pthread_create(&thread, NULL, bytecode_thread, &bcthr);
1376
+    if (ret) {
1377
+	errs() << "Bytecode: failed to create new thread!";
1378
+	errs() << cli_strerror(ret, buf, sizeof(buf));
1379
+	errs() << "\n";
1380
+	return CL_EBYTECODE;
1381
+    }
1382
+
1383
+    abstimeout.tv_sec = tv0.tv_sec + 5;
1384
+    abstimeout.tv_nsec = tv0.tv_usec*1000;
1385
+    do {
1386
+	ret = pthread_cond_timedwait(&bcthr.cond, &bcthr.mutex, &abstimeout);
1387
+    } while (!bcthr.finished && ret != ETIMEDOUT);
1388
+    pthread_mutex_unlock(&bcthr.mutex);
1389
+    if (ret == ETIMEDOUT) {
1390
+	errs() << "Bytecode run timed out, canceling thread\n";
1391
+	timedout = 1;
1392
+	ret = pthread_cancel(thread);
1393
+	if (ret) {
1394
+	    errs() << "Bytecode: failed to create new thread!";
1395
+	    errs() << cli_strerror(ret, buf, sizeof(buf));
1396
+	    errs() << "\n";
1397
+	}
1398
+    }
1399
+    ret = pthread_join(thread, &threadret);
1400
+    if (ret) {
1401
+	errs() << "Bytecode: failed to create new thread!";
1402
+	errs() << cli_strerror(ret, buf, sizeof(buf));
1403
+	errs() << "\n";
1404
+    }
1405
+    if (cli_debug_flag) {
1406
+	gettimeofday(&tv1, NULL);
1407
+	tv1.tv_sec -= tv0.tv_sec;
1408
+	tv1.tv_usec -= tv0.tv_usec;
1409
+	errs() << "bytecode finished in " << (tv1.tv_sec*1000000 + tv1.tv_usec) << "us\n";
1410
+    }
1411
+    return timedout ? CL_ETIMEOUT : (threadret ? CL_EBYTECODE : CL_SUCCESS);
1333 1412
 }
1334 1413
 
1335 1414
 static unsigned char name_salt[16] = { 16, 38, 97, 12, 8, 4, 72, 196, 217, 144, 33, 124, 18, 11, 17, 253 };