Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler-rt/lib/fuzzer/FuzzerTracePC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) {
}

void TracePC::HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop) {
if (Start == Stop) {
return;
}
const PCTableEntry *B = reinterpret_cast<const PCTableEntry *>(Start);
const PCTableEntry *E = reinterpret_cast<const PCTableEntry *>(Stop);
if (NumPCTables && ModulePCTable[NumPCTables - 1].Start == B) return;
Expand Down
60 changes: 60 additions & 0 deletions compiler-rt/test/fuzzer/SimulateEmptyModuleTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

// Like SimpleTest, but simulates an "empty" module (i.e. one without any functions to instrument).
// This reproduces a previous bug (when libFuzzer is compiled with assertions enabled).

#include <assert.h>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <ostream>

extern "C" {
void __sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop);
void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
const uintptr_t *pcs_end);
}

void dummy_func() {}

uint8_t empty_8bit_counters[0];
uintptr_t empty_pcs[0];

uint8_t fake_8bit_counters[1] = {0};
uintptr_t fake_pcs[2] = {reinterpret_cast<uintptr_t>(&dummy_func),
reinterpret_cast<uintptr_t>(&dummy_func)};

// Register two modules at program launch (same time they'd normally be registered).
// Triggering the bug requires loading an empty module, then a non-empty module after it.
bool dummy = []() {
// First, simulate loading an empty module.
__sanitizer_cov_8bit_counters_init(empty_8bit_counters, empty_8bit_counters);
__sanitizer_cov_pcs_init(empty_pcs, empty_pcs);

// Next, simulate loading a non-empty module.
__sanitizer_cov_8bit_counters_init(fake_8bit_counters,
fake_8bit_counters + 1);
__sanitizer_cov_pcs_init(fake_pcs, fake_pcs + 2);

return true;
}();

static volatile int Sink;

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
assert(Data);
if (Size > 0 && Data[0] == 'H') {
Sink = 1;
if (Size > 1 && Data[1] == 'i') {
Sink = 2;
if (Size > 2 && Data[2] == '!') {
std::cout << "BINGO; Found the target, exiting\n" << std::flush;
exit(0);
}
}
}
return 0;
}
7 changes: 7 additions & 0 deletions compiler-rt/test/fuzzer/empty-module.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CHECK: BINGO
RUN: %cpp_compiler %S/SimulateEmptyModuleTest.cpp -o %t-SimulateEmptyModuleTest

RUN: not %run %t-SimulateEmptyModuleTest 2>&1 | FileCheck %s

# only_ascii mode. Will perform some minimal self-validation.
RUN: not %run %t-SimulateEmptyModuleTest -only_ascii=1 2>&1