... | ... |
@@ -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 }; |