summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Driver/ToolChains/MSVC.cpp13
-rw-r--r--compiler-rt/cmake/config-ix.cmake2
-rw-r--r--compiler-rt/lib/fuzzer/FuzzerDefs.h7
-rw-r--r--compiler-rt/lib/fuzzer/FuzzerIO.cpp8
-rw-r--r--compiler-rt/lib/fuzzer/FuzzerIO.h2
-rw-r--r--compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp7
-rw-r--r--compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp20
-rw-r--r--compiler-rt/lib/fuzzer/FuzzerTracePC.cpp3
-rw-r--r--compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp4
-rw-r--r--compiler-rt/lib/fuzzer/tests/CMakeLists.txt2
-rw-r--r--compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp7
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_sections.cc53
-rw-r--r--compiler-rt/test/CMakeLists.txt5
-rw-r--r--llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp39
-rw-r--r--llvm/test/Instrumentation/SanitizerCoverage/coff-pc-table-inline-8bit-counters.ll12
15 files changed, 158 insertions, 26 deletions
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index d062c6abc95..4df43ac8ce9 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -365,6 +365,17 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName));
}
+ if (TC.getSanitizerArgs().needsFuzzer()) {
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back(
+ Args.MakeArgString(std::string("-wholearchive:") +
+ TC.getCompilerRTArgString(Args, "fuzzer", false)));
+ CmdArgs.push_back(Args.MakeArgString("-debug"));
+ // Prevent the linker from padding sections we use for instrumentation
+ // arrays.
+ CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
+ }
+
if (TC.getSanitizerArgs().needsAsanRt()) {
CmdArgs.push_back(Args.MakeArgString("-debug"));
CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
@@ -1298,6 +1309,8 @@ MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
SanitizerMask MSVCToolChain::getSupportedSanitizers() const {
SanitizerMask Res = ToolChain::getSupportedSanitizers();
Res |= SanitizerKind::Address;
+ Res |= SanitizerKind::Fuzzer;
+ Res |= SanitizerKind::FuzzerNoLink;
Res &= ~SanitizerKind::CFIMFCall;
return Res;
}
diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake
index f3935ffd6fd..ad2f9192391 100644
--- a/compiler-rt/cmake/config-ix.cmake
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -619,7 +619,7 @@ else()
endif()
if (COMPILER_RT_HAS_SANITIZER_COMMON AND FUZZER_SUPPORTED_ARCH AND
- OS_NAME MATCHES "Android|Darwin|Linux|NetBSD|FreeBSD|OpenBSD|Fuchsia")
+ OS_NAME MATCHES "Android|Darwin|Linux|NetBSD|FreeBSD|OpenBSD|Fuchsia|Windows")
set(COMPILER_RT_HAS_FUZZER TRUE)
else()
set(COMPILER_RT_HAS_FUZZER FALSE)
diff --git a/compiler-rt/lib/fuzzer/FuzzerDefs.h b/compiler-rt/lib/fuzzer/FuzzerDefs.h
index a35c7a181b7..31655d562cd 100644
--- a/compiler-rt/lib/fuzzer/FuzzerDefs.h
+++ b/compiler-rt/lib/fuzzer/FuzzerDefs.h
@@ -129,8 +129,15 @@
#if LIBFUZZER_WINDOWS
#define ATTRIBUTE_INTERFACE __declspec(dllexport)
+// This is used for __sancov_lowest_stack which is needed for
+// -fsanitize-coverage=stack-depth. That feature is not yet available on
+// Windows, so make the symbol static to avoid linking errors.
+#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC \
+ __attribute__((tls_model("initial-exec"))) thread_local static
#else
#define ATTRIBUTE_INTERFACE __attribute__((visibility("default")))
+#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC \
+ ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec"))) thread_local
#endif
namespace fuzzer {
diff --git a/compiler-rt/lib/fuzzer/FuzzerIO.cpp b/compiler-rt/lib/fuzzer/FuzzerIO.cpp
index f3ead0ec535..dac5ec658f1 100644
--- a/compiler-rt/lib/fuzzer/FuzzerIO.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerIO.cpp
@@ -100,14 +100,6 @@ std::string DirPlusFile(const std::string &DirPath,
return DirPath + GetSeparator() + FileName;
}
-std::string Basename(const std::string &Path, char Separator) {
- size_t Pos = Path.rfind(Separator);
- if (Pos == std::string::npos)
- return Path;
- assert(Pos < Path.size());
- return Path.substr(Pos + 1);
-}
-
void DupAndCloseStderr() {
int OutputFd = DuplicateFile(2);
if (OutputFd > 0) {
diff --git a/compiler-rt/lib/fuzzer/FuzzerIO.h b/compiler-rt/lib/fuzzer/FuzzerIO.h
index 6d7757435b7..b4a68190e78 100644
--- a/compiler-rt/lib/fuzzer/FuzzerIO.h
+++ b/compiler-rt/lib/fuzzer/FuzzerIO.h
@@ -68,7 +68,7 @@ void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V);
char GetSeparator();
// Similar to the basename utility: returns the file name w/o the dir prefix.
-std::string Basename(const std::string &Path, char Separator = GetSeparator());
+std::string Basename(const std::string &Path);
FILE* OpenFile(int Fd, const char *Mode);
diff --git a/compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp b/compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp
index 17e884d3c4c..401b4cbbf74 100644
--- a/compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp
@@ -46,6 +46,13 @@ size_t FileSize(const std::string &Path) {
return St.st_size;
}
+std::string Basename(const std::string &Path) {
+ size_t Pos = Path.rfind(GetSeparator());
+ if (Pos == std::string::npos) return Path;
+ assert(Pos < Path.size());
+ return Path.substr(Pos + 1);
+}
+
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
Vector<std::string> *V, bool TopDir) {
auto E = GetEpoch(Dir);
diff --git a/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp b/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp
index 74853646b21..314b79d0f81 100644
--- a/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp
@@ -72,6 +72,26 @@ bool IsFile(const std::string &Path) {
return IsFile(Path, Att);
}
+std::string Basename(const std::string &Path) {
+ size_t Pos = Path.find_last_of("/\\");
+ if (Pos == std::string::npos) return Path;
+ assert(Pos < Path.size());
+ return Path.substr(Pos + 1);
+}
+
+size_t FileSize(const std::string &Path) {
+ WIN32_FILE_ATTRIBUTE_DATA attr;
+ if (!GetFileAttributesExA(Path.c_str(), GetFileExInfoStandard, &attr)) {
+ Printf("GetFileAttributesExA() failed for \"%s\" (Error code: %lu).\n",
+ Path.c_str(), GetLastError());
+ return 0;
+ }
+ ULARGE_INTEGER size;
+ size.HighPart = attr.nFileSizeHigh;
+ size.LowPart = attr.nFileSizeLow;
+ return size.QuadPart;
+}
+
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
Vector<std::string> *V, bool TopDir) {
auto E = GetEpoch(Dir);
diff --git a/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp b/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp
index 1aba816e832..75130840ce0 100644
--- a/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp
@@ -32,8 +32,7 @@ ATTRIBUTE_INTERFACE
uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs];
// Used by -fsanitize-coverage=stack-depth to track stack depth
-ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec")))
-thread_local uintptr_t __sancov_lowest_stack;
+ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC uintptr_t __sancov_lowest_stack;
namespace fuzzer {
diff --git a/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp
index 8227e778ea0..257723b6050 100644
--- a/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp
@@ -179,7 +179,9 @@ const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
}
std::string DisassembleCmd(const std::string &FileName) {
- if (ExecuteCommand("dumpbin /summary > nul") == 0)
+ Vector<std::string> command_vector;
+ command_vector.push_back("dumpbin /summary > nul");
+ if (ExecuteCommand(Command(command_vector)) == 0)
return "dumpbin /disasm " + FileName;
Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
exit(1);
diff --git a/compiler-rt/lib/fuzzer/tests/CMakeLists.txt b/compiler-rt/lib/fuzzer/tests/CMakeLists.txt
index ed580716830..0b561c170ec 100644
--- a/compiler-rt/lib/fuzzer/tests/CMakeLists.txt
+++ b/compiler-rt/lib/fuzzer/tests/CMakeLists.txt
@@ -17,6 +17,8 @@ list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS --driver-mode=g++)
if(APPLE OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lc++ -lpthread)
+elseif(WIN32)
+ list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lstdc++)
else()
list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lstdc++ -lpthread)
endif()
diff --git a/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp b/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp
index e3b06702603..7cdd4458232 100644
--- a/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp
+++ b/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp
@@ -34,6 +34,13 @@ TEST(Fuzzer, Basename) {
EXPECT_EQ(Basename("/bar"), "bar");
EXPECT_EQ(Basename("foo/x"), "x");
EXPECT_EQ(Basename("foo/"), "");
+#if LIBFUZZER_WINDOWS
+ EXPECT_EQ(Basename("foo\\bar"), "bar");
+ EXPECT_EQ(Basename("foo\\bar/baz"), "baz");
+ EXPECT_EQ(Basename("\\bar"), "bar");
+ EXPECT_EQ(Basename("foo\\x"), "x");
+ EXPECT_EQ(Basename("foo\\"), "");
+#endif
}
TEST(Fuzzer, CrossOver) {
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_sections.cc b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_sections.cc
index 4b0bbf1ed1e..108f76effee 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_sections.cc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_sections.cc
@@ -7,16 +7,57 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines delimiters for Sanitizer Coverage's section.
+// This file defines delimiters for Sanitizer Coverage's section. It contains
+// Windows specific tricks to coax the linker into giving us the start and stop
+// addresses of a section, as ELF linkers can do, to get the size of certain
+// arrays. According to https://msdn.microsoft.com/en-us/library/7977wcck.aspx
+// sections with the same name before "$" are sorted alphabetically by the
+// string that comes after "$" and merged into one section. We take advantage
+// of this by putting data we want the size of into the middle (M) of a section,
+// by using the letter "M" after "$". We get the start of this data (ie:
+// __start_section_name) by making the start variable come at the start of the
+// section (using the letter A after "$"). We do the same to get the end of the
+// data by using the letter "Z" after "$" to make the end variable come after
+// the data. Note that because of our technique the address of the start
+// variable is actually the address of data that comes before our middle
+// section. We also need to prevent the linker from adding any padding. Each
+// technique we use for this is explained in the comments below.
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
#if SANITIZER_WINDOWS
#include <stdint.h>
-#pragma section(".SCOV$A", read, write) // NOLINT
-#pragma section(".SCOV$Z", read, write) // NOLINT
extern "C" {
-__declspec(allocate(".SCOV$A")) uint32_t __start___sancov_guards = 0;
-__declspec(allocate(".SCOV$Z")) uint32_t __stop___sancov_guards = 0;
+// The Guard array and counter array should both be merged into the .data
+// section to reduce the number of PE sections However, because PCTable is
+// constant it should be merged with the .rdata section.
+#pragma section(".SCOV$GA", read, write) // NOLINT
+// Use align(1) to avoid adding any padding that will mess up clients trying to
+// determine the start and end of the array.
+__declspec(allocate(".SCOV$GA")) __declspec(align(1)) uint64_t
+ __start___sancov_guards = 0;
+#pragma section(".SCOV$GZ", read, write) // NOLINT
+__declspec(allocate(".SCOV$GZ")) __declspec(align(1)) uint64_t
+ __stop___sancov_guards = 0;
+
+#pragma section(".SCOV$CA", read, write) // NOLINT
+__declspec(allocate(".SCOV$CA")) __declspec(align(1)) uint64_t
+ __start___sancov_cntrs = 0;
+#pragma section(".SCOV$CZ", read, write) // NOLINT
+__declspec(allocate(".SCOV$CZ")) __declspec(align(1)) uint64_t
+ __stop___sancov_cntrs = 0;
+
+#pragma comment(linker, "/MERGE:.SCOV=.data")
+
+// Use uint64_t so there won't be any issues if the linker tries to word align
+// the pc array.
+#pragma section(".SCOVP$A", read) // NOLINT
+__declspec(allocate(".SCOVP$A")) __declspec(align(1)) uint64_t
+ __start___sancov_pcs = 0;
+#pragma section(".SCOVP$Z", read) // NOLINT
+__declspec(allocate(".SCOVP$Z")) __declspec(align(1)) uint64_t
+ __stop___sancov_pcs = 0;
+
+#pragma comment(linker, "/MERGE:.SCOVP=.rdata")
}
-#endif // SANITIZER_WINDOWS
+#endif // SANITIZER_WINDOWS
diff --git a/compiler-rt/test/CMakeLists.txt b/compiler-rt/test/CMakeLists.txt
index 554ba5fa0f0..0a3fc025419 100644
--- a/compiler-rt/test/CMakeLists.txt
+++ b/compiler-rt/test/CMakeLists.txt
@@ -62,7 +62,10 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
compiler_rt_test_runtime(sanitizer_common)
# OpenBSD not supporting asan, cannot run the tests
- if(COMPILER_RT_BUILD_LIBFUZZER AND NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD" AND NOT ANDROID)
+ # Tests are broken for now on Windows
+ if(COMPILER_RT_BUILD_LIBFUZZER
+ AND NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD"
+ AND NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows" AND NOT ANDROID)
compiler_rt_test_runtime(fuzzer)
endif()
diff --git a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
index c0b219d1d1b..1f97e909851 100644
--- a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
+++ b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
@@ -273,9 +273,20 @@ Function *SanitizerCoverageModule::CreateInitCallsForSections(
auto SecStart = SecStartEnd.first;
auto SecEnd = SecStartEnd.second;
Function *CtorFunc;
+ Value *SecStartPtr = nullptr;
+ // Account for the fact that on windows-msvc __start_* symbols actually
+ // point to a uint64_t before the start of the array.
+ if (TargetTriple.getObjectFormat() == Triple::COFF) {
+ auto SecStartI8Ptr = IRB.CreatePointerCast(SecStart, Int8PtrTy);
+ auto GEP = IRB.CreateGEP(SecStartI8Ptr,
+ ConstantInt::get(IntptrTy, sizeof(uint64_t)));
+ SecStartPtr = IRB.CreatePointerCast(GEP, Ty);
+ } else {
+ SecStartPtr = IRB.CreatePointerCast(SecStart, Ty);
+ }
std::tie(CtorFunc, std::ignore) = createSanitizerCtorAndInitFunctions(
M, SanCovModuleCtorName, InitFunctionName, {Ty, Ty},
- {IRB.CreatePointerCast(SecStart, Ty), IRB.CreatePointerCast(SecEnd, Ty)});
+ {SecStartPtr, IRB.CreatePointerCast(SecEnd, Ty)});
if (TargetTriple.supportsCOMDAT()) {
// Use comdat to dedup CtorFunc.
@@ -397,9 +408,20 @@ bool SanitizerCoverageModule::runOnModule(Module &M) {
Function *InitFunction = declareSanitizerInitFunction(
M, SanCovPCsInitName, {IntptrPtrTy, IntptrPtrTy});
IRBuilder<> IRBCtor(Ctor->getEntryBlock().getTerminator());
- IRBCtor.CreateCall(InitFunction,
- {IRB.CreatePointerCast(SecStartEnd.first, IntptrPtrTy),
- IRB.CreatePointerCast(SecStartEnd.second, IntptrPtrTy)});
+ Value *SecStartPtr = nullptr;
+ // Account for the fact that on windows-msvc __start_pc_table actually
+ // points to a uint64_t before the start of the PC table.
+ if (TargetTriple.getObjectFormat() == Triple::COFF) {
+ auto SecStartI8Ptr = IRB.CreatePointerCast(SecStartEnd.first, Int8PtrTy);
+ auto GEP = IRB.CreateGEP(SecStartI8Ptr,
+ ConstantInt::get(IntptrTy, sizeof(uint64_t)));
+ SecStartPtr = IRB.CreatePointerCast(GEP, IntptrPtrTy);
+ } else {
+ SecStartPtr = IRB.CreatePointerCast(SecStartEnd.first, IntptrPtrTy);
+ }
+ IRBCtor.CreateCall(
+ InitFunction,
+ {SecStartPtr, IRB.CreatePointerCast(SecStartEnd.second, IntptrPtrTy)});
}
// We don't reference these arrays directly in any of our runtime functions,
// so we need to prevent them from being dead stripped.
@@ -809,8 +831,13 @@ void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, BasicBlock &BB,
std::string
SanitizerCoverageModule::getSectionName(const std::string &Section) const {
- if (TargetTriple.getObjectFormat() == Triple::COFF)
- return ".SCOV$M";
+ if (TargetTriple.getObjectFormat() == Triple::COFF) {
+ if (Section == SanCovCountersSectionName)
+ return ".SCOV$CM";
+ if (Section == SanCovPCsSectionName)
+ return ".SCOVP$M";
+ return ".SCOV$GM"; // For SanCovGuardsSectionName.
+ }
if (TargetTriple.isOSBinFormatMachO())
return "__DATA,__" + Section;
return "__" + Section;
diff --git a/llvm/test/Instrumentation/SanitizerCoverage/coff-pc-table-inline-8bit-counters.ll b/llvm/test/Instrumentation/SanitizerCoverage/coff-pc-table-inline-8bit-counters.ll
new file mode 100644
index 00000000000..d81d480009b
--- /dev/null
+++ b/llvm/test/Instrumentation/SanitizerCoverage/coff-pc-table-inline-8bit-counters.ll
@@ -0,0 +1,12 @@
+; Checks that the PC and 8-bit Counter Arrays are placed in their own sections in COFF binaries.
+; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -sanitizer-coverage-inline-8bit-counters=1 -sanitizer-coverage-pc-table=1 -S | FileCheck %s
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.14.26433"
+
+define void @foo() {
+entry:
+ ret void
+}
+
+; CHECK-DAG: section ".SCOV{{\$}}CM",
+; CHECK-DAG: section ".SCOVP{{\$}}M",
OpenPOWER on IntegriCloud