-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Example does not find panicking input since nightly-2021-12-18 #90
Comments
I think letting upstream LLVM know about the seemingly missing sancov tracing calls is good, and I think your intuition of reproducing in C++ is the correct one to make it most actionable for them. In the meantime, I think we can just update the example program to something like if data.len() == 6 &&
data[0] == b'b' &&
data[1] == b'a' &&
data[2] == b'n' &&
data[3] == b'a' &&
data[4] == b'n' &&
data[5] == b'a'
{
panic!("sucess!");
} which, IIUC, should rely a bit less on the specific Rust comparators call sequence and subsequent lowering to LLVM IR. |
The root cause here is actually rust-lang/rust#85828 That tries to do comparisons via integer comparison instead of always calling So |
Thanks for you input @scottmcm, but that shouldn't matter because with the default compilation flags cmp instructions are also instrumented, so this should work. I tried to reproduce the bug in C++ but it finds the crashing input instantly: #include <stdint.h>
#include <stddef.h>
#include <assert.h>
void FuzzMe(const uint8_t *Data, size_t DataSize) {
if (DataSize != 8) return;
const uint64_t ban = *(const uint64_t *)Data;
if (ban == 0x21616e616e6162LL) {
assert(false);
}
return;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
FuzzMe(Data, Size);
return 0;
} I am compiling that as
Following this tutorial if you want to reproduce. |
I know nothing about the fuzzer, just wanted to give some context on when it happened (since, as the OP mentions, rust-lang/rust#91838 is mostly uninteresting) and what's special about array-to-array comparisons in the codegen right now. |
While taking a look at #89, I noticed that even with the proposed workaround, the ci script fails because the first example doesn't find the panicking input. I guess this is an issue caused by llvm, but I am filing it here because I am not sure.
You can use my fork to reproduce the issue. This was working with an old version of rustc, so I was able to bisect the error. 2021-12-17 is good, 2021-12-18 is bad. This is the failing example:
Bad output
Good output
Cause
I bisected the cause to this PR: rust-lang/rust#91838 which optimizes comparison of slice and array. But note that this is just a library change, so the actual bug was probably already present before. The PR changes the PartialEq implementation from this one, which forwards the implementation to slice-slice comparison:
to this one, which uses array-array comparison:
So a quick workaround would be to force slice-slice comparison, like this:
And that does fix the issue. Another workaround is to use a longer string, which somehow prevents the optimization from happening:
And this also fixes the issue. But obviously it would be better to fix this in the compiler, otherwise there will be many bugs that could have been found by fuzzing but they were not.
I also tried changing the compilation flags, but I did not find any combination that fixed the issue. Also I tried other versions such as the latest nightly 2022-02-28 and the issue is not fixed yet.
Assembly
I tried comparing the assembly code of the good version and the bad version, and I think the main difference is that in the bad version the
banana!
string is stored inside a register as the constant0x21616e616e6162
, while in the old version it must be stored somewhere else because I did not find that constant.Also I see that most of the calls to
cmp
andtest
are preceded by a call to__sanitizer_cov_trace_const_cmp1
, which I assume is the coverage code, while the cmp with0x21616e616e6162
from the new version does not have such a call, as you can see in this snippet:Here is the full disassembly of the
rust_fuzzer_test_input
function, so you can compare the differences: fuzz_main_dissasembly.zipConclusion
I hope this report was useful, and if someone knows what is going on then let me know. If I have time I will try to check if the new slice comparison code has ever compiled correctly in older versions of rust, and also I may try to reproduce the bug in C++ and open an issue directly in the llvm repo.
The text was updated successfully, but these errors were encountered: