This is an archive of the discontinued LLVM Phabricator instance.

[libFuzzer] Create Unstable Edge Check
AbandonedPublic

Authored by kevinwkt on Jun 13 2018, 1:55 PM.

Details

Summary

Created Flags, Options to run 2 more times if UniqFeature is found to check for unstable edges.
Option 1 in flag is to compare everyone to everyone, 2 is to compare run 2 and 3 taking into account that run 1 is initialization run.
Must not use dump_coverage flag or "_Exit(1);" will be triggered.

Diff Detail

Event Timeline

kevinwkt created this revision.Jun 13 2018, 1:55 PM
Dor1s added a comment.Jun 13 2018, 2:12 PM

I've taken a quick look just to find what can be breaking the tests.

lib/fuzzer/FuzzerOptions.h
58

I think you need 0 here as well.

Did a first pass. Looks pretty good!

I'll take another look and go over the actual algorithm soon.

lib/fuzzer/FuzzerDriver.cpp
618

Please print some kind of explanation here.

619

I don't think ErrorExitCode should be used here since the docs seem to say it is the return code when a bug is found:
(see https://llvm.org/docs/LibFuzzer.html#options)

621

While it's fine for now, I think we should use "deterministic" instead of "det". Other flags don't really shorten things and deterministic isn't that long.

lib/fuzzer/FuzzerFlags.def
113

You should explain what 1 and 2 do and that this flag is incompatible with dump_coverage.

lib/fuzzer/FuzzerOptions.h
58

Yep this a bug: -1 evaluates to true.

lib/fuzzer/FuzzerTracePC.cpp
34

The __ in the variable name as well as this attribute are unnecessary, it isn't being used by the compiler unlike sancov_trace_pc_guard_8bit_counters.
Same for
sancov_trace_pc_nondeterministic_counters_initialized

kevinwkt updated this revision to Diff 151257.Jun 13 2018, 3:07 PM
kevinwkt marked 4 inline comments as done.

Changed Flag name from non_det_check to non_deterministic_check.
Corrected the bug in FuzzerOptions from -1 to 0.
Changed Exit code to _Exit(0);
Removed unnecessary lines in declaring arrays.

kevinwkt marked an inline comment as done.Jun 13 2018, 3:13 PM
kevinwkt updated this revision to Diff 151261.Jun 13 2018, 3:18 PM

Removed __ as commented in first version.

Thanks for the changes.
Left some cosmetic suggestions, I don't think this needs any important changes to functionality.

mmoroz@ Is the summary used for the commit message? That probably should be updated since it still mentions using Options.ErrorExitCode

lib/fuzzer/FuzzerDriver.cpp
618

Tomorrow let's discuss a name that is better than non_deterministic_check, since that isn't really descriptive of what happens (I like DumpUnstable but we should discuss).

622

I guess this check isn't necessary because if !non_deterministic_check then Options.NonDetCheck gets set to zero (which it already is)

lib/fuzzer/FuzzerFlags.def
115

nit: "a unique feature"
Also, let's explain that this option dumps the unstable edges, right now only the comparison is clear.

lib/fuzzer/FuzzerLoop.cpp
354

Given that we may rename the flag, you don't make this change yet:
It would probably better for this (as well as the function DumpNonDetCoverage) to be consistent with the option name (ie: NonDeterministicCheck and DumpNonDeterministicCoverage

473

I think -1 should also be an enum value.

476

Please put spaces around the equals sign

481

I think instead of comparing NonDetCheck to 1 and 2, we should use an enum. eg:

enum {

AllInstability = 1,
NonInitializationInstability = 2,

};

and then this if statement would be if (Options.NonDetCheck == AllInstability)

481

We can reduce the nesting required here by doing:

if (Options.NonDetCheck == 1 && TPC.CountersNonDet()[idx] != TPC.Counters()[idx])
  TPC.CountersNonDet()[idx] = -1;
484

Let's reduce nesting here

else if (run == 0 && TPC.CountersNonDetInitialized()[idx] != -1) {
  TPC.CountersNonDetInitialized()[idx] = TPC.Counters()[idx];
}
488

Let's do this

else if (TPC.CountersNonDetInitialized()[idx] != TPC.Counters()[idx])
  TPC.CountersNonDetInitialized()[idx] = -1;

to reduce nesting

lib/fuzzer/FuzzerTracePC.cpp
323

2 thoughts on this line:

  1. If I were to keep this check in this function, I would do:
if (!EF->__sanitizer_dump_coverage)
  return;

So that we don't need to nest the entire rest of this function.
This would be inconsistent with DumpCoverage so I could be wrong

  1. The behavior of this function (even with the change I just suggested) is consistent with DumpCoverage, so I believe it is fine for now.

However, IMO the behavior of DumpCoverage (and this function) is unfriendly right now.

The way it works, if a user tells libFuzzer to fuzz and dump_coverage, libFuzzer waits until the end of the process and then if __sanitizer_dump_coverage is unavailable, (something libFuzzer knew at the start) libFuzzer ignores the option and doesn't explain why.

I think checks for __sanitizer_dump_coverage should be done before fuzzing but that is not for this patch.
For now I think we can just print some kind of explanation (I think there is no sanitizer_dump_coverage if -fsanitize-coverage=trace-pc-guard is not used).

327

Add a space before the question mark please

329
else if (check == 2)

To reduce nesting please

330

Add a space before the question mark please

lib/fuzzer/FuzzerTracePC.h
165

Is this necessary? I don't think we are using PCs() anywhere outside of FuzzerTracePC

Dor1s added a comment.Jun 14 2018, 9:31 AM

Don't have much to add on top of Jonathan's comments, will take another look later when those get resolved.

kevinwkt updated this revision to Diff 151415.Jun 14 2018, 1:33 PM
kevinwkt marked 14 inline comments as done.

Changed Flag and Option names.
Fixed nested ifs.
Created enum and constexpr for magic numbers.
Fixed Flag explanations.
Fixed format for dump_nondeterministic_coverage by printing explanation and getting rid of the if statement.
PCs() back to private.

Dor1s added a comment.Jun 14 2018, 3:29 PM

@kevinwkt, is this ready for the next review round, or are you still doing more changes locally?

kevinwkt updated this revision to Diff 151446.Jun 14 2018, 5:43 PM
kevinwkt marked an inline comment as done.

PTAL

Moved things to TracePC as suggested along with previous changes.

kevinwkt updated this revision to Diff 151448.Jun 14 2018, 5:57 PM

PTAL

Moved all Counters() and PCs() to private again.

Dor1s added a comment.Jun 14 2018, 8:20 PM

Nice! Left some nits, will take another look in the morning.

lib/fuzzer/FuzzerFlags.def
117

Maybe let's say "execute every input 3 times in total in a unique feature is found during the first execution". I'm just trying to get rid of word "run", as it sounds a bit confusing given that there is another -runs= flag.

lib/fuzzer/FuzzerTracePC.cpp
80

make the arguments const

83

nit: && in the beginning of the line looks inconsistent with conditions on lines 85, 89.

88

add a space after if

342

make the argument const here and in the header

Dor1s added inline comments.Jun 15 2018, 7:18 AM
lib/fuzzer/FuzzerDriver.cpp
619

very minor thing, but let's maybe say dump_unstable_coverage and dump_coverage to be clear that those are names of flags

lib/fuzzer/FuzzerLoop.cpp
355

do we want to rename this function to DumpUnstableCoverage as per previous Jonathan's comment, to keep names of option and function consistent?

472

nit: unnecessary empty line, but I think we should put a comment here. Something short like "Run the same input two more times to detect non-deterministic coverage"

lib/fuzzer/FuzzerTracePC.cpp
34

I'm slightly worried that we always allocate these two arrays, even when dump_unstable_coverage is 0. However, TracePC doesn't seem to have an explicit constructor, so I'm not sure whether we have implement it because of these or leave it as is. Let's leave as is for now, I guess.

77

Counters() points to values of uint8_t type, while CountersNonDet() points to a signed int8_t. Are we sure it's going to work fine? Why do we use signed type ourselves, just to be able to put -1 as a magic value for UnstableCounter?

349

nit: in the code above you're using size_t idx, and here just i. Either way is fine (I'd prefer just i though), but let's keep it consistent.

351

use UnstableCounter instead of -1 here and on line 353?

lib/fuzzer/FuzzerTracePC.h
144

I'm trying to think of better names for these two, but can't generate anything... Maybe AllUnstableCoverage and NonInitUnstableCoverage, but not sure. Up to you, feel free to ignore.

Dor1s added inline comments.Jun 15 2018, 7:31 AM
lib/fuzzer/FuzzerTracePC.cpp
60

Are you sure you need two arrays? I think one would be enough. If we do AllInstability:

  1. InitializeNonDetCounters will put Counters into our array, this will be our baseline to compare against
  1. during the 2nd and the 3rd executions we will be comparing new Counters against our array and assign UnstableCounter when needed

If we do NonInitializationInstability:

  1. We don't need to call InitializeNonDetCounters after the first run.
  1. After the 2nd run we call InitializeNonDetCounters in order to set up a baseline to compare against
  1. After the 3rd run we compare new Counters against our baseline and assign UnstableCounter when needed

That would also simplify TracePC::DumpNonDetCoverage function and other code.

74

Is there any value in calling this function when we use NonInitializationInstability? I think no.

81

I think we should check UnstableOption and run values outside of the loop. Checking that on every iteration is not efficient. It's fine to have three loops inside three different IF branches.

82

should we also skip counters that are already known as unstable? e.g. add && CountersNonDet()[idx] != UnstableCounter. Otherwise, we'll be re-assigning UnstableCounter to the same counters again and again.

89

same problem here, if we already put UnstableCounter into CountersNonDetInitialized()[idx], there is no way for Counters()[idx] to match it. That means, we'll be overwriting those counters with UnstableCounter again and again.

kevinwkt updated this revision to Diff 151565.Jun 15 2018, 2:46 PM
kevinwkt marked 18 inline comments as done.

PTAL

metzman added inline comments.Jun 15 2018, 3:06 PM
lib/fuzzer/FuzzerFlags.def
113

Please add a space after the comma.

lib/fuzzer/FuzzerLoop.cpp
476

Please put a space in between for and the paren.

483

nit: use just one newline

lib/fuzzer/FuzzerTracePC.cpp
88

Space after ==.

351

This line is over 80 chars right? lines should be less than 80 chars in width.
(https://llvm.org/docs/CodingStandards.html#source-code-width)

I think it would be better to change this to a traditional if-else since I think multiline ternary ifs are not allowed.

Please also fix any other lines above 80 chars in width in this CL.

lib/fuzzer/FuzzerTracePC.h
141–142

nit: remove the semi colon in the comment.

kevinwkt updated this revision to Diff 151588.Jun 15 2018, 5:06 PM
kevinwkt marked 2 inline comments as done.

I will use clang-tidy or something else soon. I promise.

metzman added inline comments.Jun 15 2018, 7:33 PM
lib/fuzzer/FuzzerDriver.cpp
619

nit: "Can not use dump_unstable_coverage and dump_coverage options together\n"

Dor1s added a comment.Jun 15 2018, 8:00 PM

Looks great now! I'll take another look Monday morning, but I guess we're almost done here :)

lib/fuzzer/FuzzerTracePC.h
142

actually, the comment is not needed at all, please remove it. Plus, rename UnstableCounter to kUnstableCounter to match the style used in this file / project, e.g. https://cs.chromium.org/chromium/src/third_party/libFuzzer/src/FuzzerTracePC.h?l=72

I have two comments that I didn't think should be put in any particular place.

  1. The naming in this patch is inconsistent, we talk about instability, unstable, and nondet (which, as I mentioned earlier, isn't great since its shortened) and non-deterministic. Some of this is due to inconsistent suggestions. Regardless, I think it is best to use as few terms as possible when describing one thing. Thus, I think we should just use the terms stable and unstable in the code. I don't think these are the best terms since it isn't obvious what they mean, but I think we should be consistent with AFL. In comments and messages we can use these other terms to explain what stable and unstable mean.
  1. It's hard to do this review with "Context not available." everywhere. As Kode pointed out yesterday, there are instructions on how to upload as much context as possible with each diff, please do this in the future.
lib/fuzzer/FuzzerLoop.cpp
470

nit: Add a comment here explaining that if requested by the user, we will look for unstable edges.

476

Why is run a size_t? It's not a size and isn't being used in another operation with any other size_t.
I think it should be an int. Please do the same to UpdateNonDetCounters

476

nit: The initial value of run is somewhat confusing given its name
The zeroth run already happened (and maybe the 1st as well thanks to leak detection?)
This is more like the zeroth unstable check run, maybe change name to unstable_rerun.

lib/fuzzer/FuzzerOptions.h
58

I think the type of DumpUnstableCoverage should be the name of the enum we use (see the enum for my comments on that).
Also, instead of setting it to zero we should set it to the value in the enum signifiying not to dump unstable coverage (maybe DontDumpUnstable).

lib/fuzzer/FuzzerTracePC.cpp
70

Please add a comment explaining what this function does and when it should be run (I think it's a bit unclear why there are two calls to a function with Initialize in the title)

72

I think a comment should be added about what would set a value in CountersNondet to UnstableCounter.

87

Let's get rid of uneeded nesting and reduce the complexity of this function. You can move the if (run == 0) and the else that comes after it outside of the outer else so that we have:

if (UnstableOption == AllInstability)
  UpdateNonDetCountersImpl();
else if (run == 0)  
  InitializeNonDetCounters();
else 
  UpdateNonDetCountersImpl();

We should also get rid of the curly braces to be consistent with the rest of libFuzzer (which seems not to use them with one line if bodies.

Now that we've done that, it is easier to see another simplification we can make. We only need an if-else since there are just two possible actions taken, let's change this:

if (UnstableOption != AllInstability && run == 0)  
  InitializeNonDetCounters();
else 
  UpdateNonDetCountersImpl();

At this point it's clearer that we don't even need the else, just the if and a return in its body, followed by UpdateNonDetCountersImpl() after the body, but I don't really prefer one way or the other.

lib/fuzzer/FuzzerTracePC.h
140

Let's use the type of the enum that defines the possibilities for UnstableOption, instead of int8_t

144

3 comments on this enum:

  1. +1 to Max's comments. The names I suggested were not as good. And I suggest a big change to naming in this PR which Max's suggestion fits with.
  2. Let's give this enum a name, such as DumpUnstableCoverageOptions. That way we can set the type of DumpUnstableCoverage to it.
  3. Let's add an enum value set to zero, called something like DontDumpUnstableso that we don't have to use 0 as a magic value.
Dor1s added a comment.Jun 18 2018, 8:48 AM

+1 to Jonathan's comments, those are great suggestions.

lib/fuzzer/FuzzerLoop.cpp
476

s/unstable_rerun/UnstableRerun/

kevinwkt marked 13 inline comments as done.Jun 18 2018, 4:59 PM
kevinwkt added inline comments.
lib/fuzzer/FuzzerOptions.h
58

Will complicate things given that the enum would have to be in a file usable by both FuzzerOptions.h and also by FuzzerTracePC.h/cpp,

kevinwkt added inline comments.Jun 18 2018, 4:59 PM
lib/fuzzer/FuzzerTracePC.h
144

Changed all names to *unstable*, if definite alternative is chosen, will change later on.

kevinwkt updated this revision to Diff 151826.Jun 18 2018, 5:01 PM

Once again, minor syntax and coding standard changes. Will improve over time.

let's update the language in the commit message too, when you get a chance.

let's update the language in the commit message too, when you get a chance.

+1, take a look at other commit messages for an example: https://github.com/llvm-mirror/compiler-rt/commits/master/lib/fuzzer

I don't seem to have any other comments except of the naming (e.g. Idx) and the CL description. Jonathan, once you're also satisfied, I think we should ask @morehouse to take a look later this week. WDYT?

I don't seem to have any other comments except of the naming (e.g. Idx) and the CL description. Jonathan, once you're also satisfied, I think we should ask @morehouse to take a look later this week. WDYT?

+1, after the language in the commit is updated and [libFuzzer] is added to the title.

kevinwkt retitled this revision from Non Deterministic Edges Checks to [libFuzzer] Create Unstable Edge Check.Jun 19 2018, 6:05 PM
kevinwkt edited the summary of this revision. (Show Details)
kevinwkt updated this revision to Diff 152008.Jun 19 2018, 6:08 PM

Changed idx to i.

Dor1s accepted this revision.Jun 19 2018, 8:04 PM
Dor1s added a reviewer: morehouse.

Matt, Kevin is an intern on our team who is fighting against non-deterministic coverage. Could you please take a look?

There also will be a follow-up CL that uses this approach in order to ignore "unstable" edges when making a decision whether a particular input is NEW or now.

This revision is now accepted and ready to land.Jun 19 2018, 8:05 PM
Dor1s requested changes to this revision.Jun 19 2018, 8:14 PM

Oh, I completely forgot. We also have to add a test. Kevin, please check out the section regarding the tests in LLVM Dev Starting Kit. Then, take a look at the existing tests: https://github.com/llvm-mirror/compiler-rt/tree/master/test/fuzzer, especially at those that have "coverage" in its name. You can either update some existing .testfile or add a new one, whichever is more convenient for you.

This revision now requires changes to proceed.Jun 19 2018, 8:14 PM
morehouse added inline comments.Jun 20 2018, 10:29 AM
lib/fuzzer/FuzzerLoop.cpp
506

Can we run this loop three times, move the initialization above into UpdateUnstableCounters, and make InitializeUnstableCounters private?

508

It might make sense to set/unset RunningCB = true around the callback so the exit handler works correctly. (An unstable edge could potentially lead to an exit()).

However, if you do this you'll also need to set UnitStartTime and UnitStopTime so the timeout handler works correctly.

lib/fuzzer/FuzzerTracePC.cpp
36

If this isn't weakly defined anywhere else, what is the reason for this being a global?

66

This effectively poisons a counter if it has ever previously been marked unstable. Do we want this?

Suppose we have something like:

void foo() {
  if (rand()) {
    doSomething();
  }
}
void bar() {
  doSomething();
}

If the first run calls foo(), we would mark the PCs in doSomething as unstable. Then if a future run calls bar(), doSomething will still be marked unstable even though it isn't unstable in the context of bar().

82

This comment is confusing. What is the "zeroth rerun"?

85

Nit: const is unnecessarily verbose since the parameters are passed by value anyway.

lib/fuzzer/FuzzerTracePC.h
80

Nit: enum DumpUnstableCoverageOptions { is simpler.

147

Does this need to be public? Also, please add a comment describing the purpose of this constant.

metzman added inline comments.Jun 20 2018, 10:56 AM
lib/fuzzer/FuzzerTracePC.cpp
66

AFL does the same thing (see: https://cs.chromium.org/chromium/src/third_party/afl/src/afl-fuzz.c?q=afl-fuzz.c&sq=package:chromium&dr=C&l=2603)
I agree it isn't ideal, when we looked at the coverage reports they were hard to interpret for this reason.
Do you think there is a reasonable way to store info about paths so we only poison the first unstable edge in an unstable path (interested in other alternatives too)?

82

I think I suggested this language. Do you think "first rerun" makes more sense? I didn't like it because it means when UnstableRerun == 0 but I don't feel strongly about it.

morehouse added inline comments.Jun 20 2018, 1:47 PM
lib/fuzzer/FuzzerLoop.cpp
506

Scratch that, we don't want to rerun the callback 3 times. But maybe we could still move the initialization above into UpdateUnstableCounters to make that implementation detail private.

lib/fuzzer/FuzzerTracePC.cpp
66

We could probably store path info for the latest run only (in a large array), then discard/overwrite it on the next run. Then iterate through the path and only mark the first PC in each unstable sequence.

But that should probably be a future CL, since the change would be non-trivial, and I'd like Kostya to comment on such an approach first.

82

Maybe moving some of these comments inline would make it clearer. Something like:

if (UnstableOption != AllUnstable && UnstableRerun == 0) {
  // We are only considering the last 2 runs for determining stability.
  // Therefore we re-initialize counters on the first rerun.
...
}  else {
  // We are considering all 3 runs for determining stability.
...
kevinwkt marked 4 inline comments as done.Jun 20 2018, 2:00 PM
kevinwkt added inline comments.
lib/fuzzer/FuzzerLoop.cpp
506

So the reason I did it this way was due to the fact that I need the counters for the original run copied into my unstable_counters which are erased at the beginning of every TPC.ResetMaps. The only way I can think of at the moment to do the initialization on the TPC side is to not ResetMaps() and CB() before the TPC.Update. However, this would unnecessarily complicate things on the TPC side given counters we want are updated as the last thing in the for loop.
If there are any better way to solve this, please let me know as I may have overlooked things.

morehouse added inline comments.Jun 20 2018, 2:52 PM
lib/fuzzer/FuzzerLoop.cpp
506

Yes, I see that now.

After looking at this again, I don't think this loop is helping much. I'd suggest inlining the logic from UpdateUnstableCounters since it's awkward to be passing loop indexes to it anyway.

E.g.,

if (option == AllUnstable)
  Initialize();
doCallback();
if (option == AllUnstable)
  UpdateUnstableCounters();
else
  Initialize();
doCallback();
UpdateUnstableCounters();

This would also allow you to eliminate UpdateUnstableCountersImpl.

kevinwkt updated this revision to Diff 152409.Jun 21 2018, 4:44 PM
kevinwkt marked 2 inline comments as done.

PTAL,

Made changes as requested taking out the for loop.
However, given that I need to call Initialize() and Update() from FuzzerLoop, both were declared public in FuzzerTracePC.

kevinwkt marked 10 inline comments as done.Jun 21 2018, 4:46 PM
morehouse added inline comments.Jun 21 2018, 6:34 PM
lib/fuzzer/FuzzerLoop.cpp
527

Might be nice to move this new code into a helper method Fuzzer::CheckForUnstableCounters.

lib/fuzzer/FuzzerTracePC.cpp
54

Can we make this a member of TracePC and shorten the name?

63

Don't we always run this whether -dump_unstable_coverage is 1 or 2?

82

Sorry to contradict @Dor1s, but I think I'd actually prefer if we removed the check for kUnstableCounter. The code would be simpler, and in the typical case might be marginally faster (I would expect unstable edges to be the exception rather than the rule).

371

Typically warnings for missing external functions are handled by setting the last argument to true in FuzzerExtFunctions.def. In the case of __sanitizer_dump_coverage, we don't warn currently.

Is there a good reason to warn anyway? If so, maybe we should flip the flag in FuzzerExtFunctions.def instead. If not, let's remove the Printf.

lib/fuzzer/FuzzerTracePC.h
78

Nit: NonInitializationUnstable is a slightly confusing name to me. Maybe IgnoreInitUnstable or IgnoreFirstRunUnstable would be clearer?

195

Nit: Please move kUnstableCounter to very top of private section.

Dor1s added inline comments.Jun 22 2018, 7:01 AM
lib/fuzzer/FuzzerTracePC.cpp
82

That's a good point. Sounds reasonable to me. We may consider making this to be the second condition rather than the first one, so that it would be executed only when the edge is indeed unstable. I feel like doing another CMP on a value which we already have loaded (in a register or whatever) would be faster than doing 'store' operation, given that with unstable targets we likely to hit the same non-deterministic edges again and again. But if you insist, I'm fine with removing that.

371

The existing dump_coverage doesn't complain about missing __sanitizer_dump_coverage and thus provides not great UX in such cases. +1 to make it warn via FuzzerExtFunctions.def

kevinwkt updated this revision to Diff 152543.Jun 22 2018, 2:34 PM
kevinwkt marked 9 inline comments as done.

ptal

Fixed comments.

Code looks good. Please add a test.

lib/fuzzer/FuzzerTracePC.h
153

Please follow the surrounding naming conventions. i.e. UnstableCounters.

kevinwkt updated this revision to Diff 152567.Jun 22 2018, 6:00 PM

ptal
Added tests

morehouse added inline comments.Jun 22 2018, 6:14 PM
lib/fuzzer/FuzzerTracePC.h
152

uint8_t

test/fuzzer/DumpUnstableCoverageTest.cpp
7

Why do we need a pointer to x?

47

A switch would be more compact.

test/fuzzer/dump_unstable_coverage.test
2

Why do we need -g -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard?

12

We need to look at the actual sancov file to make sure it has the PCs we expect to be unstable.

kevinwkt marked 2 inline comments as done.Jun 25 2018, 11:10 AM
kevinwkt added inline comments.
test/fuzzer/dump_unstable_coverage.test
2

Deleted "-g -fsanitize-coverage=0", we only need "-fsanitize-coverage=trace-pc-guard" since we use the counters I believe.

12

None of the tests so far handles sancov files except for dump_coverage, and dump_coverage does the same thing I do except they only check for "LLVMFuzzerTestOneInput" in the sancov file. What would be they right way to approach this?

morehouse added inline comments.
lib/fuzzer/FuzzerTracePC.h
152

uint8_t is still misspelled.

test/fuzzer/dump_unstable_coverage.test
12

Can you do something similar to dump_coverage.test, except check that the unstable functions are there and not the stable ones?

kevinwkt updated this revision to Diff 152796.Jun 25 2018, 4:05 PM
kevinwkt marked 8 inline comments as done.
kevinwkt added inline comments.
test/fuzzer/DumpUnstableCoverageTest.cpp
47

Did not use a switch since it seemed to produce only 1 edge since it is a lookup table. Used ifs to make more edges.

kevinwkt added inline comments.Jun 25 2018, 4:20 PM
test/fuzzer/DumpUnstableCoverageTest.cpp
47

I think unlike if-else which uses multiple edges switches uses a jump-table.

morehouse added inline comments.Jun 25 2018, 5:12 PM
test/fuzzer/DumpUnstableCoverageTest.cpp
47

Right, but I don't see how a jump table would be an issue here. Especially since the test only checks coverage at the function level.

test/fuzzer/dump_unstable_coverage.test
16

Could you also check the sancov file the -dump_unstable_coverage=2 case? You'll have to make the fuzz target save some state the first time it sees a certain input, and then skip some code if that state has been set.

For example, I think this would be enough:

static bool SkipFoo = false;
if (Size == 1 && Data[0] == 'Z' && !SkipFoo)  {
  SkipFoo = true;
  Foo();
}

You'll probably also have to bump up the -runs parameter enough for libFuzzer to always find the particular input that triggers this case.

kevinwkt updated this revision to Diff 152919.Jun 26 2018, 10:36 AM
kevinwkt marked 6 inline comments as done.
morehouse accepted this revision.Jun 26 2018, 10:58 AM
morehouse added inline comments.
test/fuzzer/dump_unstable_coverage.test
13

I think it makes sense to also check that the ini functions are marked unstable for SANCOV1.

kevinwkt updated this revision to Diff 152926.Jun 26 2018, 11:07 AM
kevinwkt marked an inline comment as done.Jun 26 2018, 11:10 AM
kevinwkt added inline comments.
test/fuzzer/dump_unstable_coverage.test
13

Then I would have to bump up the runs for this test to guarantee that there is at least 1 case where ini function is triggered. How many runs do you think is ok? Would 100000 runs be adequate?

morehouse added inline comments.Jun 26 2018, 11:14 AM
test/fuzzer/dump_unstable_coverage.test
13

That should be enough. I think 100000 is pretty common for other fuzzer tests.

kcc added inline comments.Jun 26 2018, 5:05 PM
lib/fuzzer/FuzzerTracePC.h
78

Do you really need these two choices?
I understand the difference, but maybe we can have just one of these?

test/fuzzer/dump_unstable_coverage.test
2

Why do you use the old -fsanitize-coverage=trace-pc-guard instead of the new fsanitize=fuzzer?
I'd prefer if you used the new instrumentation instead of the old one because I was planing to
completely remove the old one.

kevinwkt updated this revision to Diff 153580.Jun 29 2018, 2:39 PM
kevinwkt marked 6 inline comments as done.

This seems to detect the unstable edges, however I am having errors in TracePC::DumpUnstableCoverage() in these lines.

if (UnstableCounters[UnstableIdx] == kUnstableCounter)

PCsCopy[UnstableIdx] = ModulePCTable[i].Start[j].PC;

"ERROR: Coverage points in binary and .sancov file do not match." is what I am getting which I am assuming I am sending the wrong PC. But then which PC should be sent?

"ERROR: Coverage points in binary and .sancov file do not match." is what I am getting which I am assuming I am sending the wrong PC. But then which PC should be sent?

Is this coming from sancov? I think it might only support trace-pc-guard...

@kcc: How can we test this with inline counters?

kcc added a comment.Jul 2 2018, 10:53 AM

"ERROR: Coverage points in binary and .sancov file do not match." is what I am getting which I am assuming I am sending the wrong PC. But then which PC should be sent?

Is this coming from sancov? I think it might only support trace-pc-guard...

@kcc: How can we test this with inline counters?

We don't develop sancov any further and it does not support instrumentation other than trace-pc-guard.
Do you guys use it, or you use something else?
I guess the simplest way here is to not use sancov in this test and instead use llvm-symbolizer.
You can also try to relax the check in sancov to make it work (should be simple).

kevinwkt marked 2 inline comments as done.Jul 2 2018, 11:05 AM

We don't develop sancov any further and it does not support instrumentation other than trace-pc-guard.
Do you guys use it, or you use something else?
I guess the simplest way here is to not use sancov in this test and instead use llvm-symbolizer.
You can also try to relax the check in sancov to make it work (should be simple).

Would we be able to get a coverage report through llvm-symbolizer? Because I think one of the things we want here is to be able to use this as a report as well as handling instability.

kcc added a comment.Jul 2 2018, 11:08 AM

You may try projects/compiler-rt/lib/sanitizer_common/scripts/sancov.py instead of sancov, this tool is less restrictive.
pipe the output of sancov.py through llvm-symbolizer

In D48150#1149859, @kcc wrote:

You may try projects/compiler-rt/lib/sanitizer_common/scripts/sancov.py instead of sancov, this tool is less restrictive.
pipe the output of sancov.py through llvm-symbolizer

I'm trying /usr/.../llvm/projects/compiler-rt/lib/sanitizer_common/scripts/sancov.py merge %t-DumpUnstableCoverageTest* %t_workdir/*.sancov > llvm-symbolizer and it's still not working. I tried unpacking and rawunpacking the sancov files and I get the error:
"UnicodeDecodeError: 'utf8' codec can't decode byte 0xb0 in position 12: invalid start byte"

@kcc @morehouse It doesn't look like a coverage report with new instrumentation will be feasible. What do you think of changing this CL to report stability as a stat, like AFL does, instead?

kcc added a comment.Jul 10 2018, 8:30 PM

@kcc @morehouse It doesn't look like a coverage report with new instrumentation will be feasible.

I don't understand why.

What do you think of changing this CL to report stability as a stat, like AFL does, instead?

I also don't understand what you mean by that. Maybe create a separate CL?

In D48150#1158252, @kcc wrote:

@kcc @morehouse It doesn't look like a coverage report with new instrumentation will be feasible.

I don't understand why.

I don't think sancov reports are possible using the new instrumentation. Not 100% about this, but it doesn't seem to work like it did for the old instrumentation.

What do you think of changing this CL to report stability as a stat, like AFL does, instead?

I also don't understand what you mean by that. Maybe create a separate CL?

I mean that instead of implementing coverage reports for unstable edges, add a final_stat (or a stat that gets printed to stdout) that lists the percentage of unstable edges.
This is the stability stat that AFL reports.
A separate CL works too.

kcc added a comment.Jul 10 2018, 8:42 PM
In D48150#1158252, @kcc wrote:

@kcc @morehouse It doesn't look like a coverage report with new instrumentation will be feasible.

I don't understand why.

I don't think sancov reports are possible using the new instrumentation. Not 100% about this, but it doesn't seem to work like it did for the old instrumentation.

I am 100% confident it can work.
Just either fix sancov (a bit) or use sancov.py + llvm-symbolizer

What do you think of changing this CL to report stability as a stat, like AFL does, instead?

I also don't understand what you mean by that. Maybe create a separate CL?

I mean that instead of implementing coverage reports for unstable edges, add a final_stat (or a stat that gets printed to stdout) that lists the percentage of unstable edges.
This is the stability stat that AFL reports.
A separate CL works too.

That will work too. Up to you.
"coverage reports for unstable edges" is kind of fun though.
You can also generate this report from within libFuzzer, no need to involve external files, sancov, etc.

See how we implement printing newly discovered functions or PCs, it's all there.

metzman resigned from this revision.Aug 21 2018, 7:14 PM

Removing myself as reviewer since this won't be landed and I don't like having clutter on my reviews page.

kevinwkt abandoned this revision.Aug 21 2018, 9:29 PM
Via Web