Index: lib/fuzzer/FuzzerDriver.cpp =================================================================== --- lib/fuzzer/FuzzerDriver.cpp +++ lib/fuzzer/FuzzerDriver.cpp @@ -622,6 +622,8 @@ if (Flags.handle_unstable == TracePC::MinUnstable || Flags.handle_unstable == TracePC::ZeroUnstable) Options.HandleUnstable = Flags.handle_unstable; + if (Options.HandleUnstable) + Options.PrintUnstableFuncs = Flags.print_unstable_funcs; Options.DumpCoverage = Flags.dump_coverage; if (Flags.exit_on_src_pos) Options.ExitOnSrcPos = Flags.exit_on_src_pos; Index: lib/fuzzer/FuzzerFlags.def =================================================================== --- lib/fuzzer/FuzzerFlags.def +++ lib/fuzzer/FuzzerFlags.def @@ -102,6 +102,9 @@ FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.") FUZZER_FLAG_INT(print_funcs, 2, "If >=1, print out at most this number of " "newly covered functions.") +FUZZER_FLAG_INT(print_unstable_funcs, 0, "If 1, print unstable functions that" + " have been triggered at exit." + " Used with -handle_unstable") FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.") FUZZER_FLAG_INT(print_corpus_stats, 0, "If 1, print statistics on corpus elements at exit.") Index: lib/fuzzer/FuzzerLoop.cpp =================================================================== --- lib/fuzzer/FuzzerLoop.cpp +++ lib/fuzzer/FuzzerLoop.cpp @@ -358,6 +358,8 @@ TPC.PrintUnstableStats(); if (Options.DumpCoverage) TPC.DumpCoverage(); + if (Options.PrintUnstableFuncs) + TPC.PrintUnstableFuncs(); if (Options.PrintCorpusStats) Corpus.PrintStats(); if (Options.PrintMutationStats) MD.PrintMutationStats(); Index: lib/fuzzer/FuzzerOptions.h =================================================================== --- lib/fuzzer/FuzzerOptions.h +++ lib/fuzzer/FuzzerOptions.h @@ -55,6 +55,7 @@ bool PrintMutationStats = false; bool PrintCorpusStats = false; bool PrintCoverage = false; + bool PrintUnstableFuncs = false; bool PrintUnstableStats = false; int HandleUnstable = 0; bool DumpCoverage = false; 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/print-unstable-funcs.test =================================================================== --- /dev/null +++ test/fuzzer/print-unstable-funcs.test @@ -0,0 +1,21 @@ +# Tests -print_unstable_funcs +UNSUPPORTED: aarch64 + +RUN: %cpp_compiler %S/PrintUnstableStatsTest.cpp -o %t-PrintUnstableFuncsTest + +RUN: %run %t-PrintUnstableFuncsTest -print_unstable_funcs=1 -handle_unstable=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=MIN +; We do not observe ini functions since we take the minimum hit counts, and minimum hit counts for ini is 0. +MIN: UNSTABLE_FUNCTIONS:{{$}} +MIN-NOT: {{^}}det0(){{$}} +MIN-NOT: {{^}}det1(){{$}} +MIN-NOT: {{^}}det2(){{$}} +MIN-NOT: {{^}}det3(){{$}} +MIN-NOT: {{^}}det4(){{$}} +MIN-NOT: {{^}}ini0(){{$}} +MIN-NOT: {{^}}ini1(){{$}} +MIN-NOT: {{^}}ini2(){{$}} +MIN-DAG: {{^}}t0(){{$}} +MIN-DAG: {{^}}t1(){{$}} +MIN-DAG: {{^}}t2(){{$}} +MIN-DAG: {{^}}t3(){{$}} +MIN-DAG: {{^}}t4(){{$}}