diff options
author | hexcoder <hexcoder-@users.noreply.github.com> | 2021-05-31 20:06:35 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-31 20:06:35 +0200 |
commit | 21c8b225719835d8e4fecdb8bd6f42e61ea0600b (patch) | |
tree | 46e844356f7cf88c08f9f9907caa11656a24f416 | |
parent | 1a2da67ed0505c9ac0aa1048ba3d607f3c1aa639 (diff) | |
parent | 97a1f89881878db9bd6b4cd666b3447a63818dcf (diff) | |
download | afl++-21c8b225719835d8e4fecdb8bd6f42e61ea0600b.tar.gz |
Merge pull request #948 from AFLplusplus/going_atomic
Going atomic
-rw-r--r-- | docs/Changelog.md | 1 | ||||
-rw-r--r-- | docs/env_variables.md | 5 | ||||
-rw-r--r-- | include/envs.h | 1 | ||||
-rw-r--r-- | instrumentation/README.llvm.md | 4 | ||||
-rw-r--r-- | instrumentation/README.neverzero.md | 14 | ||||
-rw-r--r-- | instrumentation/SanitizerCoverageLTO.so.cc | 36 | ||||
-rw-r--r-- | instrumentation/SanitizerCoveragePCGUARD.so.cc | 33 | ||||
-rw-r--r-- | instrumentation/afl-llvm-lto-instrumentation.so.cc | 32 | ||||
-rw-r--r-- | instrumentation/afl-llvm-pass.so.cc | 200 | ||||
-rw-r--r-- | src/afl-cc.c | 1 | ||||
-rwxr-xr-x | test/test-llvm.sh | 30 |
11 files changed, 292 insertions, 65 deletions
diff --git a/docs/Changelog.md b/docs/Changelog.md index 298a3998..d8ffe498 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -58,6 +58,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. MacOS shared memory - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup + - add thread safe counters for LLVM CLASSIC (set AFL_LLVM_THREADSAFE_INST) - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename - afl-showmap/cmin will now process queue items in alphabetical order diff --git a/docs/env_variables.md b/docs/env_variables.md index 7bbc0fdd..b4b866ab 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -231,6 +231,11 @@ Then there are a few specific features that are only available in instrumentatio See [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md) for more information. +### Thread safe instrumentation counters (in mode LLVM CLASSIC) + - Setting `AFL_LLVM_THREADSAFE_INST` will inject code that implements thread safe counters. + The overhead is a bit higher compared to the older non-thread safe case. + `AFL_LLVM_NOT_ZERO` and `AFL_LLVM_SKIP_NEVERZERO` are supported (see below). + ### NOT_ZERO - Setting `AFL_LLVM_NOT_ZERO=1` during compilation will use counters diff --git a/include/envs.h b/include/envs.h index 08b3284a..15116fc1 100644 --- a/include/envs.h +++ b/include/envs.h @@ -126,6 +126,7 @@ static char *afl_environment_variables[] = { "AFL_NGRAM_SIZE", "AFL_LLVM_NOT_ZERO", "AFL_LLVM_INSTRUMENT_FILE", + "AFL_LLVM_THREADSAFE_INST", "AFL_LLVM_SKIP_NEVERZERO", "AFL_NO_AFFINITY", "AFL_TRY_AFFINITY", diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index cfe537d5..02722588 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -144,6 +144,10 @@ is not optimal and was only fixed in llvm 9. You can set this with AFL_LLVM_NOT_ZERO=1 See [README.neverzero.md](README.neverzero.md) +Support for thread safe counters has been added for mode LLVM CLASSIC. +Activate it with `AFL_LLVM_THREADSAFE_INST=1`. The tradeoff is better precision in +multi threaded apps for a slightly higher instrumentation overhead. + ## 4) Snapshot feature To speed up fuzzing you can use a linux loadable kernel module which enables diff --git a/instrumentation/README.neverzero.md b/instrumentation/README.neverzero.md index 49104e00..9bcae324 100644 --- a/instrumentation/README.neverzero.md +++ b/instrumentation/README.neverzero.md @@ -16,11 +16,12 @@ at a very little cost (one instruction per edge). (The alternative of saturated counters has been tested also and proved to be inferior in terms of path discovery.) -This is implemented in afl-gcc and afl-gcc-fast, however for llvm_mode this is optional if -the llvm version is below 9 - as there is a perfomance bug that is only fixed -in version 9 and onwards. +This is implemented in afl-gcc and afl-gcc-fast, however for llvm_mode this is +optional if multithread safe counters are selected or the llvm version is below +9 - as there are severe performance costs in these cases. -If you want to enable this for llvm versions below 9 then set +If you want to enable this for llvm versions below 9 or thread safe counters +then set ``` export AFL_LLVM_NOT_ZERO=1 @@ -33,3 +34,8 @@ AFL_LLVM_SKIP_NEVERZERO=1 ``` If the target does not have extensive loops or functions that are called a lot then this can give a small performance boost. + +Please note that the default counter implementations are not thread safe! + +Support for thread safe counters in mode LLVM CLASSIC can be activated with setting +`AFL_LLVM_THREADSAFE_INST=1`. \ No newline at end of file diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 2f4337eb..58969e18 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -236,7 +236,8 @@ class ModuleSanitizerCoverage { uint32_t inst = 0; uint32_t afl_global_id = 0; uint64_t map_addr = 0; - char * skip_nozero = NULL; + const char * skip_nozero = NULL; + const char * use_threadsafe_counters = nullptr; std::vector<BasicBlock *> BlockList; DenseMap<Value *, std::string *> valueMap; std::vector<std::string> dictionary; @@ -437,6 +438,7 @@ bool ModuleSanitizerCoverage::instrumentModule( be_quiet = 1; skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); + use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL) if ((afl_global_id = atoi(ptr)) < 0) @@ -1208,7 +1210,7 @@ void ModuleSanitizerCoverage::instrumentFunction( return; // Should not instrument sanitizer init functions. if (F.getName().startswith("__sanitizer_")) return; // Don't instrument __sanitizer_* callbacks. - // Don't touch available_externally functions, their actual body is elewhere. + // Don't touch available_externally functions, their actual body is elsewhere. if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return; // Don't instrument MSVC CRT configuration helpers. They may run before normal // initialization. @@ -1495,23 +1497,33 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, } /* Update bitmap */ + if (use_threadsafe_counters) { /* Atomic */ - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); - Counter->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None)); + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + llvm::AtomicOrdering::Monotonic); - Value *Incr = IRB.CreateAdd(Counter, One); + } + else + { - if (skip_nozero == NULL) { + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Counter->setMetadata(Mo->getMDKindID("nosanitize"), + MDNode::get(*Ct, None)); - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Tyi); - Incr = IRB.CreateAdd(Incr, carry); + Value *Incr = IRB.CreateAdd(Counter, One); - } + if (skip_nozero == NULL) { + + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Tyi); + Incr = IRB.CreateAdd(Incr, carry); - IRB.CreateStore(Incr, MapPtrIdx) - ->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None)); + } + + IRB.CreateStore(Incr, MapPtrIdx) + ->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None)); + } // done :) inst++; diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 8878d3b1..dbddad0a 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -86,7 +86,8 @@ const char SanCovPCsSectionName[] = "sancov_pcs"; const char SanCovLowestStackName[] = "__sancov_lowest_stack"; -static char *skip_nozero; +static const char *skip_nozero; +static const char *use_threadsafe_counters; namespace { @@ -386,6 +387,7 @@ bool ModuleSanitizerCoverage::instrumentModule( be_quiet = 1; skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); + use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); initInstrumentList(); scanForDangerousFunctions(&M); @@ -1068,21 +1070,32 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, /* Load counter for CurLoc */ Value * MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc); - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); - /* Update bitmap */ + if (use_threadsafe_counters) { - Value *Incr = IRB.CreateAdd(Counter, One); + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + llvm::AtomicOrdering::Monotonic); - if (skip_nozero == NULL) { + } + else + { - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + /* Update bitmap */ - } + Value *Incr = IRB.CreateAdd(Counter, One); + + if (skip_nozero == NULL) { + + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Ty); + Incr = IRB.CreateAdd(Incr, carry); - IRB.CreateStore(Incr, MapPtrIdx); + } + + IRB.CreateStore(Incr, MapPtrIdx); + + } // done :) diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 68bd2fa5..b5fdb3d6 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -93,7 +93,8 @@ class AFLLTOPass : public ModulePass { uint32_t function_minimum_size = 1; uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0; unsigned long long int map_addr = 0x10000; - char * skip_nozero = NULL; + const char *skip_nozero = NULL; + const char *use_threadsafe_counters = nullptr; }; @@ -131,6 +132,8 @@ bool AFLLTOPass::runOnModule(Module &M) { be_quiet = 1; + use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); + if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) { if ((documentFile = fopen(ptr, "a")) == NULL) @@ -839,22 +842,27 @@ bool AFLLTOPass::runOnModule(Module &M) { /* Update bitmap */ - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); - Counter->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); + if (use_threadsafe_counters) { + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + llvm::AtomicOrdering::Monotonic); + } else { + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Counter->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); - Value *Incr = IRB.CreateAdd(Counter, One); + Value *Incr = IRB.CreateAdd(Counter, One); - if (skip_nozero == NULL) { + if (skip_nozero == NULL) { - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Ty); + Incr = IRB.CreateAdd(Incr, carry); - } + } - IRB.CreateStore(Incr, MapPtrIdx) - ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + IRB.CreateStore(Incr, MapPtrIdx) + ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + } // done :) diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 0f773aba..fe9e2e40 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -85,7 +85,8 @@ class AFLCoverage : public ModulePass { uint32_t ctx_k = 0; uint32_t map_size = MAP_SIZE; uint32_t function_minimum_size = 1; - char * ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL; + const char * ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL; + const char * use_threadsafe_counters = nullptr; }; @@ -182,6 +183,26 @@ bool AFLCoverage::runOnModule(Module &M) { char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO"); #endif skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); + use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); + + if ((isatty(2) && !getenv("AFL_QUIET")) || !!getenv("AFL_DEBUG")) { + + if (use_threadsafe_counters) { + if (!getenv("AFL_LLVM_NOT_ZERO")) { + skip_nozero = "1"; + SAYF(cCYA "afl-llvm-pass" VERSION cRST " using thread safe counters\n"); + } + else { + SAYF(cCYA "afl-llvm-pass" VERSION cRST + " using thread safe not-zero-counters\n"); + } + } + else + { + SAYF(cCYA "afl-llvm-pass" VERSION cRST " using non-thread safe instrumentation\n"); + } + + } unsigned PrevLocSize = 0; unsigned PrevCallerSize = 0; @@ -388,7 +409,6 @@ bool AFLCoverage::runOnModule(Module &M) { #endif // other constants we need - ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); ConstantInt *One = ConstantInt::get(Int8Ty, 1); Value * PrevCtx = NULL; // CTX sensitive coverage @@ -410,6 +430,7 @@ bool AFLCoverage::runOnModule(Module &M) { if (F.size() < function_minimum_size) continue; + std::list<Value *> todo; for (auto &BB : F) { BasicBlock::iterator IP = BB.getFirstInsertionPt(); @@ -628,37 +649,63 @@ bool AFLCoverage::runOnModule(Module &M) { /* Update bitmap */ - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); - Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - Value *Incr = IRB.CreateAdd(Counter, One); + if (use_threadsafe_counters) {/* Atomic */ -#if LLVM_VERSION_MAJOR < 9 - if (neverZero_counters_str != - NULL) { // with llvm 9 we make this the default as the bug in llvm is - // then fixed -#else - if (!skip_nozero) { - -#endif - /* hexcoder: Realize a counter that skips zero during overflow. - * Once this counter reaches its maximum value, it next increments to 1 - * - * Instead of - * Counter + 1 -> Counter - * we inject now this - * Counter + 1 -> {Counter, OverflowFlag} - * Counter + OverflowFlag -> Counter - */ + #if LLVM_VERSION_MAJOR < 9 + if (neverZero_counters_str != + NULL) { // with llvm 9 we make this the default as the bug in llvm is then fixed + #else + if (!skip_nozero) { - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); + #endif + // register MapPtrIdx in a todo list + todo.push_back(MapPtrIdx); + } + else + { + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + llvm::AtomicOrdering::Monotonic); + } } + else + { + + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + + Value *Incr = IRB.CreateAdd(Counter, One); + + #if LLVM_VERSION_MAJOR < 9 + if (neverZero_counters_str != + NULL) { // with llvm 9 we make this the default as the bug in llvm is + // then fixed + #else + if (!skip_nozero) { + + #endif + /* hexcoder: Realize a counter that skips zero during overflow. + * Once this counter reaches its maximum value, it next increments to 1 + * + * Instead of + * Counter + 1 -> Counter + * we inject now this + * Counter + 1 -> {Counter, OverflowFlag} + * Counter + OverflowFlag -> Counter + */ + + ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Ty); + Incr = IRB.CreateAdd(Incr, carry); + + } + + IRB.CreateStore(Incr, MapPtrIdx) + ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - IRB.CreateStore(Incr, MapPtrIdx) - ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + } /* non atomic case */ /* Update prev_loc history vector (by placing cur_loc at the head of the vector and shuffle the other elements back by one) */ @@ -715,6 +762,105 @@ bool AFLCoverage::runOnModule(Module &M) { } + if (use_threadsafe_counters) { /*Atomic NeverZero */ + // handle the list of registered blocks to instrument + for (auto val : todo) { + /* hexcoder: Realize a thread-safe counter that skips zero during overflow. Once this counter reaches its maximum value, it next increments to 1 + * + * Instead of + * Counter + 1 -> Counter + * we inject now this + * Counter + 1 -> {Counter, OverflowFlag} + * Counter + OverflowFlag -> Counter + */ + + /* equivalent c code looks like this + * Thanks to + https://preshing.com/20150402/you-can-do-any-kind-of-atomic-read-modify-write-operation/ + + int old = atomic_load_explicit(&Counter, memory_order_relaxed); + int new; + do { + if (old == 255) { + new = 1; + } else { + new = old + 1; + } + } while (!atomic_compare_exchange_weak_explicit(&Counter, &old, new, + memory_order_relaxed, memory_order_relaxed)); + + */ + + Value * MapPtrIdx = val; + Instruction * MapPtrIdxInst = cast<Instruction>(val); + BasicBlock::iterator it0(&(*MapPtrIdxInst)); + ++it0; + IRBuilder<> IRB(&(*it0)); + + // load the old counter value atomically + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Counter->setAlignment(llvm::Align()); + Counter->setAtomic(llvm::AtomicOrdering::Monotonic); + Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + + BasicBlock *BB = IRB.GetInsertBlock(); + // insert a basic block with the corpus of a do while loop + // the calculation may need to repeat, if atomic compare_exchange is not successful + + BasicBlock::iterator it(*Counter); + it++; // split after load counter + BasicBlock *end_bb = BB->splitBasicBlock(it); + end_bb->setName("injected"); + + // insert the block before the second half of the split + BasicBlock *do_while_bb = + BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); + + // set terminator of BB from target end_bb to target do_while_bb + auto term = BB->getTerminator(); + BranchInst::Create(do_while_bb, BB); + term->eraseFromParent(); + + // continue to fill instructions into the do_while loop + IRB.SetInsertPoint(do_while_bb, do_while_bb->getFirstInsertionPt()); + + PHINode *PN = IRB.CreatePHI(Int8Ty, 2); + + // compare with maximum value 0xff + auto *Cmp = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, -1)); + + // increment the counter + Value *Incr = IRB.CreateAdd(Counter, One); + + // select the counter value or 1 + auto *Select = IRB.CreateSelect(Cmp, One, Incr); + + // try to save back the new counter value + auto *CmpXchg = IRB.CreateAtomicCmpXchg( + MapPtrIdx, PN, Select, llvm::AtomicOrdering::Monotonic, + llvm::AtomicOrdering::Monotonic); + CmpXchg->setAlignment(llvm::Align()); + CmpXchg->setWeak(true); + CmpXchg->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + + // get the result of trying to update the Counter + Value *Success = + IRB.CreateExtractValue(CmpXchg, ArrayRef<unsigned>({1})); + // get the (possibly updated) value of Counter + Value *OldVal = + IRB.CreateExtractValue(CmpXchg, ArrayRef<unsigned>({0})); + + // initially we use Counter + PN->addIncoming(Counter, BB); + // on retry, we use the updated value + PN->addIncoming(OldVal, do_while_bb); + + // if the cmpXchg was not successful, retry + IRB.CreateCondBr(Success, end_bb, do_while_bb); + } + + } + } /* diff --git a/src/afl-cc.c b/src/afl-cc.c index 8af8e7b0..6be6e165 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1777,6 +1777,7 @@ int main(int argc, char **argv, char **envp) { SAYF( "\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment " "variables:\n" + " AFL_LLVM_THREADSAFE_INST: instrument with thread safe counters\n" COUNTER_BEHAVIOUR diff --git a/test/test-llvm.sh b/test/test-llvm.sh index 06d0a0f8..1152cc4e 100755 --- a/test/test-llvm.sh +++ b/test/test-llvm.sh @@ -43,6 +43,36 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { $ECHO "$RED[!] llvm_mode failed" CODE=1 } + AFL_LLVM_INSTRUMENT=CLASSIC AFL_LLVM_THREADSAFE_INST=1 ../afl-clang-fast -o test-instr.ts ../test-instr.c > /dev/null 2>&1 + test -e test-instr.ts && { + $ECHO "$GREEN[+] llvm_mode threadsafe compilation succeeded" + echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.ts.0 -r -- ./test-instr.ts > /dev/null 2>&1 + AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.ts.1 -r -- ./test-instr.ts < /dev/null > /dev/null 2>&1 + test -e test-instr.ts.0 -a -e test-instr.ts.1 && { + diff test-instr.ts.0 test-instr.ts.1 > /dev/null 2>&1 && { + $ECHO "$RED[!] llvm_mode threadsafe instrumentation should be different on different input but is not" + CODE=1 + } || { + $ECHO "$GREEN[+] llvm_mode threadsafe instrumentation present and working correctly" + TUPLES=`echo 0|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.ts 2>&1 | grep Captur | awk '{print$3}'` + test "$TUPLES" -gt 2 -a "$TUPLES" -lt 8 && { + $ECHO "$GREEN[+] llvm_mode run reported $TUPLES threadsafe instrumented locations which is fine" + } || { + $ECHO "$RED[!] llvm_mode threadsafe instrumentation produces weird numbers: $TUPLES" + CODE=1 + } + test "$TUPLES" -lt 3 && SKIP=1 + true + } + } || { + $ECHO "$RED[!] llvm_mode threadsafe instrumentation failed" + CODE=1 + } + rm -f test-instr.ts.0 test-instr.ts.1 + } || { + $ECHO "$RED[!] llvm_mode (threadsafe) failed" + CODE=1 + } ../afl-clang-fast -DTEST_SHARED_OBJECT=1 -z defs -fPIC -shared -o test-instr.so ../test-instr.c > /dev/null 2>&1 test -e test-instr.so && { $ECHO "$GREEN[+] llvm_mode shared object with -z defs compilation succeeded" |