Index: lib/fuzzer/FuzzerLoop.cpp =================================================================== --- lib/fuzzer/FuzzerLoop.cpp +++ lib/fuzzer/FuzzerLoop.cpp @@ -354,8 +354,10 @@ void Fuzzer::PrintFinalStats() { if (Options.PrintCoverage) TPC.PrintCoverage(); - if (Options.PrintUnstableStats) + if (Options.PrintUnstableStats) { TPC.PrintUnstableStats(); + TPC.PrintUnstableFuncs(); + } if (Options.DumpCoverage) TPC.DumpCoverage(); if (Options.PrintCorpusStats) Index: lib/fuzzer/FuzzerTracePC.h =================================================================== --- lib/fuzzer/FuzzerTracePC.h +++ lib/fuzzer/FuzzerTracePC.h @@ -110,6 +110,7 @@ void PrintCoverage(); void DumpCoverage(); void PrintUnstableStats(); + void PrintUnstableFuncs(); template void IterateCoveredFunctions(CallBack CB); Index: lib/fuzzer/FuzzerTracePC.cpp =================================================================== --- lib/fuzzer/FuzzerTracePC.cpp +++ lib/fuzzer/FuzzerTracePC.cpp @@ -340,6 +340,22 @@ IterateCoveredFunctions(CoveredFunctionCallback); } +void TracePC::PrintUnstableFuncs() { + Printf("UNSTABLE_FUNCTIONS:\n"); + + IterateInline8bitCounters([&](int i, int j, int UnstableIdx) { + const PCTableEntry &TE = ModulePCTable[i].Start[j]; + if (UnstableCounters[UnstableIdx].IsUnstable && + ObservedFuncs.count(TE.PC)) { + auto VisualizePC = GetNextInstructionPc(TE.PC); + std::string FunctionStr = DescribePC("%F", VisualizePC); + if (FunctionStr.find("in ") == 0) + FunctionStr = FunctionStr.substr(3); + Printf("%s\n", FunctionStr.c_str()); + } + }); +} + void TracePC::DumpCoverage() { if (EF->__sanitizer_dump_coverage) { Vector PCsCopy(GetNumPCs()); Index: test/fuzzer/PrintUnstableStatsTest.cpp =================================================================== --- test/fuzzer/PrintUnstableStatsTest.cpp +++ test/fuzzer/PrintUnstableStatsTest.cpp @@ -18,11 +18,11 @@ __attribute__((noinline)) void ini1() { x++; } __attribute__((noinline)) void ini2() { x++; } -__attribute__((noinline)) void t0() { x++; } +__attribute__((noinline)) void t0(int a) { x += a; } __attribute__((noinline)) void t1() { x++; } -__attribute__((noinline)) void t2() { x++; } +__attribute__((noinline)) void t2(int a, int b) { x += a + b; } __attribute__((noinline)) void t3() { x++; } -__attribute__((noinline)) void t4() { x++; } +__attribute__((noinline)) void t4(int a, int b, int c) { x += a + b +c; } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { if (Size == 1 && Data[0] == 'A' && !skip0) { @@ -45,19 +45,19 @@ switch (a % 5) { case 0: - t0(); + t0(a); break; case 1: t1(); break; case 2: - t2(); + t2(a, a); break; case 3: t3(); break; case 4: - t4(); + t4(a, a, a); break; default: assert(false); Index: test/fuzzer/handle-unstable.test =================================================================== --- test/fuzzer/handle-unstable.test +++ test/fuzzer/handle-unstable.test @@ -13,11 +13,11 @@ NORMAL-DAG: ini0() NORMAL-DAG: ini1() NORMAL-DAG: ini2() -NORMAL-DAG: t0() +NORMAL-DAG: t0(int) NORMAL-DAG: t1() -NORMAL-DAG: t2() +NORMAL-DAG: t2(int, int) NORMAL-DAG: t3() -NORMAL-DAG: t4() +NORMAL-DAG: t4(int, int, int) ; MinUnstable RUN: %run %t-HandleUnstableTest -print_coverage=1 -handle_unstable=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=MIN Index: test/fuzzer/print_unstable_stats.test =================================================================== --- test/fuzzer/print_unstable_stats.test +++ test/fuzzer/print_unstable_stats.test @@ -1,3 +1,20 @@ RUN: %cpp_compiler %S/PrintUnstableStatsTest.cpp -o %t-PrintUnstableStatsTest + RUN: %run %t-PrintUnstableStatsTest -print_unstable_stats=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=LONG -LONG: stat::stability_rate: 27.59 +LONG-DAG: stat::stability_rate: 27.59 + +; We do not observe ini functions since we take the minimum hit counts, and minimum hit counts for ini is 0. +LONG: UNSTABLE_FUNCTIONS:{{$}} +LONG-NOT: {{^}}det0(){{$}} +LONG-NOT: {{^}}det1(){{$}} +LONG-NOT: {{^}}det2(){{$}} +LONG-NOT: {{^}}det3(){{$}} +LONG-NOT: {{^}}det4(){{$}} +LONG-NOT: {{^}}ini0(){{$}} +LONG-NOT: {{^}}ini1(){{$}} +LONG-NOT: {{^}}ini2(){{$}} +LONG-DAG: {{^}}t0(int){{$}} +LONG-DAG: {{^}}t1(){{$}} +LONG-DAG: {{^}}t2(int, int){{$}} +LONG-DAG: {{^}}t3(){{$}} +LONG-DAG: {{^}}t4(int, int, int){{$}}