[libFuzzer][MSVC] Make Sanitizer Coverage MSVC-compatible

Summary:
Make Sanitizer Coverage work when compiled work when compiler-rt
is compiled with MSVC.

The previous solution did not work for MSVC because MSVC tried to
align the .SCOV$CZ section even though we used
__declspec(align(1)) on its only symbol:
__stop___sancov_cntrs.
Because the counter array is composed
of 1 byte elements, it does not always end on an 8 or 4 byte
boundary. This means that padding was sometimes added to
added to align the next section, .SCOV$CZ.
Use a different strategy now: instead of only instructing
the compiler not to align the symbol, make the section
one byte long by making its only symbol a uint8_t, so that
the linker won't try to align it.

Reviewers: morehouse, rnk

Reviewed By: rnk

Subscribers: kubamracek

Differential Revision: https://reviews.llvm.org/D56866

llvm-svn: 351714
This commit is contained in:
Jonathan Metzman 2019-01-21 02:15:29 +00:00
parent a35df433bf
commit dd467f4f43
1 changed files with 25 additions and 20 deletions

View File

@ -26,35 +26,40 @@
#include "sanitizer_platform.h"
#if SANITIZER_WINDOWS
#include <stdint.h>
extern "C" {
// 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;
extern "C" {
// Use uint64_t so the linker won't need to add any padding if it tries to word
// align the start of the 8-bit counters array. The array will always start 8
// bytes after __start_sancov_cntrs.
#pragma section(".SCOV$CA", read, write) // NOLINT
__declspec(allocate(".SCOV$CA")) __declspec(align(1)) uint64_t
__start___sancov_cntrs = 0;
__declspec(allocate(".SCOV$CA")) uint64_t __start___sancov_cntrs = 0;
// Even though we said not to align __stop__sancov_cntrs (using the "align"
// declspec), MSVC's linker may try to align the section, .SCOV$CZ, containing
// it. This can cause a mismatch between the number of PCs and counters since
// each PCTable element is 8 bytes (unlike counters which are 1 byte) so no
// padding would be added to align .SCOVP$Z, However, if .SCOV$CZ section is 1
// byte, the linker won't try to align it on an 8-byte boundary, so use a
// uint8_t for __stop_sancov_cntrs.
#pragma section(".SCOV$CZ", read, write) // NOLINT
__declspec(allocate(".SCOV$CZ")) __declspec(align(1)) uint64_t
__declspec(allocate(".SCOV$CZ")) __declspec(align(1)) uint8_t
__stop___sancov_cntrs = 0;
#pragma section(".SCOV$GA", read, write) // NOLINT
__declspec(allocate(".SCOV$GA")) uint64_t __start___sancov_guards = 0;
#pragma section(".SCOV$GZ", read, write) // NOLINT
__declspec(allocate(".SCOV$GZ")) __declspec(align(1)) uint8_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 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;
__declspec(allocate(".SCOVP$A")) uint64_t __start___sancov_pcs = 0;
#pragma section(".SCOVP$Z", read) // NOLINT
__declspec(allocate(".SCOVP$Z")) __declspec(align(1)) uint64_t
__declspec(allocate(".SCOVP$Z")) __declspec(align(1)) uint8_t
__stop___sancov_pcs = 0;
#pragma comment(linker, "/MERGE:.SCOVP=.rdata")