2017-10-20 06:07:16 +08:00
|
|
|
//===- AddressSanitizer.cpp - memory error detector -----------------------===//
|
2011-11-16 09:35:23 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2011-11-16 09:35:23 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file is a part of AddressSanitizer, an address sanity checker.
|
|
|
|
// Details of the algorithm:
|
2017-11-14 07:47:58 +08:00
|
|
|
// https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm
|
2011-11-16 09:35:23 +08:00
|
|
|
//
|
2020-06-30 05:46:25 +08:00
|
|
|
// FIXME: This sanitizer does not yet handle scalable vectors
|
|
|
|
//
|
2011-11-16 09:35:23 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
|
2011-11-16 09:35:23 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2012-12-27 16:50:58 +08:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2012-12-25 20:04:36 +08:00
|
|
|
#include "llvm/ADT/DepthFirstIterator.h"
|
2018-06-12 19:16:56 +08:00
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
2011-11-16 09:35:23 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2013-10-16 22:06:14 +08:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2011-11-16 09:35:23 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2017-10-20 06:07:16 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2012-05-23 19:52:12 +08:00
|
|
|
#include "llvm/ADT/Triple.h"
|
2017-07-19 06:28:03 +08:00
|
|
|
#include "llvm/ADT/Twine.h"
|
2015-03-04 21:27:53 +08:00
|
|
|
#include "llvm/Analysis/MemoryBuiltins.h"
|
|
|
|
#include "llvm/Analysis/TargetLibraryInfo.h"
|
|
|
|
#include "llvm/Analysis/ValueTracking.h"
|
2017-10-20 06:07:16 +08:00
|
|
|
#include "llvm/BinaryFormat/MachO.h"
|
2017-07-19 06:28:03 +08:00
|
|
|
#include "llvm/IR/Argument.h"
|
2017-10-20 06:07:16 +08:00
|
|
|
#include "llvm/IR/Attributes.h"
|
|
|
|
#include "llvm/IR/BasicBlock.h"
|
|
|
|
#include "llvm/IR/Comdat.h"
|
|
|
|
#include "llvm/IR/Constant.h"
|
|
|
|
#include "llvm/IR/Constants.h"
|
2014-03-06 08:22:06 +08:00
|
|
|
#include "llvm/IR/DIBuilder.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/DataLayout.h"
|
2017-10-20 06:07:16 +08:00
|
|
|
#include "llvm/IR/DebugInfoMetadata.h"
|
|
|
|
#include "llvm/IR/DebugLoc.h"
|
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
2014-12-01 16:47:58 +08:00
|
|
|
#include "llvm/IR/Dominators.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/Function.h"
|
2017-10-20 06:07:16 +08:00
|
|
|
#include "llvm/IR/GlobalAlias.h"
|
|
|
|
#include "llvm/IR/GlobalValue.h"
|
|
|
|
#include "llvm/IR/GlobalVariable.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/IRBuilder.h"
|
|
|
|
#include "llvm/IR/InlineAsm.h"
|
2014-03-06 11:23:41 +08:00
|
|
|
#include "llvm/IR/InstVisitor.h"
|
2017-10-20 06:07:16 +08:00
|
|
|
#include "llvm/IR/InstrTypes.h"
|
|
|
|
#include "llvm/IR/Instruction.h"
|
|
|
|
#include "llvm/IR/Instructions.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
2017-10-20 06:07:16 +08:00
|
|
|
#include "llvm/IR/Intrinsics.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/LLVMContext.h"
|
[asan] extend asan-coverage (still experimental).
- add a mode for collecting per-block coverage (-asan-coverage=2).
So far the implementation is naive (all blocks are instrumented),
the performance overhead on top of asan could be as high as 30%.
- Make sure the one-time calls to __sanitizer_cov are moved to function buttom,
which in turn required to copy the original debug info into the call insn.
Here is the performance data on SPEC 2006
(train data, comparing asan with asan-coverage={0,1,2}):
asan+cov0 asan+cov1 diff 0-1 asan+cov2 diff 0-2 diff 1-2
400.perlbench, 65.60, 65.80, 1.00, 76.20, 1.16, 1.16
401.bzip2, 65.10, 65.50, 1.01, 75.90, 1.17, 1.16
403.gcc, 1.64, 1.69, 1.03, 2.04, 1.24, 1.21
429.mcf, 21.90, 22.60, 1.03, 23.20, 1.06, 1.03
445.gobmk, 166.00, 169.00, 1.02, 205.00, 1.23, 1.21
456.hmmer, 88.30, 87.90, 1.00, 91.00, 1.03, 1.04
458.sjeng, 210.00, 222.00, 1.06, 258.00, 1.23, 1.16
462.libquantum, 1.73, 1.75, 1.01, 2.11, 1.22, 1.21
464.h264ref, 147.00, 152.00, 1.03, 160.00, 1.09, 1.05
471.omnetpp, 115.00, 116.00, 1.01, 140.00, 1.22, 1.21
473.astar, 133.00, 131.00, 0.98, 142.00, 1.07, 1.08
483.xalancbmk, 118.00, 120.00, 1.02, 154.00, 1.31, 1.28
433.milc, 19.80, 20.00, 1.01, 20.10, 1.02, 1.01
444.namd, 16.20, 16.20, 1.00, 17.60, 1.09, 1.09
447.dealII, 41.80, 42.20, 1.01, 43.50, 1.04, 1.03
450.soplex, 7.51, 7.82, 1.04, 8.25, 1.10, 1.05
453.povray, 14.00, 14.40, 1.03, 15.80, 1.13, 1.10
470.lbm, 33.30, 34.10, 1.02, 34.10, 1.02, 1.00
482.sphinx3, 12.40, 12.30, 0.99, 13.00, 1.05, 1.06
llvm-svn: 199488
2014-01-17 19:00:30 +08:00
|
|
|
#include "llvm/IR/MDBuilder.h"
|
2017-10-20 06:07:16 +08:00
|
|
|
#include "llvm/IR/Metadata.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#include "llvm/IR/Type.h"
|
2017-10-20 06:07:16 +08:00
|
|
|
#include "llvm/IR/Use.h"
|
|
|
|
#include "llvm/IR/Value.h"
|
Sink all InitializePasses.h includes
This file lists every pass in LLVM, and is included by Pass.h, which is
very popular. Every time we add, remove, or rename a pass in LLVM, it
caused lots of recompilation.
I found this fact by looking at this table, which is sorted by the
number of times a file was changed over the last 100,000 git commits
multiplied by the number of object files that depend on it in the
current checkout:
recompiles touches affected_files header
342380 95 3604 llvm/include/llvm/ADT/STLExtras.h
314730 234 1345 llvm/include/llvm/InitializePasses.h
307036 118 2602 llvm/include/llvm/ADT/APInt.h
213049 59 3611 llvm/include/llvm/Support/MathExtras.h
170422 47 3626 llvm/include/llvm/Support/Compiler.h
162225 45 3605 llvm/include/llvm/ADT/Optional.h
158319 63 2513 llvm/include/llvm/ADT/Triple.h
140322 39 3598 llvm/include/llvm/ADT/StringRef.h
137647 59 2333 llvm/include/llvm/Support/Error.h
131619 73 1803 llvm/include/llvm/Support/FileSystem.h
Before this change, touching InitializePasses.h would cause 1345 files
to recompile. After this change, touching it only causes 550 compiles in
an incremental rebuild.
Reviewers: bkramer, asbirlea, bollu, jdoerfert
Differential Revision: https://reviews.llvm.org/D70211
2019-11-14 05:15:01 +08:00
|
|
|
#include "llvm/InitializePasses.h"
|
2014-12-06 06:19:18 +08:00
|
|
|
#include "llvm/MC/MCSectionMachO.h"
|
2017-10-20 06:07:16 +08:00
|
|
|
#include "llvm/Pass.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
2011-11-16 09:35:23 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
#include "llvm/Support/Debug.h"
|
2017-10-20 06:07:16 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/MathExtras.h"
|
2017-07-19 06:28:03 +08:00
|
|
|
#include "llvm/Support/ScopedPrinter.h"
|
2015-03-24 03:32:43 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2016-04-18 17:17:29 +08:00
|
|
|
#include "llvm/Transforms/Instrumentation.h"
|
2020-04-30 17:05:00 +08:00
|
|
|
#include "llvm/Transforms/Instrumentation/AddressSanitizerCommon.h"
|
2013-12-06 17:00:17 +08:00
|
|
|
#include "llvm/Transforms/Utils/ASanStackFrameLayout.h"
|
2011-11-16 09:35:23 +08:00
|
|
|
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
2019-02-14 06:22:48 +08:00
|
|
|
#include "llvm/Transforms/Utils/Local.h"
|
2011-11-16 09:35:23 +08:00
|
|
|
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
2015-02-27 11:12:36 +08:00
|
|
|
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
|
2011-11-16 09:35:23 +08:00
|
|
|
#include <algorithm>
|
2017-10-20 06:07:16 +08:00
|
|
|
#include <cassert>
|
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
2016-08-21 02:34:39 +08:00
|
|
|
#include <iomanip>
|
2016-08-30 02:17:21 +08:00
|
|
|
#include <limits>
|
2017-10-20 06:07:16 +08:00
|
|
|
#include <memory>
|
2016-08-21 02:34:39 +08:00
|
|
|
#include <sstream>
|
2012-12-04 00:50:05 +08:00
|
|
|
#include <string>
|
2017-10-20 06:07:16 +08:00
|
|
|
#include <tuple>
|
2011-11-16 09:35:23 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
2014-04-22 10:55:47 +08:00
|
|
|
#define DEBUG_TYPE "asan"
|
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
static const uint64_t kDefaultShadowScale = 3;
|
|
|
|
static const uint64_t kDefaultShadowOffset32 = 1ULL << 29;
|
|
|
|
static const uint64_t kDefaultShadowOffset64 = 1ULL << 44;
|
2017-10-20 06:07:16 +08:00
|
|
|
static const uint64_t kDynamicShadowSentinel =
|
|
|
|
std::numeric_limits<uint64_t>::max();
|
2017-11-17 01:03:00 +08:00
|
|
|
static const uint64_t kSmallX86_64ShadowOffsetBase = 0x7FFFFFFF; // < 2G.
|
|
|
|
static const uint64_t kSmallX86_64ShadowOffsetAlignMask = ~0xFFFULL;
|
2015-06-19 20:19:07 +08:00
|
|
|
static const uint64_t kLinuxKasan_ShadowOffset64 = 0xdffffc0000000000;
|
2017-12-08 06:53:33 +08:00
|
|
|
static const uint64_t kPPC64_ShadowOffset64 = 1ULL << 44;
|
[ASan] Add shadow offset for SystemZ.
SystemZ on Linux currently has 53-bit address space. In theory, the hardware
could support a full 64-bit address space, but that's not supported due to
kernel limitations (it'd require 5-level page tables), and there are no plans
for that. The default process layout stays within first 4TB of address space
(to avoid creating 4-level page tables), so any offset >= (1 << 42) is fine.
Let's use 1 << 52 here, ie. exactly half the address space.
I've originally used 7 << 50 (uses top 1/8th of the address space), but ASan
runtime assumes there's some space after the shadow area. While this is
fixable, it's simpler to avoid the issue entirely.
Also, I've originally wanted to have the shadow aligned to 1/8th the address
space, so that we can use OR like X86 to assemble the offset. I no longer
think it's a good idea, since using ADD enables us to load the constant just
once and use it with register + register indexed addressing.
Differential Revision: http://reviews.llvm.org/D19650
llvm-svn: 268161
2016-04-30 17:57:34 +08:00
|
|
|
static const uint64_t kSystemZ_ShadowOffset64 = 1ULL << 52;
|
2014-11-05 03:46:15 +08:00
|
|
|
static const uint64_t kMIPS32_ShadowOffset32 = 0x0aaa0000;
|
2015-01-31 18:43:18 +08:00
|
|
|
static const uint64_t kMIPS64_ShadowOffset64 = 1ULL << 37;
|
2015-02-03 19:20:45 +08:00
|
|
|
static const uint64_t kAArch64_ShadowOffset64 = 1ULL << 36;
|
2014-02-10 15:37:04 +08:00
|
|
|
static const uint64_t kFreeBSD_ShadowOffset32 = 1ULL << 30;
|
|
|
|
static const uint64_t kFreeBSD_ShadowOffset64 = 1ULL << 46;
|
2018-05-11 08:58:01 +08:00
|
|
|
static const uint64_t kNetBSD_ShadowOffset32 = 1ULL << 30;
|
2017-08-29 06:13:52 +08:00
|
|
|
static const uint64_t kNetBSD_ShadowOffset64 = 1ULL << 46;
|
2018-12-16 00:32:41 +08:00
|
|
|
static const uint64_t kNetBSDKasan_ShadowOffset64 = 0xdfff900000000000;
|
2017-02-24 01:10:28 +08:00
|
|
|
static const uint64_t kPS4CPU_ShadowOffset64 = 1ULL << 40;
|
2015-01-22 20:24:21 +08:00
|
|
|
static const uint64_t kWindowsShadowOffset32 = 3ULL << 28;
|
[WebAssembly] Implement Address Sanitizer for Emscripten
Summary:
This diff enables address sanitizer on Emscripten.
On Emscripten, real memory starts at the value passed to --global-base.
All memory before this is used as shadow memory, and thus the shadow mapping
function is simply dividing by 8.
Reviewers: tlively, aheejin, sbc100
Reviewed By: sbc100
Subscribers: dschuff, sbc100, jgravelle-google, hiraditya, sunfish, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D63742
llvm-svn: 364468
2019-06-27 04:16:14 +08:00
|
|
|
static const uint64_t kEmscriptenShadowOffset = 0;
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2018-05-18 12:10:38 +08:00
|
|
|
static const uint64_t kMyriadShadowScale = 5;
|
|
|
|
static const uint64_t kMyriadMemoryOffset32 = 0x80000000ULL;
|
|
|
|
static const uint64_t kMyriadMemorySize32 = 0x20000000ULL;
|
|
|
|
static const uint64_t kMyriadTagShift = 29;
|
|
|
|
static const uint64_t kMyriadDDRTag = 4;
|
|
|
|
static const uint64_t kMyriadCacheBitMask32 = 0x40000000ULL;
|
|
|
|
|
2016-10-01 01:46:32 +08:00
|
|
|
// The shadow memory space is dynamically allocated.
|
|
|
|
static const uint64_t kWindowsShadowOffset64 = kDynamicShadowSentinel;
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
static const size_t kMinStackMallocSize = 1 << 6; // 64B
|
2011-11-16 09:35:23 +08:00
|
|
|
static const size_t kMaxStackMallocSize = 1 << 16; // 64K
|
|
|
|
static const uintptr_t kCurrentStackFrameMagic = 0x41B58AB3;
|
|
|
|
static const uintptr_t kRetiredStackFrameMagic = 0x45E0360E;
|
|
|
|
|
2013-07-16 09:17:10 +08:00
|
|
|
static const char *const kAsanModuleCtorName = "asan.module_ctor";
|
|
|
|
static const char *const kAsanModuleDtorName = "asan.module_dtor";
|
2015-03-04 21:27:53 +08:00
|
|
|
static const uint64_t kAsanCtorAndDtorPriority = 1;
|
[WebAssembly] Lower ASan constructor priority on Emscripten
Summary:
This change gives Emscripten the ability to use more than one constructor
priorities that runs before ASan. By convention, constructor priorites 0-100
are reserved for use by the system. ASan on Emscripten now uses priority 50,
leaving plenty of room for use by Emscripten before and after ASan.
This change is done in response to:
https://github.com/emscripten-core/emscripten/pull/9076#discussion_r310323723
Reviewers: kripken, tlively, aheejin
Reviewed By: tlively
Subscribers: cfe-commits, dschuff, sbc100, jgravelle-google, hiraditya, sunfish, llvm-commits
Tags: #llvm, #clang
Differential Revision: https://reviews.llvm.org/D65684
llvm-svn: 368101
2019-08-07 05:52:58 +08:00
|
|
|
// On Emscripten, the system needs more than one priorities for constructors.
|
|
|
|
static const uint64_t kAsanEmscriptenCtorAndDtorPriority = 50;
|
2013-07-16 09:17:10 +08:00
|
|
|
static const char *const kAsanReportErrorTemplate = "__asan_report_";
|
|
|
|
static const char *const kAsanRegisterGlobalsName = "__asan_register_globals";
|
2013-08-05 21:19:49 +08:00
|
|
|
static const char *const kAsanUnregisterGlobalsName =
|
|
|
|
"__asan_unregister_globals";
|
2016-03-29 04:28:57 +08:00
|
|
|
static const char *const kAsanRegisterImageGlobalsName =
|
|
|
|
"__asan_register_image_globals";
|
|
|
|
static const char *const kAsanUnregisterImageGlobalsName =
|
|
|
|
"__asan_unregister_image_globals";
|
2017-04-28 04:27:27 +08:00
|
|
|
static const char *const kAsanRegisterElfGlobalsName =
|
|
|
|
"__asan_register_elf_globals";
|
|
|
|
static const char *const kAsanUnregisterElfGlobalsName =
|
|
|
|
"__asan_unregister_elf_globals";
|
2013-07-16 09:17:10 +08:00
|
|
|
static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init";
|
|
|
|
static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init";
|
2015-07-23 18:54:06 +08:00
|
|
|
static const char *const kAsanInitName = "__asan_init";
|
2017-11-21 01:41:57 +08:00
|
|
|
static const char *const kAsanVersionCheckNamePrefix =
|
|
|
|
"__asan_version_mismatch_check_v";
|
2014-02-27 20:45:36 +08:00
|
|
|
static const char *const kAsanPtrCmp = "__sanitizer_ptr_cmp";
|
|
|
|
static const char *const kAsanPtrSub = "__sanitizer_ptr_sub";
|
2013-07-16 09:17:10 +08:00
|
|
|
static const char *const kAsanHandleNoReturnName = "__asan_handle_no_return";
|
2015-03-04 21:27:53 +08:00
|
|
|
static const int kMaxAsanStackMallocSizeClass = 10;
|
2013-09-10 21:16:56 +08:00
|
|
|
static const char *const kAsanStackMallocNameTemplate = "__asan_stack_malloc_";
|
|
|
|
static const char *const kAsanStackFreeNameTemplate = "__asan_stack_free_";
|
2018-07-19 06:23:14 +08:00
|
|
|
static const char *const kAsanGenPrefix = "___asan_gen_";
|
2016-02-08 16:30:57 +08:00
|
|
|
static const char *const kODRGenPrefix = "__odr_asan_gen_";
|
2014-11-19 08:22:58 +08:00
|
|
|
static const char *const kSanCovGenPrefix = "__sancov_gen_";
|
2016-08-21 02:34:39 +08:00
|
|
|
static const char *const kAsanSetShadowPrefix = "__asan_set_shadow_";
|
2013-07-16 09:17:10 +08:00
|
|
|
static const char *const kAsanPoisonStackMemoryName =
|
|
|
|
"__asan_poison_stack_memory";
|
|
|
|
static const char *const kAsanUnpoisonStackMemoryName =
|
2012-12-04 09:34:23 +08:00
|
|
|
"__asan_unpoison_stack_memory";
|
2017-04-28 04:27:27 +08:00
|
|
|
|
|
|
|
// ASan version script has __asan_* wildcard. Triple underscore prevents a
|
|
|
|
// linker (gold) warning about attempting to export a local symbol.
|
2016-03-29 04:28:57 +08:00
|
|
|
static const char *const kAsanGlobalsRegisteredFlagName =
|
2017-04-28 04:27:27 +08:00
|
|
|
"___asan_globals_registered";
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2016-06-02 08:06:42 +08:00
|
|
|
static const char *const kAsanOptionDetectUseAfterReturn =
|
2013-09-18 22:07:14 +08:00
|
|
|
"__asan_option_detect_stack_use_after_return";
|
|
|
|
|
2016-10-01 01:46:32 +08:00
|
|
|
static const char *const kAsanShadowMemoryDynamicAddress =
|
|
|
|
"__asan_shadow_memory_dynamic_address";
|
|
|
|
|
2015-06-12 19:27:06 +08:00
|
|
|
static const char *const kAsanAllocaPoison = "__asan_alloca_poison";
|
|
|
|
static const char *const kAsanAllocasUnpoison = "__asan_allocas_unpoison";
|
2015-05-28 15:51:49 +08:00
|
|
|
|
2012-07-17 00:15:40 +08:00
|
|
|
// Accesses sizes are powers of two: 1, 2, 4, 8, 16.
|
|
|
|
static const size_t kNumberOfAccessSizes = 5;
|
|
|
|
|
2014-11-21 18:29:50 +08:00
|
|
|
static const unsigned kAllocaRzSize = 32;
|
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
// Command-line flags.
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-06-19 20:19:07 +08:00
|
|
|
static cl::opt<bool> ClEnableKasan(
|
|
|
|
"asan-kernel", cl::desc("Enable KernelAddressSanitizer instrumentation"),
|
|
|
|
cl::Hidden, cl::init(false));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-11-11 18:36:49 +08:00
|
|
|
static cl::opt<bool> ClRecover(
|
|
|
|
"asan-recover",
|
|
|
|
cl::desc("Enable recovery mode (continue-after-error)."),
|
|
|
|
cl::Hidden, cl::init(false));
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2019-08-29 04:40:55 +08:00
|
|
|
static cl::opt<bool> ClInsertVersionCheck(
|
|
|
|
"asan-guard-against-version-mismatch",
|
|
|
|
cl::desc("Guard against compiler/runtime version mismatch."),
|
|
|
|
cl::Hidden, cl::init(true));
|
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
// This flag may need to be replaced with -f[no-]asan-reads.
|
|
|
|
static cl::opt<bool> ClInstrumentReads("asan-instrument-reads",
|
2015-03-04 21:27:53 +08:00
|
|
|
cl::desc("instrument read instructions"),
|
|
|
|
cl::Hidden, cl::init(true));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
static cl::opt<bool> ClInstrumentWrites(
|
|
|
|
"asan-instrument-writes", cl::desc("instrument write instructions"),
|
|
|
|
cl::Hidden, cl::init(true));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
static cl::opt<bool> ClInstrumentAtomics(
|
|
|
|
"asan-instrument-atomics",
|
|
|
|
cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,
|
|
|
|
cl::init(true));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
[AddressSanitizer] Instrument byval call arguments
Summary:
In the LLVM IR, "call" instructions read memory for each byval operand.
For example:
```
$ cat blah.c
struct foo { void *a, *b, *c; };
struct bar { struct foo foo; };
void func1(const struct foo);
void func2(struct bar *bar) { func1(bar->foo); }
$ [...]/bin/clang -S -flto -c blah.c -O2 ; cat blah.s
[...]
define dso_local void @func2(%struct.bar* %bar) local_unnamed_addr #0 {
entry:
%foo = getelementptr inbounds %struct.bar, %struct.bar* %bar, i64 0, i32 0
tail call void @func1(%struct.foo* byval(%struct.foo) align 8 %foo) #2
ret void
}
[...]
$ [...]/bin/clang -S -c blah.c -O2 ; cat blah.s
[...]
func2: # @func2
[...]
subq $24, %rsp
[...]
movq 16(%rdi), %rax
movq %rax, 16(%rsp)
movups (%rdi), %xmm0
movups %xmm0, (%rsp)
callq func1
addq $24, %rsp
[...]
retq
```
Let ASAN instrument these hidden memory accesses.
This is patch 4/4 of a patch series:
https://reviews.llvm.org/D77616 [PATCH 1/4] [AddressSanitizer] Refactor ClDebug{Min,Max} handling
https://reviews.llvm.org/D77617 [PATCH 2/4] [AddressSanitizer] Split out memory intrinsic handling
https://reviews.llvm.org/D77618 [PATCH 3/4] [AddressSanitizer] Refactor: Permit >1 interesting operands per instruction
https://reviews.llvm.org/D77619 [PATCH 4/4] [AddressSanitizer] Instrument byval call arguments
Reviewers: kcc, glider
Reviewed By: glider
Subscribers: hiraditya, dexonsmith, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77619
2020-04-30 17:05:01 +08:00
|
|
|
static cl::opt<bool>
|
|
|
|
ClInstrumentByval("asan-instrument-byval",
|
|
|
|
cl::desc("instrument byval call arguments"), cl::Hidden,
|
|
|
|
cl::init(true));
|
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
static cl::opt<bool> ClAlwaysSlowPath(
|
|
|
|
"asan-always-slow-path",
|
|
|
|
cl::desc("use instrumentation with slow path for all accesses"), cl::Hidden,
|
|
|
|
cl::init(false));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2016-10-01 01:46:32 +08:00
|
|
|
static cl::opt<bool> ClForceDynamicShadow(
|
|
|
|
"asan-force-dynamic-shadow",
|
|
|
|
cl::desc("Load shadow address into a local variable for each function"),
|
|
|
|
cl::Hidden, cl::init(false));
|
|
|
|
|
2017-11-21 01:41:57 +08:00
|
|
|
static cl::opt<bool>
|
|
|
|
ClWithIfunc("asan-with-ifunc",
|
|
|
|
cl::desc("Access dynamic shadow through an ifunc global on "
|
|
|
|
"platforms that support this"),
|
|
|
|
cl::Hidden, cl::init(true));
|
|
|
|
|
|
|
|
static cl::opt<bool> ClWithIfuncSuppressRemat(
|
|
|
|
"asan-with-ifunc-suppress-remat",
|
|
|
|
cl::desc("Suppress rematerialization of dynamic shadow address by passing "
|
|
|
|
"it through inline asm in prologue."),
|
|
|
|
cl::Hidden, cl::init(true));
|
|
|
|
|
2012-07-17 00:15:40 +08:00
|
|
|
// This flag limits the number of instructions to be instrumented
|
2012-06-28 17:34:41 +08:00
|
|
|
// in any given BB. Normally, this should be set to unlimited (INT_MAX),
|
|
|
|
// but due to http://llvm.org/bugs/show_bug.cgi?id=12652 we temporary
|
|
|
|
// set it to 10000.
|
2015-03-04 21:27:53 +08:00
|
|
|
static cl::opt<int> ClMaxInsnsToInstrumentPerBB(
|
|
|
|
"asan-max-ins-per-bb", cl::init(10000),
|
|
|
|
cl::desc("maximal number of instructions to instrument in any given BB"),
|
|
|
|
cl::Hidden);
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
// This flag may need to be replaced with -f[no]asan-stack.
|
2015-03-04 21:27:53 +08:00
|
|
|
static cl::opt<bool> ClStack("asan-stack", cl::desc("Handle stack memory"),
|
|
|
|
cl::Hidden, cl::init(true));
|
2016-08-21 04:23:50 +08:00
|
|
|
static cl::opt<uint32_t> ClMaxInlinePoisoningSize(
|
|
|
|
"asan-max-inline-poisoning-size",
|
|
|
|
cl::desc(
|
|
|
|
"Inline shadow poisoning for blocks up to the given size in bytes."),
|
|
|
|
cl::Hidden, cl::init(64));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
static cl::opt<bool> ClUseAfterReturn("asan-use-after-return",
|
2016-04-22 06:00:13 +08:00
|
|
|
cl::desc("Check stack-use-after-return"),
|
2015-03-04 21:27:53 +08:00
|
|
|
cl::Hidden, cl::init(true));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2017-07-19 06:28:03 +08:00
|
|
|
static cl::opt<bool> ClRedzoneByvalArgs("asan-redzone-byval-args",
|
|
|
|
cl::desc("Create redzones for byval "
|
|
|
|
"arguments (extra copy "
|
|
|
|
"required)"), cl::Hidden,
|
|
|
|
cl::init(true));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2016-04-21 04:02:58 +08:00
|
|
|
static cl::opt<bool> ClUseAfterScope("asan-use-after-scope",
|
|
|
|
cl::desc("Check stack-use-after-scope"),
|
|
|
|
cl::Hidden, cl::init(false));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
// This flag may need to be replaced with -f[no]asan-globals.
|
|
|
|
static cl::opt<bool> ClGlobals("asan-globals",
|
2015-03-04 21:27:53 +08:00
|
|
|
cl::desc("Handle global objects"), cl::Hidden,
|
|
|
|
cl::init(true));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2012-08-21 16:24:25 +08:00
|
|
|
static cl::opt<bool> ClInitializers("asan-initialization-order",
|
2015-03-04 21:27:53 +08:00
|
|
|
cl::desc("Handle C++ initializer order"),
|
|
|
|
cl::Hidden, cl::init(true));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
static cl::opt<bool> ClInvalidPointerPairs(
|
|
|
|
"asan-detect-invalid-pointer-pair",
|
|
|
|
cl::desc("Instrument <, <=, >, >=, - with pointer operands"), cl::Hidden,
|
|
|
|
cl::init(false));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2019-03-28 18:51:24 +08:00
|
|
|
static cl::opt<bool> ClInvalidPointerCmp(
|
|
|
|
"asan-detect-invalid-pointer-cmp",
|
|
|
|
cl::desc("Instrument <, <=, >, >= with pointer operands"), cl::Hidden,
|
|
|
|
cl::init(false));
|
|
|
|
|
|
|
|
static cl::opt<bool> ClInvalidPointerSub(
|
|
|
|
"asan-detect-invalid-pointer-sub",
|
|
|
|
cl::desc("Instrument - operations with pointer operands"), cl::Hidden,
|
|
|
|
cl::init(false));
|
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
static cl::opt<unsigned> ClRealignStack(
|
|
|
|
"asan-realign-stack",
|
|
|
|
cl::desc("Realign stack to the value of this flag (power of two)"),
|
|
|
|
cl::Hidden, cl::init(32));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2014-04-16 20:12:19 +08:00
|
|
|
static cl::opt<int> ClInstrumentationWithCallsThreshold(
|
|
|
|
"asan-instrumentation-with-call-threshold",
|
2015-03-04 21:27:53 +08:00
|
|
|
cl::desc(
|
|
|
|
"If the function being instrumented contains more than "
|
|
|
|
"this number of memory accesses, use callbacks instead of "
|
|
|
|
"inline checks (-1 means never use callbacks)."),
|
|
|
|
cl::Hidden, cl::init(7000));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2014-04-16 20:12:19 +08:00
|
|
|
static cl::opt<std::string> ClMemoryAccessCallbackPrefix(
|
2015-03-04 21:27:53 +08:00
|
|
|
"asan-memory-access-callback-prefix",
|
|
|
|
cl::desc("Prefix for memory access callbacks"), cl::Hidden,
|
|
|
|
cl::init("__asan_"));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2016-08-21 01:22:27 +08:00
|
|
|
static cl::opt<bool>
|
|
|
|
ClInstrumentDynamicAllocas("asan-instrument-dynamic-allocas",
|
|
|
|
cl::desc("instrument dynamic allocas"),
|
|
|
|
cl::Hidden, cl::init(true));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
static cl::opt<bool> ClSkipPromotableAllocas(
|
|
|
|
"asan-skip-promotable-allocas",
|
|
|
|
cl::desc("Do not instrument promotable allocas"), cl::Hidden,
|
|
|
|
cl::init(true));
|
2011-11-16 09:35:23 +08:00
|
|
|
|
|
|
|
// These flags allow to change the shadow mapping.
|
|
|
|
// The shadow mapping looks like
|
2016-05-06 18:25:22 +08:00
|
|
|
// Shadow = (Mem >> scale) + offset
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
static cl::opt<int> ClMappingScale("asan-mapping-scale",
|
2015-03-04 21:27:53 +08:00
|
|
|
cl::desc("scale of asan shadow mapping"),
|
|
|
|
cl::Hidden, cl::init(0));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2019-04-24 10:40:20 +08:00
|
|
|
static cl::opt<uint64_t>
|
|
|
|
ClMappingOffset("asan-mapping-offset",
|
|
|
|
cl::desc("offset of asan shadow mapping [EXPERIMENTAL]"),
|
|
|
|
cl::Hidden, cl::init(0));
|
2011-11-16 09:35:23 +08:00
|
|
|
|
|
|
|
// Optimization flags. Not user visible, used mostly for testing
|
|
|
|
// and benchmarking the tool.
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
static cl::opt<bool> ClOpt("asan-opt", cl::desc("Optimize instrumentation"),
|
|
|
|
cl::Hidden, cl::init(true));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
static cl::opt<bool> ClOptSameTemp(
|
|
|
|
"asan-opt-same-temp", cl::desc("Instrument the same temp just once"),
|
|
|
|
cl::Hidden, cl::init(true));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
static cl::opt<bool> ClOptGlobals("asan-opt-globals",
|
2015-03-04 21:27:53 +08:00
|
|
|
cl::desc("Don't instrument scalar globals"),
|
|
|
|
cl::Hidden, cl::init(true));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
static cl::opt<bool> ClOptStack(
|
|
|
|
"asan-opt-stack", cl::desc("Don't instrument scalar stack variables"),
|
|
|
|
cl::Hidden, cl::init(false));
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2014-12-12 05:53:03 +08:00
|
|
|
static cl::opt<bool> ClDynamicAllocaStack(
|
|
|
|
"asan-stack-dynamic-alloca",
|
|
|
|
cl::desc("Use dynamic alloca to represent stack variables"), cl::Hidden,
|
2015-02-06 03:39:20 +08:00
|
|
|
cl::init(true));
|
2014-12-12 05:53:03 +08:00
|
|
|
|
2015-03-18 00:59:19 +08:00
|
|
|
static cl::opt<uint32_t> ClForceExperiment(
|
|
|
|
"asan-force-experiment",
|
|
|
|
cl::desc("Force optimization experiment (for testing)"), cl::Hidden,
|
|
|
|
cl::init(0));
|
|
|
|
|
2016-02-08 16:30:57 +08:00
|
|
|
static cl::opt<bool>
|
2018-12-05 07:17:41 +08:00
|
|
|
ClUsePrivateAlias("asan-use-private-alias",
|
|
|
|
cl::desc("Use private aliases for global variables"),
|
|
|
|
cl::Hidden, cl::init(false));
|
|
|
|
|
|
|
|
static cl::opt<bool>
|
|
|
|
ClUseOdrIndicator("asan-use-odr-indicator",
|
|
|
|
cl::desc("Use odr indicators to improve ODR reporting"),
|
|
|
|
cl::Hidden, cl::init(false));
|
2016-02-08 16:30:57 +08:00
|
|
|
|
2016-07-06 05:53:08 +08:00
|
|
|
static cl::opt<bool>
|
2017-04-25 03:34:13 +08:00
|
|
|
ClUseGlobalsGC("asan-globals-live-support",
|
|
|
|
cl::desc("Use linker features to support dead "
|
|
|
|
"code stripping of globals"),
|
|
|
|
cl::Hidden, cl::init(true));
|
2016-07-06 05:53:08 +08:00
|
|
|
|
2017-04-28 04:27:23 +08:00
|
|
|
// This is on by default even though there is a bug in gold:
|
|
|
|
// https://sourceware.org/bugzilla/show_bug.cgi?id=19002
|
|
|
|
static cl::opt<bool>
|
|
|
|
ClWithComdat("asan-with-comdat",
|
|
|
|
cl::desc("Place ASan constructors in comdat sections"),
|
|
|
|
cl::Hidden, cl::init(true));
|
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
// Debug flags.
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
static cl::opt<int> ClDebug("asan-debug", cl::desc("debug"), cl::Hidden,
|
|
|
|
cl::init(0));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
static cl::opt<int> ClDebugStack("asan-debug-stack", cl::desc("debug stack"),
|
|
|
|
cl::Hidden, cl::init(0));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
static cl::opt<std::string> ClDebugFunc("asan-debug-func", cl::Hidden,
|
|
|
|
cl::desc("Debug func"));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
static cl::opt<int> ClDebugMin("asan-debug-min", cl::desc("Debug min inst"),
|
|
|
|
cl::Hidden, cl::init(-1));
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2016-09-22 22:57:24 +08:00
|
|
|
static cl::opt<int> ClDebugMax("asan-debug-max", cl::desc("Debug max inst"),
|
2011-11-16 09:35:23 +08:00
|
|
|
cl::Hidden, cl::init(-1));
|
|
|
|
|
2013-10-16 22:06:14 +08:00
|
|
|
STATISTIC(NumInstrumentedReads, "Number of instrumented reads");
|
|
|
|
STATISTIC(NumInstrumentedWrites, "Number of instrumented writes");
|
|
|
|
STATISTIC(NumOptimizedAccessesToGlobalVar,
|
|
|
|
"Number of optimized accesses to global vars");
|
2015-03-04 21:27:53 +08:00
|
|
|
STATISTIC(NumOptimizedAccessesToStackVar,
|
|
|
|
"Number of optimized accesses to stack vars");
|
2013-10-16 22:06:14 +08:00
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
namespace {
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2013-01-16 21:23:28 +08:00
|
|
|
/// This struct defines the shadow mapping using the rule:
|
2013-01-23 20:54:55 +08:00
|
|
|
/// shadow = (mem >> Scale) ADD-or-OR Offset.
|
2017-11-21 01:41:57 +08:00
|
|
|
/// If InGlobal is true, then
|
|
|
|
/// extern char __asan_shadow[];
|
|
|
|
/// shadow = (mem >> Scale) + &__asan_shadow
|
2013-01-16 21:23:28 +08:00
|
|
|
struct ShadowMapping {
|
|
|
|
int Scale;
|
|
|
|
uint64_t Offset;
|
2013-01-23 20:54:55 +08:00
|
|
|
bool OrShadowOffset;
|
2017-11-21 01:41:57 +08:00
|
|
|
bool InGlobal;
|
2013-01-16 21:23:28 +08:00
|
|
|
};
|
|
|
|
|
2017-10-20 06:07:16 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
2015-06-19 20:19:07 +08:00
|
|
|
static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize,
|
|
|
|
bool IsKasan) {
|
2015-10-09 05:21:24 +08:00
|
|
|
bool IsAndroid = TargetTriple.isAndroid();
|
2016-02-03 06:05:07 +08:00
|
|
|
bool IsIOS = TargetTriple.isiOS() || TargetTriple.isWatchOS();
|
2014-11-23 03:12:10 +08:00
|
|
|
bool IsFreeBSD = TargetTriple.isOSFreeBSD();
|
2017-08-29 06:13:52 +08:00
|
|
|
bool IsNetBSD = TargetTriple.isOSNetBSD();
|
2017-02-24 01:10:28 +08:00
|
|
|
bool IsPS4CPU = TargetTriple.isPS4CPU();
|
2014-11-23 03:12:10 +08:00
|
|
|
bool IsLinux = TargetTriple.isOSLinux();
|
2017-10-20 06:07:16 +08:00
|
|
|
bool IsPPC64 = TargetTriple.getArch() == Triple::ppc64 ||
|
|
|
|
TargetTriple.getArch() == Triple::ppc64le;
|
|
|
|
bool IsSystemZ = TargetTriple.getArch() == Triple::systemz;
|
|
|
|
bool IsX86_64 = TargetTriple.getArch() == Triple::x86_64;
|
2018-06-26 00:49:20 +08:00
|
|
|
bool IsMIPS32 = TargetTriple.isMIPS32();
|
|
|
|
bool IsMIPS64 = TargetTriple.isMIPS64();
|
2017-11-21 01:41:57 +08:00
|
|
|
bool IsArmOrThumb = TargetTriple.isARM() || TargetTriple.isThumb();
|
2017-10-20 06:07:16 +08:00
|
|
|
bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64;
|
2015-01-13 01:38:58 +08:00
|
|
|
bool IsWindows = TargetTriple.isOSWindows();
|
2017-02-28 06:49:37 +08:00
|
|
|
bool IsFuchsia = TargetTriple.isOSFuchsia();
|
2018-05-18 12:10:38 +08:00
|
|
|
bool IsMyriad = TargetTriple.getVendor() == llvm::Triple::Myriad;
|
[WebAssembly] Implement Address Sanitizer for Emscripten
Summary:
This diff enables address sanitizer on Emscripten.
On Emscripten, real memory starts at the value passed to --global-base.
All memory before this is used as shadow memory, and thus the shadow mapping
function is simply dividing by 8.
Reviewers: tlively, aheejin, sbc100
Reviewed By: sbc100
Subscribers: dschuff, sbc100, jgravelle-google, hiraditya, sunfish, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D63742
llvm-svn: 364468
2019-06-27 04:16:14 +08:00
|
|
|
bool IsEmscripten = TargetTriple.isOSEmscripten();
|
2013-01-16 21:23:28 +08:00
|
|
|
|
|
|
|
ShadowMapping Mapping;
|
|
|
|
|
2018-05-18 12:10:38 +08:00
|
|
|
Mapping.Scale = IsMyriad ? kMyriadShadowScale : kDefaultShadowScale;
|
2017-11-17 01:03:00 +08:00
|
|
|
if (ClMappingScale.getNumOccurrences() > 0) {
|
|
|
|
Mapping.Scale = ClMappingScale;
|
|
|
|
}
|
|
|
|
|
2015-07-30 02:22:25 +08:00
|
|
|
if (LongSize == 32) {
|
|
|
|
if (IsAndroid)
|
2017-11-21 01:41:57 +08:00
|
|
|
Mapping.Offset = kDynamicShadowSentinel;
|
2015-07-30 02:22:25 +08:00
|
|
|
else if (IsMIPS32)
|
2014-02-24 21:40:24 +08:00
|
|
|
Mapping.Offset = kMIPS32_ShadowOffset32;
|
|
|
|
else if (IsFreeBSD)
|
|
|
|
Mapping.Offset = kFreeBSD_ShadowOffset32;
|
2018-05-11 08:58:01 +08:00
|
|
|
else if (IsNetBSD)
|
|
|
|
Mapping.Offset = kNetBSD_ShadowOffset32;
|
2014-04-24 01:14:45 +08:00
|
|
|
else if (IsIOS)
|
2019-06-22 05:01:39 +08:00
|
|
|
Mapping.Offset = kDynamicShadowSentinel;
|
2015-01-13 01:38:58 +08:00
|
|
|
else if (IsWindows)
|
|
|
|
Mapping.Offset = kWindowsShadowOffset32;
|
[WebAssembly] Implement Address Sanitizer for Emscripten
Summary:
This diff enables address sanitizer on Emscripten.
On Emscripten, real memory starts at the value passed to --global-base.
All memory before this is used as shadow memory, and thus the shadow mapping
function is simply dividing by 8.
Reviewers: tlively, aheejin, sbc100
Reviewed By: sbc100
Subscribers: dschuff, sbc100, jgravelle-google, hiraditya, sunfish, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D63742
llvm-svn: 364468
2019-06-27 04:16:14 +08:00
|
|
|
else if (IsEmscripten)
|
|
|
|
Mapping.Offset = kEmscriptenShadowOffset;
|
2018-05-18 12:10:38 +08:00
|
|
|
else if (IsMyriad) {
|
|
|
|
uint64_t ShadowOffset = (kMyriadMemoryOffset32 + kMyriadMemorySize32 -
|
|
|
|
(kMyriadMemorySize32 >> Mapping.Scale));
|
|
|
|
Mapping.Offset = ShadowOffset - (kMyriadMemoryOffset32 >> Mapping.Scale);
|
|
|
|
}
|
2014-02-24 21:40:24 +08:00
|
|
|
else
|
|
|
|
Mapping.Offset = kDefaultShadowOffset32;
|
|
|
|
} else { // LongSize == 64
|
2017-02-28 06:49:37 +08:00
|
|
|
// Fuchsia is always PIE, which means that the beginning of the address
|
|
|
|
// space is always available.
|
|
|
|
if (IsFuchsia)
|
|
|
|
Mapping.Offset = 0;
|
|
|
|
else if (IsPPC64)
|
2014-02-24 21:40:24 +08:00
|
|
|
Mapping.Offset = kPPC64_ShadowOffset64;
|
[ASan] Add shadow offset for SystemZ.
SystemZ on Linux currently has 53-bit address space. In theory, the hardware
could support a full 64-bit address space, but that's not supported due to
kernel limitations (it'd require 5-level page tables), and there are no plans
for that. The default process layout stays within first 4TB of address space
(to avoid creating 4-level page tables), so any offset >= (1 << 42) is fine.
Let's use 1 << 52 here, ie. exactly half the address space.
I've originally used 7 << 50 (uses top 1/8th of the address space), but ASan
runtime assumes there's some space after the shadow area. While this is
fixable, it's simpler to avoid the issue entirely.
Also, I've originally wanted to have the shadow aligned to 1/8th the address
space, so that we can use OR like X86 to assemble the offset. I no longer
think it's a good idea, since using ADD enables us to load the constant just
once and use it with register + register indexed addressing.
Differential Revision: http://reviews.llvm.org/D19650
llvm-svn: 268161
2016-04-30 17:57:34 +08:00
|
|
|
else if (IsSystemZ)
|
|
|
|
Mapping.Offset = kSystemZ_ShadowOffset64;
|
2018-08-02 06:51:13 +08:00
|
|
|
else if (IsFreeBSD && !IsMIPS64)
|
2014-02-24 21:40:24 +08:00
|
|
|
Mapping.Offset = kFreeBSD_ShadowOffset64;
|
2018-12-16 00:32:41 +08:00
|
|
|
else if (IsNetBSD) {
|
|
|
|
if (IsKasan)
|
|
|
|
Mapping.Offset = kNetBSDKasan_ShadowOffset64;
|
|
|
|
else
|
|
|
|
Mapping.Offset = kNetBSD_ShadowOffset64;
|
|
|
|
} else if (IsPS4CPU)
|
2017-02-24 01:10:28 +08:00
|
|
|
Mapping.Offset = kPS4CPU_ShadowOffset64;
|
2015-06-19 20:19:07 +08:00
|
|
|
else if (IsLinux && IsX86_64) {
|
|
|
|
if (IsKasan)
|
|
|
|
Mapping.Offset = kLinuxKasan_ShadowOffset64;
|
|
|
|
else
|
2017-11-17 01:03:00 +08:00
|
|
|
Mapping.Offset = (kSmallX86_64ShadowOffsetBase &
|
|
|
|
(kSmallX86_64ShadowOffsetAlignMask << Mapping.Scale));
|
2016-06-21 23:07:29 +08:00
|
|
|
} else if (IsWindows && IsX86_64) {
|
|
|
|
Mapping.Offset = kWindowsShadowOffset64;
|
2015-06-19 20:19:07 +08:00
|
|
|
} else if (IsMIPS64)
|
2014-11-12 07:02:57 +08:00
|
|
|
Mapping.Offset = kMIPS64_ShadowOffset64;
|
2016-02-03 06:05:07 +08:00
|
|
|
else if (IsIOS)
|
2019-06-22 05:01:39 +08:00
|
|
|
Mapping.Offset = kDynamicShadowSentinel;
|
2015-02-03 19:20:45 +08:00
|
|
|
else if (IsAArch64)
|
|
|
|
Mapping.Offset = kAArch64_ShadowOffset64;
|
2014-02-24 21:40:24 +08:00
|
|
|
else
|
|
|
|
Mapping.Offset = kDefaultShadowOffset64;
|
2013-01-16 21:23:28 +08:00
|
|
|
}
|
|
|
|
|
2016-10-01 01:46:32 +08:00
|
|
|
if (ClForceDynamicShadow) {
|
|
|
|
Mapping.Offset = kDynamicShadowSentinel;
|
|
|
|
}
|
|
|
|
|
2016-05-06 18:25:22 +08:00
|
|
|
if (ClMappingOffset.getNumOccurrences() > 0) {
|
|
|
|
Mapping.Offset = ClMappingOffset;
|
|
|
|
}
|
|
|
|
|
2014-02-24 21:40:24 +08:00
|
|
|
// OR-ing shadow offset if more efficient (at least on x86) if the offset
|
|
|
|
// is a power of two, but on ppc64 we have to use add since the shadow
|
[ASan] Add shadow offset for SystemZ.
SystemZ on Linux currently has 53-bit address space. In theory, the hardware
could support a full 64-bit address space, but that's not supported due to
kernel limitations (it'd require 5-level page tables), and there are no plans
for that. The default process layout stays within first 4TB of address space
(to avoid creating 4-level page tables), so any offset >= (1 << 42) is fine.
Let's use 1 << 52 here, ie. exactly half the address space.
I've originally used 7 << 50 (uses top 1/8th of the address space), but ASan
runtime assumes there's some space after the shadow area. While this is
fixable, it's simpler to avoid the issue entirely.
Also, I've originally wanted to have the shadow aligned to 1/8th the address
space, so that we can use OR like X86 to assemble the offset. I no longer
think it's a good idea, since using ADD enables us to load the constant just
once and use it with register + register indexed addressing.
Differential Revision: http://reviews.llvm.org/D19650
llvm-svn: 268161
2016-04-30 17:57:34 +08:00
|
|
|
// offset is not necessary 1/8-th of the address space. On SystemZ,
|
|
|
|
// we could OR the constant in a single instruction, but it's more
|
|
|
|
// efficient to load it once and use indexed addressing.
|
2017-02-24 01:10:28 +08:00
|
|
|
Mapping.OrShadowOffset = !IsAArch64 && !IsPPC64 && !IsSystemZ && !IsPS4CPU &&
|
|
|
|
!(Mapping.Offset & (Mapping.Offset - 1)) &&
|
|
|
|
Mapping.Offset != kDynamicShadowSentinel;
|
2017-11-21 01:41:57 +08:00
|
|
|
bool IsAndroidWithIfuncSupport =
|
|
|
|
IsAndroid && !TargetTriple.isAndroidVersionLT(21);
|
|
|
|
Mapping.InGlobal = ClWithIfunc && IsAndroidWithIfuncSupport && IsArmOrThumb;
|
2014-02-24 21:40:24 +08:00
|
|
|
|
2013-01-16 21:23:28 +08:00
|
|
|
return Mapping;
|
2012-11-22 11:18:50 +08:00
|
|
|
}
|
|
|
|
|
2020-06-12 20:58:00 +08:00
|
|
|
static uint64_t getRedzoneSizeForScale(int MappingScale) {
|
2012-11-22 11:18:50 +08:00
|
|
|
// Redzone used for stack and globals is at least 32 bytes.
|
|
|
|
// For scales 6 and 7, the redzone has to be 64 and 128 bytes respectively.
|
2013-01-16 21:23:28 +08:00
|
|
|
return std::max(32U, 1U << MappingScale);
|
2012-11-22 11:18:50 +08:00
|
|
|
}
|
2012-11-20 21:00:01 +08:00
|
|
|
|
[WebAssembly] Lower ASan constructor priority on Emscripten
Summary:
This change gives Emscripten the ability to use more than one constructor
priorities that runs before ASan. By convention, constructor priorites 0-100
are reserved for use by the system. ASan on Emscripten now uses priority 50,
leaving plenty of room for use by Emscripten before and after ASan.
This change is done in response to:
https://github.com/emscripten-core/emscripten/pull/9076#discussion_r310323723
Reviewers: kripken, tlively, aheejin
Reviewed By: tlively
Subscribers: cfe-commits, dschuff, sbc100, jgravelle-google, hiraditya, sunfish, llvm-commits
Tags: #llvm, #clang
Differential Revision: https://reviews.llvm.org/D65684
llvm-svn: 368101
2019-08-07 05:52:58 +08:00
|
|
|
static uint64_t GetCtorAndDtorPriority(Triple &TargetTriple) {
|
|
|
|
if (TargetTriple.isOSEmscripten()) {
|
|
|
|
return kAsanEmscriptenCtorAndDtorPriority;
|
|
|
|
} else {
|
|
|
|
return kAsanCtorAndDtorPriority;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-20 06:07:16 +08:00
|
|
|
namespace {
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
/// Module analysis for getting various metadata about the module.
|
|
|
|
class ASanGlobalsMetadataWrapperPass : public ModulePass {
|
|
|
|
public:
|
2018-10-27 06:51:51 +08:00
|
|
|
static char ID;
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
ASanGlobalsMetadataWrapperPass() : ModulePass(ID) {
|
|
|
|
initializeASanGlobalsMetadataWrapperPassPass(
|
|
|
|
*PassRegistry::getPassRegistry());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool runOnModule(Module &M) override {
|
|
|
|
GlobalsMD = GlobalsMetadata(M);
|
|
|
|
return false;
|
2018-10-27 06:51:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
StringRef getPassName() const override {
|
2019-02-14 06:22:48 +08:00
|
|
|
return "ASanGlobalsMetadataWrapperPass";
|
2018-10-27 06:51:51 +08:00
|
|
|
}
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2018-10-27 06:51:51 +08:00
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
2019-02-14 06:22:48 +08:00
|
|
|
AU.setPreservesAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
GlobalsMetadata &getGlobalsMD() { return GlobalsMD; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
GlobalsMetadata GlobalsMD;
|
|
|
|
};
|
|
|
|
|
|
|
|
char ASanGlobalsMetadataWrapperPass::ID = 0;
|
|
|
|
|
|
|
|
/// AddressSanitizer: instrument the code in module to find memory bugs.
|
|
|
|
struct AddressSanitizer {
|
2019-10-02 04:49:07 +08:00
|
|
|
AddressSanitizer(Module &M, const GlobalsMetadata *GlobalsMD,
|
2019-02-14 06:22:48 +08:00
|
|
|
bool CompileKernel = false, bool Recover = false,
|
|
|
|
bool UseAfterScope = false)
|
2020-06-10 21:01:40 +08:00
|
|
|
: CompileKernel(ClEnableKasan.getNumOccurrences() > 0 ? ClEnableKasan
|
|
|
|
: CompileKernel),
|
|
|
|
Recover(ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover),
|
|
|
|
UseAfterScope(UseAfterScope || ClUseAfterScope), GlobalsMD(*GlobalsMD) {
|
2019-02-14 06:22:48 +08:00
|
|
|
C = &(M.getContext());
|
|
|
|
LongSize = M.getDataLayout().getPointerSizeInBits();
|
|
|
|
IntptrTy = Type::getIntNTy(*C, LongSize);
|
|
|
|
TargetTriple = Triple(M.getTargetTriple());
|
|
|
|
|
|
|
|
Mapping = getShadowMapping(TargetTriple, LongSize, this->CompileKernel);
|
2014-12-01 16:47:58 +08:00
|
|
|
}
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2016-07-29 06:50:50 +08:00
|
|
|
uint64_t getAllocaSizeInBytes(const AllocaInst &AI) const {
|
2016-06-27 23:57:08 +08:00
|
|
|
uint64_t ArraySize = 1;
|
2016-07-29 06:50:50 +08:00
|
|
|
if (AI.isArrayAllocation()) {
|
|
|
|
const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize());
|
2016-06-27 23:57:08 +08:00
|
|
|
assert(CI && "non-constant array size");
|
|
|
|
ArraySize = CI->getZExtValue();
|
|
|
|
}
|
2016-07-29 06:50:50 +08:00
|
|
|
Type *Ty = AI.getAllocatedType();
|
2015-03-10 10:37:25 +08:00
|
|
|
uint64_t SizeInBytes =
|
2016-07-29 06:50:50 +08:00
|
|
|
AI.getModule()->getDataLayout().getTypeAllocSize(Ty);
|
2016-06-27 23:57:08 +08:00
|
|
|
return SizeInBytes * ArraySize;
|
2015-02-27 11:12:36 +08:00
|
|
|
}
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-02-27 11:12:36 +08:00
|
|
|
/// Check if we want (and can) handle this alloca.
|
2016-07-29 06:50:50 +08:00
|
|
|
bool isInterestingAlloca(const AllocaInst &AI);
|
2015-05-28 15:51:49 +08:00
|
|
|
|
2020-04-30 17:05:00 +08:00
|
|
|
bool ignoreAccess(Value *Ptr);
|
|
|
|
void getInterestingMemoryOperands(
|
|
|
|
Instruction *I, SmallVectorImpl<InterestingMemoryOperand> &Interesting);
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2020-04-30 17:05:00 +08:00
|
|
|
void instrumentMop(ObjectSizeOffsetVisitor &ObjSizeVis,
|
|
|
|
InterestingMemoryOperand &O, bool UseCalls,
|
|
|
|
const DataLayout &DL);
|
2014-02-27 20:45:36 +08:00
|
|
|
void instrumentPointerComparisonOrSubtraction(Instruction *I);
|
2013-02-19 19:29:21 +08:00
|
|
|
void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore,
|
|
|
|
Value *Addr, uint32_t TypeSize, bool IsWrite,
|
2015-03-18 00:59:19 +08:00
|
|
|
Value *SizeArgument, bool UseCalls, uint32_t Exp);
|
2017-01-06 23:24:51 +08:00
|
|
|
void instrumentUnusualSizeOrAlignment(Instruction *I,
|
|
|
|
Instruction *InsertBefore, Value *Addr,
|
2015-03-18 00:59:19 +08:00
|
|
|
uint32_t TypeSize, bool IsWrite,
|
|
|
|
Value *SizeArgument, bool UseCalls,
|
|
|
|
uint32_t Exp);
|
2012-07-17 00:15:40 +08:00
|
|
|
Value *createSlowPathCmp(IRBuilder<> &IRB, Value *AddrLong,
|
|
|
|
Value *ShadowValue, uint32_t TypeSize);
|
2012-08-14 22:04:51 +08:00
|
|
|
Instruction *generateCrashCode(Instruction *InsertBefore, Value *Addr,
|
2013-02-19 19:29:21 +08:00
|
|
|
bool IsWrite, size_t AccessSizeIndex,
|
2015-03-18 00:59:19 +08:00
|
|
|
Value *SizeArgument, uint32_t Exp);
|
2014-04-21 19:50:42 +08:00
|
|
|
void instrumentMemIntrinsic(MemIntrinsic *MI);
|
2011-11-16 09:35:23 +08:00
|
|
|
Value *memToShadow(Value *Shadow, IRBuilder<> &IRB);
|
2020-04-30 17:04:51 +08:00
|
|
|
bool suppressInstrumentationSiteForDebug(int &Instrumented);
|
2019-02-14 06:22:48 +08:00
|
|
|
bool instrumentFunction(Function &F, const TargetLibraryInfo *TLI);
|
2012-01-31 07:50:10 +08:00
|
|
|
bool maybeInsertAsanInitAtFunctionEntry(Function &F);
|
2020-06-04 15:13:11 +08:00
|
|
|
bool maybeInsertDynamicShadowAtFunctionEntry(Function &F);
|
2015-07-22 01:40:14 +08:00
|
|
|
void markEscapedLocalAllocas(Function &F);
|
2014-12-01 16:47:58 +08:00
|
|
|
|
2017-10-20 06:07:16 +08:00
|
|
|
private:
|
|
|
|
friend struct FunctionStackPoisoner;
|
|
|
|
|
2012-11-29 17:54:21 +08:00
|
|
|
void initializeCallbacks(Module &M);
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2011-11-18 09:41:06 +08:00
|
|
|
bool LooksLikeCodeInBug11395(Instruction *I);
|
2013-10-16 22:06:14 +08:00
|
|
|
bool GlobalIsLinkerInitialized(GlobalVariable *G);
|
2015-03-04 21:27:53 +08:00
|
|
|
bool isSafeAccess(ObjectSizeOffsetVisitor &ObjSizeVis, Value *Addr,
|
|
|
|
uint64_t TypeSize) const;
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2015-07-22 01:40:14 +08:00
|
|
|
/// Helper to cleanup per-function state.
|
|
|
|
struct FunctionStateRAII {
|
|
|
|
AddressSanitizer *Pass;
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-07-22 01:40:14 +08:00
|
|
|
FunctionStateRAII(AddressSanitizer *Pass) : Pass(Pass) {
|
|
|
|
assert(Pass->ProcessedAllocas.empty() &&
|
|
|
|
"last pass forgot to clear cache");
|
2016-10-01 01:46:32 +08:00
|
|
|
assert(!Pass->LocalDynamicShadow);
|
|
|
|
}
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2016-10-01 01:46:32 +08:00
|
|
|
~FunctionStateRAII() {
|
|
|
|
Pass->LocalDynamicShadow = nullptr;
|
|
|
|
Pass->ProcessedAllocas.clear();
|
2015-07-22 01:40:14 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
LLVMContext *C;
|
2014-12-06 06:19:18 +08:00
|
|
|
Triple TargetTriple;
|
2011-11-16 09:35:23 +08:00
|
|
|
int LongSize;
|
2015-06-19 20:19:07 +08:00
|
|
|
bool CompileKernel;
|
2015-11-11 18:36:49 +08:00
|
|
|
bool Recover;
|
2016-05-28 06:55:10 +08:00
|
|
|
bool UseAfterScope;
|
2011-11-16 09:35:23 +08:00
|
|
|
Type *IntptrTy;
|
2013-01-16 21:23:28 +08:00
|
|
|
ShadowMapping Mapping;
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee AsanHandleNoReturnFunc;
|
|
|
|
FunctionCallee AsanPtrCmpFunction, AsanPtrSubFunction;
|
2017-11-21 01:41:57 +08:00
|
|
|
Constant *AsanShadowGlobal;
|
2017-10-20 06:07:16 +08:00
|
|
|
|
|
|
|
// These arrays is indexed by AccessIsWrite, Experiment and log2(AccessSize).
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee AsanErrorCallback[2][2][kNumberOfAccessSizes];
|
|
|
|
FunctionCallee AsanMemoryAccessCallback[2][2][kNumberOfAccessSizes];
|
2017-10-20 06:07:16 +08:00
|
|
|
|
|
|
|
// These arrays is indexed by AccessIsWrite and Experiment.
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee AsanErrorCallbackSized[2][2];
|
|
|
|
FunctionCallee AsanMemoryAccessCallbackSized[2][2];
|
2017-10-20 06:07:16 +08:00
|
|
|
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee AsanMemmove, AsanMemcpy, AsanMemset;
|
2017-10-20 06:07:16 +08:00
|
|
|
Value *LocalDynamicShadow = nullptr;
|
2019-10-02 04:30:46 +08:00
|
|
|
const GlobalsMetadata &GlobalsMD;
|
2016-07-29 06:50:50 +08:00
|
|
|
DenseMap<const AllocaInst *, bool> ProcessedAllocas;
|
2011-11-16 09:35:23 +08:00
|
|
|
};
|
2012-07-17 00:15:40 +08:00
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
class AddressSanitizerLegacyPass : public FunctionPass {
|
2017-04-25 03:34:13 +08:00
|
|
|
public:
|
2018-10-27 06:51:51 +08:00
|
|
|
static char ID;
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
explicit AddressSanitizerLegacyPass(bool CompileKernel = false,
|
|
|
|
bool Recover = false,
|
|
|
|
bool UseAfterScope = false)
|
|
|
|
: FunctionPass(ID), CompileKernel(CompileKernel), Recover(Recover),
|
|
|
|
UseAfterScope(UseAfterScope) {
|
|
|
|
initializeAddressSanitizerLegacyPassPass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef getPassName() const override {
|
|
|
|
return "AddressSanitizerFunctionPass";
|
|
|
|
}
|
|
|
|
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
|
|
AU.addRequired<ASanGlobalsMetadataWrapperPass>();
|
|
|
|
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool runOnFunction(Function &F) override {
|
|
|
|
GlobalsMetadata &GlobalsMD =
|
|
|
|
getAnalysis<ASanGlobalsMetadataWrapperPass>().getGlobalsMD();
|
|
|
|
const TargetLibraryInfo *TLI =
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
&getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
|
2019-10-02 04:49:07 +08:00
|
|
|
AddressSanitizer ASan(*F.getParent(), &GlobalsMD, CompileKernel, Recover,
|
2019-02-14 06:22:48 +08:00
|
|
|
UseAfterScope);
|
|
|
|
return ASan.instrumentFunction(F, TLI);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool CompileKernel;
|
|
|
|
bool Recover;
|
|
|
|
bool UseAfterScope;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ModuleAddressSanitizer {
|
|
|
|
public:
|
2019-10-02 04:49:07 +08:00
|
|
|
ModuleAddressSanitizer(Module &M, const GlobalsMetadata *GlobalsMD,
|
2019-02-14 06:22:48 +08:00
|
|
|
bool CompileKernel = false, bool Recover = false,
|
|
|
|
bool UseGlobalsGC = true, bool UseOdrIndicator = false)
|
2020-06-10 21:01:40 +08:00
|
|
|
: GlobalsMD(*GlobalsMD),
|
|
|
|
CompileKernel(ClEnableKasan.getNumOccurrences() > 0 ? ClEnableKasan
|
|
|
|
: CompileKernel),
|
|
|
|
Recover(ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover),
|
|
|
|
UseGlobalsGC(UseGlobalsGC && ClUseGlobalsGC && !this->CompileKernel),
|
2018-12-05 09:44:31 +08:00
|
|
|
// Enable aliases as they should have no downside with ODR indicators.
|
|
|
|
UsePrivateAlias(UseOdrIndicator || ClUsePrivateAlias),
|
|
|
|
UseOdrIndicator(UseOdrIndicator || ClUseOdrIndicator),
|
2017-05-16 04:43:42 +08:00
|
|
|
// Not a typo: ClWithComdat is almost completely pointless without
|
|
|
|
// ClUseGlobalsGC (because then it only works on modules without
|
|
|
|
// globals, which are rare); it is a prerequisite for ClUseGlobalsGC;
|
|
|
|
// and both suffer from gold PR19002 for which UseGlobalsGC constructor
|
|
|
|
// argument is designed as workaround. Therefore, disable both
|
|
|
|
// ClWithComdat and ClUseGlobalsGC unless the frontend says it's ok to
|
|
|
|
// do globals-gc.
|
2020-06-10 21:01:40 +08:00
|
|
|
UseCtorComdat(UseGlobalsGC && ClWithComdat && !this->CompileKernel) {
|
2019-02-14 06:22:48 +08:00
|
|
|
C = &(M.getContext());
|
|
|
|
int LongSize = M.getDataLayout().getPointerSizeInBits();
|
|
|
|
IntptrTy = Type::getIntNTy(*C, LongSize);
|
|
|
|
TargetTriple = Triple(M.getTargetTriple());
|
|
|
|
Mapping = getShadowMapping(TargetTriple, LongSize, this->CompileKernel);
|
2018-12-04 08:36:14 +08:00
|
|
|
}
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
bool instrumentModule(Module &);
|
2012-12-04 09:34:23 +08:00
|
|
|
|
2016-10-01 10:56:57 +08:00
|
|
|
private:
|
2012-12-25 20:28:20 +08:00
|
|
|
void initializeCallbacks(Module &M);
|
|
|
|
|
2017-04-28 04:27:23 +08:00
|
|
|
bool InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool *CtorComdat);
|
2017-01-13 07:03:03 +08:00
|
|
|
void InstrumentGlobalsCOFF(IRBuilder<> &IRB, Module &M,
|
|
|
|
ArrayRef<GlobalVariable *> ExtendedGlobals,
|
|
|
|
ArrayRef<Constant *> MetadataInitializers);
|
2017-04-28 04:27:27 +08:00
|
|
|
void InstrumentGlobalsELF(IRBuilder<> &IRB, Module &M,
|
|
|
|
ArrayRef<GlobalVariable *> ExtendedGlobals,
|
|
|
|
ArrayRef<Constant *> MetadataInitializers,
|
|
|
|
const std::string &UniqueModuleId);
|
2017-01-13 07:03:03 +08:00
|
|
|
void InstrumentGlobalsMachO(IRBuilder<> &IRB, Module &M,
|
|
|
|
ArrayRef<GlobalVariable *> ExtendedGlobals,
|
|
|
|
ArrayRef<Constant *> MetadataInitializers);
|
|
|
|
void
|
|
|
|
InstrumentGlobalsWithMetadataArray(IRBuilder<> &IRB, Module &M,
|
|
|
|
ArrayRef<GlobalVariable *> ExtendedGlobals,
|
|
|
|
ArrayRef<Constant *> MetadataInitializers);
|
|
|
|
|
|
|
|
GlobalVariable *CreateMetadataGlobal(Module &M, Constant *Initializer,
|
|
|
|
StringRef OriginalName);
|
2017-04-28 04:27:27 +08:00
|
|
|
void SetComdatForGlobalMetadata(GlobalVariable *G, GlobalVariable *Metadata,
|
|
|
|
StringRef InternalSuffix);
|
2020-02-17 00:46:26 +08:00
|
|
|
Instruction *CreateAsanModuleDtor(Module &M);
|
2017-01-13 07:03:03 +08:00
|
|
|
|
2020-06-10 21:01:40 +08:00
|
|
|
bool canInstrumentAliasedGlobal(const GlobalAlias &GA) const;
|
|
|
|
bool shouldInstrumentGlobal(GlobalVariable *G) const;
|
2016-03-29 04:28:57 +08:00
|
|
|
bool ShouldUseMachOGlobalsSection() const;
|
[asan] Make ASan compatible with linker dead stripping on Windows
Summary:
This is similar to what was done for Darwin in rL264645 /
http://reviews.llvm.org/D16737, but it uses COFF COMDATs to achive the
same result instead of relying on new custom linker features.
As on MachO, this creates one metadata global per instrumented global.
The metadata global is placed in the custom .ASAN$GL section, which the
ASan runtime will iterate over during initialization. There are no other
references to the metadata, so normal linker dead stripping would
discard it. However, the metadata is put in a COMDAT group with the
instrumented global, so that it will be discarded if and only if the
instrumented global is discarded.
I didn't update the ASan ABI version check since this doesn't affect
non-Windows platforms, and the WinASan ABI isn't really stable yet.
Implementing this for ELF will require extending LLVM IR and MC a bit so
that we can use non-COMDAT section groups.
Reviewers: pcc, kcc, mehdi_amini, kubabrecka
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D26770
llvm-svn: 287576
2016-11-22 04:40:37 +08:00
|
|
|
StringRef getGlobalMetadataSection() const;
|
2014-05-29 08:51:15 +08:00
|
|
|
void poisonOneInitializer(Function &GlobalInit, GlobalValue *ModuleName);
|
2013-03-26 21:05:41 +08:00
|
|
|
void createInitializerPoisonCalls(Module &M, GlobalValue *ModuleName);
|
2020-06-12 20:58:00 +08:00
|
|
|
uint64_t getMinRedzoneSizeForGlobal() const {
|
|
|
|
return getRedzoneSizeForScale(Mapping.Scale);
|
2013-01-16 21:23:28 +08:00
|
|
|
}
|
2020-06-12 20:58:00 +08:00
|
|
|
uint64_t getRedzoneSizeForGlobal(uint64_t SizeInBytes) const;
|
2017-11-21 01:41:57 +08:00
|
|
|
int GetAsanVersion(const Module &M) const;
|
2012-11-22 11:18:50 +08:00
|
|
|
|
2019-10-02 04:30:46 +08:00
|
|
|
const GlobalsMetadata &GlobalsMD;
|
2015-06-19 20:19:07 +08:00
|
|
|
bool CompileKernel;
|
2015-11-11 18:36:49 +08:00
|
|
|
bool Recover;
|
2017-04-25 03:34:13 +08:00
|
|
|
bool UseGlobalsGC;
|
2018-12-05 09:44:31 +08:00
|
|
|
bool UsePrivateAlias;
|
|
|
|
bool UseOdrIndicator;
|
2017-05-16 04:43:42 +08:00
|
|
|
bool UseCtorComdat;
|
2012-11-22 11:18:50 +08:00
|
|
|
Type *IntptrTy;
|
|
|
|
LLVMContext *C;
|
2014-12-06 06:19:18 +08:00
|
|
|
Triple TargetTriple;
|
2013-01-16 21:23:28 +08:00
|
|
|
ShadowMapping Mapping;
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee AsanPoisonGlobals;
|
|
|
|
FunctionCallee AsanUnpoisonGlobals;
|
|
|
|
FunctionCallee AsanRegisterGlobals;
|
|
|
|
FunctionCallee AsanUnregisterGlobals;
|
|
|
|
FunctionCallee AsanRegisterImageGlobals;
|
|
|
|
FunctionCallee AsanUnregisterImageGlobals;
|
|
|
|
FunctionCallee AsanRegisterElfGlobals;
|
|
|
|
FunctionCallee AsanUnregisterElfGlobals;
|
2017-04-28 04:27:23 +08:00
|
|
|
|
|
|
|
Function *AsanCtorFunction = nullptr;
|
|
|
|
Function *AsanDtorFunction = nullptr;
|
2012-11-22 11:18:50 +08:00
|
|
|
};
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
class ModuleAddressSanitizerLegacyPass : public ModulePass {
|
|
|
|
public:
|
|
|
|
static char ID;
|
|
|
|
|
|
|
|
explicit ModuleAddressSanitizerLegacyPass(bool CompileKernel = false,
|
|
|
|
bool Recover = false,
|
|
|
|
bool UseGlobalGC = true,
|
|
|
|
bool UseOdrIndicator = false)
|
|
|
|
: ModulePass(ID), CompileKernel(CompileKernel), Recover(Recover),
|
|
|
|
UseGlobalGC(UseGlobalGC), UseOdrIndicator(UseOdrIndicator) {
|
|
|
|
initializeModuleAddressSanitizerLegacyPassPass(
|
|
|
|
*PassRegistry::getPassRegistry());
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef getPassName() const override { return "ModuleAddressSanitizer"; }
|
|
|
|
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
|
|
AU.addRequired<ASanGlobalsMetadataWrapperPass>();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool runOnModule(Module &M) override {
|
|
|
|
GlobalsMetadata &GlobalsMD =
|
|
|
|
getAnalysis<ASanGlobalsMetadataWrapperPass>().getGlobalsMD();
|
2019-10-02 04:49:07 +08:00
|
|
|
ModuleAddressSanitizer ASanModule(M, &GlobalsMD, CompileKernel, Recover,
|
2019-02-14 06:22:48 +08:00
|
|
|
UseGlobalGC, UseOdrIndicator);
|
|
|
|
return ASanModule.instrumentModule(M);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool CompileKernel;
|
|
|
|
bool Recover;
|
|
|
|
bool UseGlobalGC;
|
|
|
|
bool UseOdrIndicator;
|
|
|
|
};
|
|
|
|
|
2012-12-25 20:04:36 +08:00
|
|
|
// Stack poisoning does not play well with exception handling.
|
|
|
|
// When an exception is thrown, we essentially bypass the code
|
|
|
|
// that unpoisones the stack. This is why the run-time library has
|
|
|
|
// to intercept __cxa_throw (as well as longjmp, etc) and unpoison the entire
|
|
|
|
// stack in the interceptor. This however does not work inside the
|
|
|
|
// actual function which catches the exception. Most likely because the
|
|
|
|
// compiler hoists the load of the shadow value somewhere too high.
|
|
|
|
// This causes asan to report a non-existing bug on 453.povray.
|
|
|
|
// It sounds like an LLVM bug.
|
|
|
|
struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
|
|
|
|
Function &F;
|
|
|
|
AddressSanitizer &ASan;
|
|
|
|
DIBuilder DIB;
|
|
|
|
LLVMContext *C;
|
|
|
|
Type *IntptrTy;
|
|
|
|
Type *IntptrPtrTy;
|
2013-01-16 21:23:28 +08:00
|
|
|
ShadowMapping Mapping;
|
2012-12-25 20:04:36 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
SmallVector<AllocaInst *, 16> AllocaVec;
|
2016-11-09 05:30:41 +08:00
|
|
|
SmallVector<AllocaInst *, 16> StaticAllocasToMoveUp;
|
2015-03-04 21:27:53 +08:00
|
|
|
SmallVector<Instruction *, 8> RetVec;
|
2012-12-25 20:04:36 +08:00
|
|
|
unsigned StackAlignment;
|
|
|
|
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee AsanStackMallocFunc[kMaxAsanStackMallocSizeClass + 1],
|
|
|
|
AsanStackFreeFunc[kMaxAsanStackMallocSizeClass + 1];
|
|
|
|
FunctionCallee AsanSetShadowFunc[0x100] = {};
|
|
|
|
FunctionCallee AsanPoisonStackMemoryFunc, AsanUnpoisonStackMemoryFunc;
|
|
|
|
FunctionCallee AsanAllocaPoisonFunc, AsanAllocasUnpoisonFunc;
|
2012-12-25 20:04:36 +08:00
|
|
|
|
2012-12-27 16:50:58 +08:00
|
|
|
// Stores a place and arguments of poisoning/unpoisoning call for alloca.
|
|
|
|
struct AllocaPoisonCall {
|
|
|
|
IntrinsicInst *InsBefore;
|
2013-11-18 22:53:55 +08:00
|
|
|
AllocaInst *AI;
|
2012-12-27 16:50:58 +08:00
|
|
|
uint64_t Size;
|
|
|
|
bool DoPoison;
|
|
|
|
};
|
2016-08-21 01:22:27 +08:00
|
|
|
SmallVector<AllocaPoisonCall, 8> DynamicAllocaPoisonCallVec;
|
|
|
|
SmallVector<AllocaPoisonCall, 8> StaticAllocaPoisonCallVec;
|
2019-04-16 15:54:20 +08:00
|
|
|
bool HasUntracedLifetimeIntrinsic = false;
|
2012-12-27 16:50:58 +08:00
|
|
|
|
2015-05-28 15:51:49 +08:00
|
|
|
SmallVector<AllocaInst *, 1> DynamicAllocaVec;
|
|
|
|
SmallVector<IntrinsicInst *, 1> StackRestoreVec;
|
|
|
|
AllocaInst *DynamicAllocaLayout = nullptr;
|
2015-07-22 01:40:14 +08:00
|
|
|
IntrinsicInst *LocalEscapeCall = nullptr;
|
2014-11-21 18:29:50 +08:00
|
|
|
|
2012-12-27 16:50:58 +08:00
|
|
|
// Maps Value to an AllocaInst from which the Value is originated.
|
2017-10-20 06:07:16 +08:00
|
|
|
using AllocaForValueMapTy = DenseMap<Value *, AllocaInst *>;
|
2012-12-27 16:50:58 +08:00
|
|
|
AllocaForValueMapTy AllocaForValue;
|
|
|
|
|
2020-06-23 02:43:52 +08:00
|
|
|
bool HasInlineAsm = false;
|
[ASan] Disable dynamic alloca and UAR detection in presence of returns_twice calls.
Summary:
returns_twice (most importantly, setjmp) functions are
optimization-hostile: if local variable is promoted to register, and is
changed between setjmp() and longjmp() calls, this update will be
undone. This is the reason why "man setjmp" advises to mark all these
locals as "volatile".
This can not be enough for ASan, though: when it replaces static alloca
with dynamic one, optionally called if UAR mode is enabled, it adds a
whole lot of SSA values, and computations of local variable addresses,
that can involve virtual registers, and cause unexpected behavior, when
these registers are restored from buffer saved in setjmp.
To fix this, just disable dynamic alloca and UAR tricks whenever we see
a returns_twice call in the function.
Reviewers: rnk
Subscribers: llvm-commits, kcc
Differential Revision: http://reviews.llvm.org/D11495
llvm-svn: 243561
2015-07-30 03:36:08 +08:00
|
|
|
bool HasReturnsTwiceCall = false;
|
2014-12-12 05:53:03 +08:00
|
|
|
|
2012-12-25 20:04:36 +08:00
|
|
|
FunctionStackPoisoner(Function &F, AddressSanitizer &ASan)
|
2019-02-14 06:22:48 +08:00
|
|
|
: F(F), ASan(ASan), DIB(*F.getParent(), /*AllowUnresolved*/ false),
|
|
|
|
C(ASan.C), IntptrTy(ASan.IntptrTy),
|
|
|
|
IntptrPtrTy(PointerType::get(IntptrTy, 0)), Mapping(ASan.Mapping),
|
2020-06-23 02:43:52 +08:00
|
|
|
StackAlignment(1 << Mapping.Scale) {}
|
2012-12-25 20:04:36 +08:00
|
|
|
|
|
|
|
bool runOnFunction() {
|
|
|
|
if (!ClStack) return false;
|
2017-07-19 06:28:03 +08:00
|
|
|
|
2017-08-10 01:59:43 +08:00
|
|
|
if (ClRedzoneByvalArgs)
|
2017-08-07 15:12:34 +08:00
|
|
|
copyArgsPassedByValToAllocas();
|
2017-07-19 06:28:03 +08:00
|
|
|
|
2012-12-25 20:04:36 +08:00
|
|
|
// Collect alloca, ret, lifetime instructions etc.
|
2015-03-04 21:27:53 +08:00
|
|
|
for (BasicBlock *BB : depth_first(&F.getEntryBlock())) visit(*BB);
|
2014-04-11 09:50:01 +08:00
|
|
|
|
2014-11-21 18:29:50 +08:00
|
|
|
if (AllocaVec.empty() && DynamicAllocaVec.empty()) return false;
|
2012-12-25 20:04:36 +08:00
|
|
|
|
|
|
|
initializeCallbacks(*F.getParent());
|
|
|
|
|
2019-04-16 15:54:20 +08:00
|
|
|
if (HasUntracedLifetimeIntrinsic) {
|
|
|
|
// If there are lifetime intrinsics which couldn't be traced back to an
|
|
|
|
// alloca, we may not know exactly when a variable enters scope, and
|
|
|
|
// therefore should "fail safe" by not poisoning them.
|
|
|
|
StaticAllocaPoisonCallVec.clear();
|
|
|
|
DynamicAllocaPoisonCallVec.clear();
|
|
|
|
}
|
|
|
|
|
2016-08-21 01:22:27 +08:00
|
|
|
processDynamicAllocas();
|
|
|
|
processStaticAllocas();
|
2012-12-25 20:04:36 +08:00
|
|
|
|
|
|
|
if (ClDebugStack) {
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << F);
|
2012-12-25 20:04:36 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-19 06:28:03 +08:00
|
|
|
// Arguments marked with the "byval" attribute are implicitly copied without
|
|
|
|
// using an alloca instruction. To produce redzones for those arguments, we
|
|
|
|
// copy them a second time into memory allocated with an alloca instruction.
|
|
|
|
void copyArgsPassedByValToAllocas();
|
|
|
|
|
2014-11-21 18:29:50 +08:00
|
|
|
// Finds all Alloca instructions and puts
|
2012-12-25 20:04:36 +08:00
|
|
|
// poisoned red zones around all of them.
|
|
|
|
// Then unpoison everything back before the function returns.
|
2016-08-21 01:22:27 +08:00
|
|
|
void processStaticAllocas();
|
|
|
|
void processDynamicAllocas();
|
2012-12-25 20:04:36 +08:00
|
|
|
|
2015-05-28 15:51:49 +08:00
|
|
|
void createDynamicAllocasInitStorage();
|
|
|
|
|
2012-12-25 20:04:36 +08:00
|
|
|
// ----------------------- Visitors.
|
2018-05-01 23:54:18 +08:00
|
|
|
/// Collect all Ret instructions.
|
2015-03-04 21:27:53 +08:00
|
|
|
void visitReturnInst(ReturnInst &RI) { RetVec.push_back(&RI); }
|
2012-12-25 20:04:36 +08:00
|
|
|
|
2018-05-01 23:54:18 +08:00
|
|
|
/// Collect all Resume instructions.
|
2016-07-23 06:04:38 +08:00
|
|
|
void visitResumeInst(ResumeInst &RI) { RetVec.push_back(&RI); }
|
|
|
|
|
2018-05-01 23:54:18 +08:00
|
|
|
/// Collect all CatchReturnInst instructions.
|
2016-07-23 06:04:38 +08:00
|
|
|
void visitCleanupReturnInst(CleanupReturnInst &CRI) { RetVec.push_back(&CRI); }
|
|
|
|
|
2015-05-28 15:51:49 +08:00
|
|
|
void unpoisonDynamicAllocasBeforeInst(Instruction *InstBefore,
|
|
|
|
Value *SavedStack) {
|
|
|
|
IRBuilder<> IRB(InstBefore);
|
2015-12-04 17:19:14 +08:00
|
|
|
Value *DynamicAreaPtr = IRB.CreatePtrToInt(SavedStack, IntptrTy);
|
|
|
|
// When we insert _asan_allocas_unpoison before @llvm.stackrestore, we
|
|
|
|
// need to adjust extracted SP to compute the address of the most recent
|
|
|
|
// alloca. We have a special @llvm.get.dynamic.area.offset intrinsic for
|
|
|
|
// this purpose.
|
|
|
|
if (!isa<ReturnInst>(InstBefore)) {
|
|
|
|
Function *DynamicAreaOffsetFunc = Intrinsic::getDeclaration(
|
|
|
|
InstBefore->getModule(), Intrinsic::get_dynamic_area_offset,
|
|
|
|
{IntptrTy});
|
|
|
|
|
|
|
|
Value *DynamicAreaOffset = IRB.CreateCall(DynamicAreaOffsetFunc, {});
|
|
|
|
|
|
|
|
DynamicAreaPtr = IRB.CreateAdd(IRB.CreatePtrToInt(SavedStack, IntptrTy),
|
|
|
|
DynamicAreaOffset);
|
|
|
|
}
|
|
|
|
|
2019-02-02 04:44:24 +08:00
|
|
|
IRB.CreateCall(
|
|
|
|
AsanAllocasUnpoisonFunc,
|
|
|
|
{IRB.CreateLoad(IntptrTy, DynamicAllocaLayout), DynamicAreaPtr});
|
2014-11-21 18:29:50 +08:00
|
|
|
}
|
|
|
|
|
2015-05-28 15:51:49 +08:00
|
|
|
// Unpoison dynamic allocas redzones.
|
|
|
|
void unpoisonDynamicAllocas() {
|
|
|
|
for (auto &Ret : RetVec)
|
|
|
|
unpoisonDynamicAllocasBeforeInst(Ret, DynamicAllocaLayout);
|
2014-11-21 18:29:50 +08:00
|
|
|
|
2015-05-28 15:51:49 +08:00
|
|
|
for (auto &StackRestoreInst : StackRestoreVec)
|
|
|
|
unpoisonDynamicAllocasBeforeInst(StackRestoreInst,
|
|
|
|
StackRestoreInst->getOperand(0));
|
|
|
|
}
|
2014-11-21 18:29:50 +08:00
|
|
|
|
|
|
|
// Deploy and poison redzones around dynamic alloca call. To do this, we
|
|
|
|
// should replace this call with another one with changed parameters and
|
|
|
|
// replace all its uses with new address, so
|
|
|
|
// addr = alloca type, old_size, align
|
|
|
|
// is replaced by
|
|
|
|
// new_size = (old_size + additional_size) * sizeof(type)
|
|
|
|
// tmp = alloca i8, new_size, max(align, 32)
|
|
|
|
// addr = tmp + 32 (first 32 bytes are for the left redzone).
|
|
|
|
// Additional_size is added to make new memory allocation contain not only
|
|
|
|
// requested memory, but also left, partial and right redzones.
|
2015-05-28 15:51:49 +08:00
|
|
|
void handleDynamicAllocaCall(AllocaInst *AI);
|
2014-11-21 18:29:50 +08:00
|
|
|
|
2018-05-01 23:54:18 +08:00
|
|
|
/// Collect Alloca instructions we want (and can) handle.
|
2012-12-25 20:04:36 +08:00
|
|
|
void visitAllocaInst(AllocaInst &AI) {
|
2015-07-17 14:29:57 +08:00
|
|
|
if (!ASan.isInterestingAlloca(AI)) {
|
2016-11-09 05:30:41 +08:00
|
|
|
if (AI.isStaticAlloca()) {
|
|
|
|
// Skip over allocas that are present *before* the first instrumented
|
|
|
|
// alloca, we don't want to move those around.
|
|
|
|
if (AllocaVec.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
StaticAllocasToMoveUp.push_back(&AI);
|
|
|
|
}
|
2015-07-17 14:29:57 +08:00
|
|
|
return;
|
|
|
|
}
|
2012-12-25 20:04:36 +08:00
|
|
|
|
|
|
|
StackAlignment = std::max(StackAlignment, AI.getAlignment());
|
2016-06-27 23:57:08 +08:00
|
|
|
if (!AI.isStaticAlloca())
|
2015-05-28 15:51:49 +08:00
|
|
|
DynamicAllocaVec.push_back(&AI);
|
2014-11-21 18:29:50 +08:00
|
|
|
else
|
|
|
|
AllocaVec.push_back(&AI);
|
2012-12-25 20:04:36 +08:00
|
|
|
}
|
|
|
|
|
2018-05-01 23:54:18 +08:00
|
|
|
/// Collect lifetime intrinsic calls to check for use-after-scope
|
2012-12-27 16:50:58 +08:00
|
|
|
/// errors.
|
|
|
|
void visitIntrinsicInst(IntrinsicInst &II) {
|
|
|
|
Intrinsic::ID ID = II.getIntrinsicID();
|
2015-05-28 15:51:49 +08:00
|
|
|
if (ID == Intrinsic::stackrestore) StackRestoreVec.push_back(&II);
|
2015-07-22 01:40:14 +08:00
|
|
|
if (ID == Intrinsic::localescape) LocalEscapeCall = &II;
|
2016-05-28 06:55:10 +08:00
|
|
|
if (!ASan.UseAfterScope)
|
|
|
|
return;
|
2018-12-22 05:49:40 +08:00
|
|
|
if (!II.isLifetimeStartOrEnd())
|
2012-12-27 16:50:58 +08:00
|
|
|
return;
|
|
|
|
// Found lifetime intrinsic, add ASan instrumentation if necessary.
|
2019-09-21 04:52:21 +08:00
|
|
|
auto *Size = cast<ConstantInt>(II.getArgOperand(0));
|
2012-12-27 16:50:58 +08:00
|
|
|
// If size argument is undefined, don't do anything.
|
|
|
|
if (Size->isMinusOne()) return;
|
|
|
|
// Check that size doesn't saturate uint64_t and can
|
|
|
|
// be stored in IntptrTy.
|
|
|
|
const uint64_t SizeValue = Size->getValue().getLimitedValue();
|
|
|
|
if (SizeValue == ~0ULL ||
|
|
|
|
!ConstantInt::isValueValidForType(IntptrTy, SizeValue))
|
|
|
|
return;
|
|
|
|
// Find alloca instruction that corresponds to llvm.lifetime argument.
|
2019-04-15 16:59:56 +08:00
|
|
|
AllocaInst *AI =
|
|
|
|
llvm::findAllocaForValue(II.getArgOperand(1), AllocaForValue);
|
2019-04-16 15:54:20 +08:00
|
|
|
if (!AI) {
|
|
|
|
HasUntracedLifetimeIntrinsic = true;
|
|
|
|
return;
|
|
|
|
}
|
2019-04-15 16:59:56 +08:00
|
|
|
// We're interested only in allocas we can handle.
|
2019-04-16 15:54:20 +08:00
|
|
|
if (!ASan.isInterestingAlloca(*AI))
|
2016-06-10 07:31:59 +08:00
|
|
|
return;
|
2012-12-27 16:50:58 +08:00
|
|
|
bool DoPoison = (ID == Intrinsic::lifetime_end);
|
2013-11-18 22:53:55 +08:00
|
|
|
AllocaPoisonCall APC = {&II, AI, SizeValue, DoPoison};
|
2016-08-21 01:22:27 +08:00
|
|
|
if (AI->isStaticAlloca())
|
|
|
|
StaticAllocaPoisonCallVec.push_back(APC);
|
|
|
|
else if (ClInstrumentDynamicAllocas)
|
|
|
|
DynamicAllocaPoisonCallVec.push_back(APC);
|
2012-12-27 16:50:58 +08:00
|
|
|
}
|
|
|
|
|
2020-04-21 12:34:35 +08:00
|
|
|
void visitCallBase(CallBase &CB) {
|
|
|
|
if (CallInst *CI = dyn_cast<CallInst>(&CB)) {
|
2020-06-23 02:43:52 +08:00
|
|
|
HasInlineAsm |= CI->isInlineAsm() && &CB != ASan.LocalDynamicShadow;
|
[ASan] Disable dynamic alloca and UAR detection in presence of returns_twice calls.
Summary:
returns_twice (most importantly, setjmp) functions are
optimization-hostile: if local variable is promoted to register, and is
changed between setjmp() and longjmp() calls, this update will be
undone. This is the reason why "man setjmp" advises to mark all these
locals as "volatile".
This can not be enough for ASan, though: when it replaces static alloca
with dynamic one, optionally called if UAR mode is enabled, it adds a
whole lot of SSA values, and computations of local variable addresses,
that can involve virtual registers, and cause unexpected behavior, when
these registers are restored from buffer saved in setjmp.
To fix this, just disable dynamic alloca and UAR tricks whenever we see
a returns_twice call in the function.
Reviewers: rnk
Subscribers: llvm-commits, kcc
Differential Revision: http://reviews.llvm.org/D11495
llvm-svn: 243561
2015-07-30 03:36:08 +08:00
|
|
|
HasReturnsTwiceCall |= CI->canReturnTwice();
|
|
|
|
}
|
2014-12-12 05:53:03 +08:00
|
|
|
}
|
|
|
|
|
2012-12-25 20:04:36 +08:00
|
|
|
// ---------------------- Helpers.
|
|
|
|
void initializeCallbacks(Module &M);
|
|
|
|
|
2016-08-30 02:17:21 +08:00
|
|
|
// Copies bytes from ShadowBytes into shadow memory for indexes where
|
|
|
|
// ShadowMask is not zero. If ShadowMask[i] is zero, we assume that
|
|
|
|
// ShadowBytes[i] is constantly zero and doesn't need to be overwritten.
|
|
|
|
void copyToShadow(ArrayRef<uint8_t> ShadowMask, ArrayRef<uint8_t> ShadowBytes,
|
|
|
|
IRBuilder<> &IRB, Value *ShadowBase);
|
|
|
|
void copyToShadow(ArrayRef<uint8_t> ShadowMask, ArrayRef<uint8_t> ShadowBytes,
|
|
|
|
size_t Begin, size_t End, IRBuilder<> &IRB,
|
|
|
|
Value *ShadowBase);
|
|
|
|
void copyToShadowInline(ArrayRef<uint8_t> ShadowMask,
|
|
|
|
ArrayRef<uint8_t> ShadowBytes, size_t Begin,
|
|
|
|
size_t End, IRBuilder<> &IRB, Value *ShadowBase);
|
|
|
|
|
2013-08-10 04:53:48 +08:00
|
|
|
void poisonAlloca(Value *V, uint64_t Size, IRBuilder<> &IRB, bool DoPoison);
|
2013-09-17 20:14:50 +08:00
|
|
|
|
2014-12-12 05:53:03 +08:00
|
|
|
Value *createAllocaForLayout(IRBuilder<> &IRB, const ASanStackFrameLayout &L,
|
|
|
|
bool Dynamic);
|
|
|
|
PHINode *createPHI(IRBuilder<> &IRB, Value *Cond, Value *ValueIfTrue,
|
|
|
|
Instruction *ThenTerm, Value *ValueIfFalse);
|
2012-12-25 20:04:36 +08:00
|
|
|
};
|
|
|
|
|
2017-10-20 06:07:16 +08:00
|
|
|
} // end anonymous namespace
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
void LocationMetadata::parse(MDNode *MDN) {
|
|
|
|
assert(MDN->getNumOperands() == 3);
|
|
|
|
MDString *DIFilename = cast<MDString>(MDN->getOperand(0));
|
|
|
|
Filename = DIFilename->getString();
|
|
|
|
LineNo = mdconst::extract<ConstantInt>(MDN->getOperand(1))->getLimitedValue();
|
|
|
|
ColumnNo =
|
|
|
|
mdconst::extract<ConstantInt>(MDN->getOperand(2))->getLimitedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: It would be cleaner to instead attach relevant metadata to the globals
|
|
|
|
// we want to sanitize instead and reading this metadata on each pass over a
|
|
|
|
// function instead of reading module level metadata at first.
|
|
|
|
GlobalsMetadata::GlobalsMetadata(Module &M) {
|
|
|
|
NamedMDNode *Globals = M.getNamedMetadata("llvm.asan.globals");
|
|
|
|
if (!Globals)
|
|
|
|
return;
|
|
|
|
for (auto MDN : Globals->operands()) {
|
|
|
|
// Metadata node contains the global and the fields of "Entry".
|
|
|
|
assert(MDN->getNumOperands() == 5);
|
|
|
|
auto *V = mdconst::extract_or_null<Constant>(MDN->getOperand(0));
|
|
|
|
// The optimizer may optimize away a global entirely.
|
|
|
|
if (!V)
|
|
|
|
continue;
|
|
|
|
auto *StrippedV = V->stripPointerCasts();
|
|
|
|
auto *GV = dyn_cast<GlobalVariable>(StrippedV);
|
|
|
|
if (!GV)
|
|
|
|
continue;
|
|
|
|
// We can already have an entry for GV if it was merged with another
|
|
|
|
// global.
|
|
|
|
Entry &E = Entries[GV];
|
|
|
|
if (auto *Loc = cast_or_null<MDNode>(MDN->getOperand(1)))
|
|
|
|
E.SourceLoc.parse(Loc);
|
|
|
|
if (auto *Name = cast_or_null<MDString>(MDN->getOperand(2)))
|
|
|
|
E.Name = Name->getString();
|
|
|
|
ConstantInt *IsDynInit = mdconst::extract<ConstantInt>(MDN->getOperand(3));
|
|
|
|
E.IsDynInit |= IsDynInit->isOne();
|
2020-06-20 15:42:26 +08:00
|
|
|
ConstantInt *IsExcluded =
|
2019-02-14 06:22:48 +08:00
|
|
|
mdconst::extract<ConstantInt>(MDN->getOperand(4));
|
2020-06-20 15:42:26 +08:00
|
|
|
E.IsExcluded |= IsExcluded->isOne();
|
2019-02-14 06:22:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AnalysisKey ASanGlobalsMetadataAnalysis::Key;
|
|
|
|
|
|
|
|
GlobalsMetadata ASanGlobalsMetadataAnalysis::run(Module &M,
|
|
|
|
ModuleAnalysisManager &AM) {
|
|
|
|
return GlobalsMetadata(M);
|
|
|
|
}
|
|
|
|
|
|
|
|
AddressSanitizerPass::AddressSanitizerPass(bool CompileKernel, bool Recover,
|
|
|
|
bool UseAfterScope)
|
|
|
|
: CompileKernel(CompileKernel), Recover(Recover),
|
|
|
|
UseAfterScope(UseAfterScope) {}
|
|
|
|
|
|
|
|
PreservedAnalyses AddressSanitizerPass::run(Function &F,
|
|
|
|
AnalysisManager<Function> &AM) {
|
|
|
|
auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
|
|
|
|
Module &M = *F.getParent();
|
2020-01-15 02:27:20 +08:00
|
|
|
if (auto *R = MAMProxy.getCachedResult<ASanGlobalsMetadataAnalysis>(M)) {
|
2019-02-14 06:22:48 +08:00
|
|
|
const TargetLibraryInfo *TLI = &AM.getResult<TargetLibraryAnalysis>(F);
|
2019-10-02 04:49:07 +08:00
|
|
|
AddressSanitizer Sanitizer(M, R, CompileKernel, Recover, UseAfterScope);
|
2019-02-14 06:22:48 +08:00
|
|
|
if (Sanitizer.instrumentFunction(F, TLI))
|
|
|
|
return PreservedAnalyses::none();
|
|
|
|
return PreservedAnalyses::all();
|
|
|
|
}
|
|
|
|
|
|
|
|
report_fatal_error(
|
|
|
|
"The ASanGlobalsMetadataAnalysis is required to run before "
|
|
|
|
"AddressSanitizer can run");
|
|
|
|
return PreservedAnalyses::all();
|
|
|
|
}
|
|
|
|
|
|
|
|
ModuleAddressSanitizerPass::ModuleAddressSanitizerPass(bool CompileKernel,
|
|
|
|
bool Recover,
|
|
|
|
bool UseGlobalGC,
|
|
|
|
bool UseOdrIndicator)
|
|
|
|
: CompileKernel(CompileKernel), Recover(Recover), UseGlobalGC(UseGlobalGC),
|
|
|
|
UseOdrIndicator(UseOdrIndicator) {}
|
|
|
|
|
|
|
|
PreservedAnalyses ModuleAddressSanitizerPass::run(Module &M,
|
|
|
|
AnalysisManager<Module> &AM) {
|
|
|
|
GlobalsMetadata &GlobalsMD = AM.getResult<ASanGlobalsMetadataAnalysis>(M);
|
2019-10-02 04:49:07 +08:00
|
|
|
ModuleAddressSanitizer Sanitizer(M, &GlobalsMD, CompileKernel, Recover,
|
2019-02-14 06:22:48 +08:00
|
|
|
UseGlobalGC, UseOdrIndicator);
|
|
|
|
if (Sanitizer.instrumentModule(M))
|
|
|
|
return PreservedAnalyses::none();
|
|
|
|
return PreservedAnalyses::all();
|
|
|
|
}
|
|
|
|
|
|
|
|
INITIALIZE_PASS(ASanGlobalsMetadataWrapperPass, "asan-globals-md",
|
|
|
|
"Read metadata to mark which globals should be instrumented "
|
|
|
|
"when running ASan.",
|
2019-02-14 20:10:49 +08:00
|
|
|
false, true)
|
2019-02-14 06:22:48 +08:00
|
|
|
|
|
|
|
char AddressSanitizerLegacyPass::ID = 0;
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
INITIALIZE_PASS_BEGIN(
|
2019-02-14 06:22:48 +08:00
|
|
|
AddressSanitizerLegacyPass, "asan",
|
2015-03-04 21:27:53 +08:00
|
|
|
"AddressSanitizer: detects use-after-free and out-of-bounds bugs.", false,
|
|
|
|
false)
|
2019-02-14 06:22:48 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(ASanGlobalsMetadataWrapperPass)
|
2015-10-20 18:13:55 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
|
2015-03-04 21:27:53 +08:00
|
|
|
INITIALIZE_PASS_END(
|
2019-02-14 06:22:48 +08:00
|
|
|
AddressSanitizerLegacyPass, "asan",
|
2015-03-04 21:27:53 +08:00
|
|
|
"AddressSanitizer: detects use-after-free and out-of-bounds bugs.", false,
|
|
|
|
false)
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-11-11 18:36:49 +08:00
|
|
|
FunctionPass *llvm::createAddressSanitizerFunctionPass(bool CompileKernel,
|
2016-05-28 06:55:10 +08:00
|
|
|
bool Recover,
|
|
|
|
bool UseAfterScope) {
|
2015-11-11 18:36:49 +08:00
|
|
|
assert(!CompileKernel || Recover);
|
2019-02-14 06:22:48 +08:00
|
|
|
return new AddressSanitizerLegacyPass(CompileKernel, Recover, UseAfterScope);
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
char ModuleAddressSanitizerLegacyPass::ID = 0;
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
INITIALIZE_PASS(
|
2019-02-14 06:22:48 +08:00
|
|
|
ModuleAddressSanitizerLegacyPass, "asan-module",
|
2012-11-28 18:31:36 +08:00
|
|
|
"AddressSanitizer: detects use-after-free and out-of-bounds bugs."
|
2015-03-04 21:27:53 +08:00
|
|
|
"ModulePass",
|
|
|
|
false, false)
|
2017-10-20 06:07:16 +08:00
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
ModulePass *llvm::createModuleAddressSanitizerLegacyPassPass(
|
|
|
|
bool CompileKernel, bool Recover, bool UseGlobalsGC, bool UseOdrIndicator) {
|
2015-11-11 18:36:49 +08:00
|
|
|
assert(!CompileKernel || Recover);
|
2019-02-14 06:22:48 +08:00
|
|
|
return new ModuleAddressSanitizerLegacyPass(CompileKernel, Recover,
|
|
|
|
UseGlobalsGC, UseOdrIndicator);
|
2012-01-23 19:22:43 +08:00
|
|
|
}
|
|
|
|
|
2012-07-17 01:12:07 +08:00
|
|
|
static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
|
2013-05-25 06:23:49 +08:00
|
|
|
size_t Res = countTrailingZeros(TypeSize / 8);
|
2012-07-17 01:12:07 +08:00
|
|
|
assert(Res < kNumberOfAccessSizes);
|
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
2018-05-01 23:54:18 +08:00
|
|
|
/// Create a global describing a source location.
|
2014-08-02 08:35:50 +08:00
|
|
|
static GlobalVariable *createPrivateGlobalForSourceLoc(Module &M,
|
|
|
|
LocationMetadata MD) {
|
|
|
|
Constant *LocData[] = {
|
2018-10-12 07:03:27 +08:00
|
|
|
createPrivateGlobalForString(M, MD.Filename, true, kAsanGenPrefix),
|
2014-08-02 08:35:50 +08:00
|
|
|
ConstantInt::get(Type::getInt32Ty(M.getContext()), MD.LineNo),
|
|
|
|
ConstantInt::get(Type::getInt32Ty(M.getContext()), MD.ColumnNo),
|
|
|
|
};
|
|
|
|
auto LocStruct = ConstantStruct::getAnon(LocData);
|
|
|
|
auto GV = new GlobalVariable(M, LocStruct->getType(), true,
|
|
|
|
GlobalValue::PrivateLinkage, LocStruct,
|
|
|
|
kAsanGenPrefix);
|
2016-06-15 05:01:22 +08:00
|
|
|
GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
2014-08-02 08:35:50 +08:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2018-05-01 23:54:18 +08:00
|
|
|
/// Check if \p G has been created by a trusted compiler pass.
|
2016-06-23 01:30:58 +08:00
|
|
|
static bool GlobalWasGeneratedByCompiler(GlobalVariable *G) {
|
2018-08-21 07:35:45 +08:00
|
|
|
// Do not instrument @llvm.global_ctors, @llvm.used, etc.
|
|
|
|
if (G->getName().startswith("llvm."))
|
|
|
|
return true;
|
|
|
|
|
2016-06-23 01:30:58 +08:00
|
|
|
// Do not instrument asan globals.
|
|
|
|
if (G->getName().startswith(kAsanGenPrefix) ||
|
|
|
|
G->getName().startswith(kSanCovGenPrefix) ||
|
|
|
|
G->getName().startswith(kODRGenPrefix))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Do not instrument gcov counter arrays.
|
|
|
|
if (G->getName() == "__llvm_gcov_ctr")
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Value *AddressSanitizer::memToShadow(Value *Shadow, IRBuilder<> &IRB) {
|
|
|
|
// Shadow >> scale
|
2013-01-16 21:23:28 +08:00
|
|
|
Shadow = IRB.CreateLShr(Shadow, Mapping.Scale);
|
2015-03-04 21:27:53 +08:00
|
|
|
if (Mapping.Offset == 0) return Shadow;
|
2011-11-16 09:35:23 +08:00
|
|
|
// (Shadow >> scale) | offset
|
2016-10-01 01:46:32 +08:00
|
|
|
Value *ShadowBase;
|
|
|
|
if (LocalDynamicShadow)
|
|
|
|
ShadowBase = LocalDynamicShadow;
|
|
|
|
else
|
|
|
|
ShadowBase = ConstantInt::get(IntptrTy, Mapping.Offset);
|
2013-01-23 20:54:55 +08:00
|
|
|
if (Mapping.OrShadowOffset)
|
2016-10-01 01:46:32 +08:00
|
|
|
return IRB.CreateOr(Shadow, ShadowBase);
|
2013-01-23 20:54:55 +08:00
|
|
|
else
|
2016-10-01 01:46:32 +08:00
|
|
|
return IRB.CreateAdd(Shadow, ShadowBase);
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Instrument memset/memmove/memcpy
|
2014-04-21 19:50:42 +08:00
|
|
|
void AddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) {
|
|
|
|
IRBuilder<> IRB(MI);
|
|
|
|
if (isa<MemTransferInst>(MI)) {
|
2015-05-19 06:13:54 +08:00
|
|
|
IRB.CreateCall(
|
2014-04-21 19:50:42 +08:00
|
|
|
isa<MemMoveInst>(MI) ? AsanMemmove : AsanMemcpy,
|
2015-05-19 06:13:54 +08:00
|
|
|
{IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()),
|
|
|
|
IRB.CreatePointerCast(MI->getOperand(1), IRB.getInt8PtrTy()),
|
|
|
|
IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
|
2014-04-21 19:50:42 +08:00
|
|
|
} else if (isa<MemSetInst>(MI)) {
|
2015-05-19 06:13:54 +08:00
|
|
|
IRB.CreateCall(
|
2014-04-21 19:50:42 +08:00
|
|
|
AsanMemset,
|
2015-05-19 06:13:54 +08:00
|
|
|
{IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()),
|
|
|
|
IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false),
|
|
|
|
IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
2014-04-21 19:50:42 +08:00
|
|
|
MI->eraseFromParent();
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
2015-02-27 11:12:36 +08:00
|
|
|
/// Check if we want (and can) handle this alloca.
|
2016-07-29 06:50:50 +08:00
|
|
|
bool AddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
|
2015-03-28 02:52:01 +08:00
|
|
|
auto PreviouslySeenAllocaInfo = ProcessedAllocas.find(&AI);
|
|
|
|
|
|
|
|
if (PreviouslySeenAllocaInfo != ProcessedAllocas.end())
|
|
|
|
return PreviouslySeenAllocaInfo->getSecond();
|
|
|
|
|
2015-05-28 15:51:49 +08:00
|
|
|
bool IsInteresting =
|
|
|
|
(AI.getAllocatedType()->isSized() &&
|
|
|
|
// alloca() may be called with 0 size, ignore it.
|
2016-07-29 06:50:50 +08:00
|
|
|
((!AI.isStaticAlloca()) || getAllocaSizeInBytes(AI) > 0) &&
|
2015-05-28 15:51:49 +08:00
|
|
|
// We are only interested in allocas not promotable to registers.
|
|
|
|
// Promotable allocas are common under -O0.
|
2015-11-06 05:18:41 +08:00
|
|
|
(!ClSkipPromotableAllocas || !isAllocaPromotable(&AI)) &&
|
|
|
|
// inalloca allocas are not treated as static, and we don't want
|
|
|
|
// dynamic alloca instrumentation for them as well.
|
2017-02-16 04:43:43 +08:00
|
|
|
!AI.isUsedWithInAlloca() &&
|
|
|
|
// swifterror allocas are register promoted by ISel
|
|
|
|
!AI.isSwiftError());
|
2015-03-28 02:52:01 +08:00
|
|
|
|
|
|
|
ProcessedAllocas[&AI] = IsInteresting;
|
|
|
|
return IsInteresting;
|
2015-02-27 11:12:36 +08:00
|
|
|
}
|
|
|
|
|
2020-04-30 17:05:00 +08:00
|
|
|
bool AddressSanitizer::ignoreAccess(Value *Ptr) {
|
|
|
|
// Do not instrument acesses from different address spaces; we cannot deal
|
|
|
|
// with them.
|
|
|
|
Type *PtrTy = cast<PointerType>(Ptr->getType()->getScalarType());
|
|
|
|
if (PtrTy->getPointerAddressSpace() != 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Ignore swifterror addresses.
|
|
|
|
// swifterror memory addresses are mem2reg promoted by instruction
|
|
|
|
// selection. As such they cannot have regular uses like an instrumentation
|
|
|
|
// function and it makes no sense to track them as memory.
|
|
|
|
if (Ptr->isSwiftError())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Treat memory accesses to promotable allocas as non-interesting since they
|
|
|
|
// will not cause memory violations. This greatly speeds up the instrumented
|
|
|
|
// executable at -O0.
|
|
|
|
if (auto AI = dyn_cast_or_null<AllocaInst>(Ptr))
|
|
|
|
if (ClSkipPromotableAllocas && !isInterestingAlloca(*AI))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddressSanitizer::getInterestingMemoryOperands(
|
|
|
|
Instruction *I, SmallVectorImpl<InterestingMemoryOperand> &Interesting) {
|
2014-07-18 02:48:12 +08:00
|
|
|
// Skip memory accesses inserted by another instrumentation.
|
2020-04-30 17:05:00 +08:00
|
|
|
if (I->hasMetadata("nosanitize"))
|
|
|
|
return;
|
2015-02-27 11:12:36 +08:00
|
|
|
|
2016-10-01 01:46:32 +08:00
|
|
|
// Do not instrument the load fetching the dynamic shadow address.
|
|
|
|
if (LocalDynamicShadow == I)
|
2020-04-30 17:05:00 +08:00
|
|
|
return;
|
2016-10-01 01:46:32 +08:00
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
|
2020-04-30 17:05:00 +08:00
|
|
|
if (!ClInstrumentReads || ignoreAccess(LI->getPointerOperand()))
|
|
|
|
return;
|
|
|
|
Interesting.emplace_back(I, LI->getPointerOperandIndex(), false,
|
2020-07-03 16:06:43 +08:00
|
|
|
LI->getType(), LI->getAlign());
|
2015-02-27 11:12:36 +08:00
|
|
|
} else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
|
2020-04-30 17:05:00 +08:00
|
|
|
if (!ClInstrumentWrites || ignoreAccess(SI->getPointerOperand()))
|
|
|
|
return;
|
|
|
|
Interesting.emplace_back(I, SI->getPointerOperandIndex(), true,
|
2020-07-03 16:06:43 +08:00
|
|
|
SI->getValueOperand()->getType(), SI->getAlign());
|
2015-02-27 11:12:36 +08:00
|
|
|
} else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
|
2020-04-30 17:05:00 +08:00
|
|
|
if (!ClInstrumentAtomics || ignoreAccess(RMW->getPointerOperand()))
|
|
|
|
return;
|
|
|
|
Interesting.emplace_back(I, RMW->getPointerOperandIndex(), true,
|
2020-07-03 16:06:43 +08:00
|
|
|
RMW->getValOperand()->getType(), None);
|
2015-02-27 11:12:36 +08:00
|
|
|
} else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
|
2020-04-30 17:05:00 +08:00
|
|
|
if (!ClInstrumentAtomics || ignoreAccess(XCHG->getPointerOperand()))
|
|
|
|
return;
|
|
|
|
Interesting.emplace_back(I, XCHG->getPointerOperandIndex(), true,
|
2020-07-03 16:06:43 +08:00
|
|
|
XCHG->getCompareOperand()->getType(), None);
|
2016-11-16 06:37:30 +08:00
|
|
|
} else if (auto CI = dyn_cast<CallInst>(I)) {
|
2020-04-28 11:15:59 +08:00
|
|
|
auto *F = CI->getCalledFunction();
|
2016-11-16 06:37:30 +08:00
|
|
|
if (F && (F->getName().startswith("llvm.masked.load.") ||
|
|
|
|
F->getName().startswith("llvm.masked.store."))) {
|
2020-04-30 17:05:00 +08:00
|
|
|
bool IsWrite = F->getName().startswith("llvm.masked.store.");
|
|
|
|
// Masked store has an initial operand for the value.
|
|
|
|
unsigned OpOffset = IsWrite ? 1 : 0;
|
|
|
|
if (IsWrite ? !ClInstrumentWrites : !ClInstrumentReads)
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto BasePtr = CI->getOperand(OpOffset);
|
|
|
|
if (ignoreAccess(BasePtr))
|
|
|
|
return;
|
2017-01-06 23:24:51 +08:00
|
|
|
auto Ty = cast<PointerType>(BasePtr->getType())->getElementType();
|
2020-07-03 16:06:43 +08:00
|
|
|
MaybeAlign Alignment = Align(1);
|
2020-04-30 17:05:00 +08:00
|
|
|
// Otherwise no alignment guarantees. We probably got Undef.
|
2020-07-03 16:06:43 +08:00
|
|
|
if (auto *Op = dyn_cast<ConstantInt>(CI->getOperand(1 + OpOffset)))
|
|
|
|
Alignment = Op->getMaybeAlignValue();
|
2020-04-30 17:05:00 +08:00
|
|
|
Value *Mask = CI->getOperand(2 + OpOffset);
|
|
|
|
Interesting.emplace_back(I, OpOffset, IsWrite, Ty, Alignment, Mask);
|
[AddressSanitizer] Instrument byval call arguments
Summary:
In the LLVM IR, "call" instructions read memory for each byval operand.
For example:
```
$ cat blah.c
struct foo { void *a, *b, *c; };
struct bar { struct foo foo; };
void func1(const struct foo);
void func2(struct bar *bar) { func1(bar->foo); }
$ [...]/bin/clang -S -flto -c blah.c -O2 ; cat blah.s
[...]
define dso_local void @func2(%struct.bar* %bar) local_unnamed_addr #0 {
entry:
%foo = getelementptr inbounds %struct.bar, %struct.bar* %bar, i64 0, i32 0
tail call void @func1(%struct.foo* byval(%struct.foo) align 8 %foo) #2
ret void
}
[...]
$ [...]/bin/clang -S -c blah.c -O2 ; cat blah.s
[...]
func2: # @func2
[...]
subq $24, %rsp
[...]
movq 16(%rdi), %rax
movq %rax, 16(%rsp)
movups (%rdi), %xmm0
movups %xmm0, (%rsp)
callq func1
addq $24, %rsp
[...]
retq
```
Let ASAN instrument these hidden memory accesses.
This is patch 4/4 of a patch series:
https://reviews.llvm.org/D77616 [PATCH 1/4] [AddressSanitizer] Refactor ClDebug{Min,Max} handling
https://reviews.llvm.org/D77617 [PATCH 2/4] [AddressSanitizer] Split out memory intrinsic handling
https://reviews.llvm.org/D77618 [PATCH 3/4] [AddressSanitizer] Refactor: Permit >1 interesting operands per instruction
https://reviews.llvm.org/D77619 [PATCH 4/4] [AddressSanitizer] Instrument byval call arguments
Reviewers: kcc, glider
Reviewed By: glider
Subscribers: hiraditya, dexonsmith, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77619
2020-04-30 17:05:01 +08:00
|
|
|
} else {
|
|
|
|
for (unsigned ArgNo = 0; ArgNo < CI->getNumArgOperands(); ArgNo++) {
|
|
|
|
if (!ClInstrumentByval || !CI->isByValArgument(ArgNo) ||
|
|
|
|
ignoreAccess(CI->getArgOperand(ArgNo)))
|
|
|
|
continue;
|
|
|
|
Type *Ty = CI->getParamByValType(ArgNo);
|
2020-07-03 16:06:43 +08:00
|
|
|
Interesting.emplace_back(I, ArgNo, false, Ty, Align(1));
|
[AddressSanitizer] Instrument byval call arguments
Summary:
In the LLVM IR, "call" instructions read memory for each byval operand.
For example:
```
$ cat blah.c
struct foo { void *a, *b, *c; };
struct bar { struct foo foo; };
void func1(const struct foo);
void func2(struct bar *bar) { func1(bar->foo); }
$ [...]/bin/clang -S -flto -c blah.c -O2 ; cat blah.s
[...]
define dso_local void @func2(%struct.bar* %bar) local_unnamed_addr #0 {
entry:
%foo = getelementptr inbounds %struct.bar, %struct.bar* %bar, i64 0, i32 0
tail call void @func1(%struct.foo* byval(%struct.foo) align 8 %foo) #2
ret void
}
[...]
$ [...]/bin/clang -S -c blah.c -O2 ; cat blah.s
[...]
func2: # @func2
[...]
subq $24, %rsp
[...]
movq 16(%rdi), %rax
movq %rax, 16(%rsp)
movups (%rdi), %xmm0
movups %xmm0, (%rsp)
callq func1
addq $24, %rsp
[...]
retq
```
Let ASAN instrument these hidden memory accesses.
This is patch 4/4 of a patch series:
https://reviews.llvm.org/D77616 [PATCH 1/4] [AddressSanitizer] Refactor ClDebug{Min,Max} handling
https://reviews.llvm.org/D77617 [PATCH 2/4] [AddressSanitizer] Split out memory intrinsic handling
https://reviews.llvm.org/D77618 [PATCH 3/4] [AddressSanitizer] Refactor: Permit >1 interesting operands per instruction
https://reviews.llvm.org/D77619 [PATCH 4/4] [AddressSanitizer] Instrument byval call arguments
Reviewers: kcc, glider
Reviewed By: glider
Subscribers: hiraditya, dexonsmith, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77619
2020-04-30 17:05:01 +08:00
|
|
|
}
|
2016-11-16 06:37:30 +08:00
|
|
|
}
|
2012-05-30 17:04:06 +08:00
|
|
|
}
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
2014-02-27 20:45:36 +08:00
|
|
|
static bool isPointerOperand(Value *V) {
|
|
|
|
return V->getType()->isPointerTy() || isa<PtrToIntInst>(V);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is a rough heuristic; it may cause both false positives and
|
|
|
|
// false negatives. The proper implementation requires cooperation with
|
|
|
|
// the frontend.
|
2019-03-28 18:51:24 +08:00
|
|
|
static bool isInterestingPointerComparison(Instruction *I) {
|
2014-02-27 20:45:36 +08:00
|
|
|
if (ICmpInst *Cmp = dyn_cast<ICmpInst>(I)) {
|
2019-03-28 18:51:24 +08:00
|
|
|
if (!Cmp->isRelational())
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return isPointerOperand(I->getOperand(0)) &&
|
|
|
|
isPointerOperand(I->getOperand(1));
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is a rough heuristic; it may cause both false positives and
|
|
|
|
// false negatives. The proper implementation requires cooperation with
|
|
|
|
// the frontend.
|
|
|
|
static bool isInterestingPointerSubtraction(Instruction *I) {
|
|
|
|
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(I)) {
|
|
|
|
if (BO->getOpcode() != Instruction::Sub)
|
|
|
|
return false;
|
2014-02-27 20:45:36 +08:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2015-10-27 02:06:40 +08:00
|
|
|
return isPointerOperand(I->getOperand(0)) &&
|
|
|
|
isPointerOperand(I->getOperand(1));
|
2014-02-27 20:45:36 +08:00
|
|
|
}
|
|
|
|
|
2013-10-16 22:06:14 +08:00
|
|
|
bool AddressSanitizer::GlobalIsLinkerInitialized(GlobalVariable *G) {
|
|
|
|
// If a global variable does not have dynamic initialization we don't
|
|
|
|
// have to instrument it. However, if a global does not have initializer
|
|
|
|
// at all, we assume it has dynamic initializer (in other TU).
|
2019-02-14 06:22:48 +08:00
|
|
|
//
|
|
|
|
// FIXME: Metadata should be attched directly to the global directly instead
|
|
|
|
// of being added to llvm.asan.globals.
|
2014-07-12 06:36:02 +08:00
|
|
|
return G->hasInitializer() && !GlobalsMD.get(G).IsDynInit;
|
2013-10-16 22:06:14 +08:00
|
|
|
}
|
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
void AddressSanitizer::instrumentPointerComparisonOrSubtraction(
|
|
|
|
Instruction *I) {
|
2014-02-27 20:45:36 +08:00
|
|
|
IRBuilder<> IRB(I);
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee F = isa<ICmpInst>(I) ? AsanPtrCmpFunction : AsanPtrSubFunction;
|
2014-02-27 20:45:36 +08:00
|
|
|
Value *Param[2] = {I->getOperand(0), I->getOperand(1)};
|
2016-06-26 20:28:59 +08:00
|
|
|
for (Value *&i : Param) {
|
|
|
|
if (i->getType()->isPointerTy())
|
|
|
|
i = IRB.CreatePointerCast(i, IntptrTy);
|
2014-02-27 20:45:36 +08:00
|
|
|
}
|
2015-05-19 06:13:54 +08:00
|
|
|
IRB.CreateCall(F, Param);
|
2014-02-27 20:45:36 +08:00
|
|
|
}
|
|
|
|
|
2016-11-16 06:37:30 +08:00
|
|
|
static void doInstrumentAddress(AddressSanitizer *Pass, Instruction *I,
|
2017-01-06 23:24:51 +08:00
|
|
|
Instruction *InsertBefore, Value *Addr,
|
2020-07-03 16:06:43 +08:00
|
|
|
MaybeAlign Alignment, unsigned Granularity,
|
2017-01-06 23:24:51 +08:00
|
|
|
uint32_t TypeSize, bool IsWrite,
|
|
|
|
Value *SizeArgument, bool UseCalls,
|
|
|
|
uint32_t Exp) {
|
2016-11-16 06:37:30 +08:00
|
|
|
// Instrument a 1-, 2-, 4-, 8-, or 16- byte access with one check
|
|
|
|
// if the data is properly aligned.
|
|
|
|
if ((TypeSize == 8 || TypeSize == 16 || TypeSize == 32 || TypeSize == 64 ||
|
|
|
|
TypeSize == 128) &&
|
2020-07-03 16:06:43 +08:00
|
|
|
(!Alignment || *Alignment >= Granularity || *Alignment >= TypeSize / 8))
|
2017-01-06 23:24:51 +08:00
|
|
|
return Pass->instrumentAddress(I, InsertBefore, Addr, TypeSize, IsWrite,
|
|
|
|
nullptr, UseCalls, Exp);
|
|
|
|
Pass->instrumentUnusualSizeOrAlignment(I, InsertBefore, Addr, TypeSize,
|
|
|
|
IsWrite, nullptr, UseCalls, Exp);
|
2016-11-16 06:37:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void instrumentMaskedLoadOrStore(AddressSanitizer *Pass,
|
|
|
|
const DataLayout &DL, Type *IntptrTy,
|
2017-01-06 23:24:51 +08:00
|
|
|
Value *Mask, Instruction *I,
|
2020-07-03 16:06:43 +08:00
|
|
|
Value *Addr, MaybeAlign Alignment,
|
2016-11-16 06:37:30 +08:00
|
|
|
unsigned Granularity, uint32_t TypeSize,
|
|
|
|
bool IsWrite, Value *SizeArgument,
|
|
|
|
bool UseCalls, uint32_t Exp) {
|
2020-06-30 05:46:25 +08:00
|
|
|
auto *VTy = cast<FixedVectorType>(
|
|
|
|
cast<PointerType>(Addr->getType())->getElementType());
|
2016-11-16 06:37:30 +08:00
|
|
|
uint64_t ElemTypeSize = DL.getTypeStoreSizeInBits(VTy->getScalarType());
|
2020-04-10 22:35:06 +08:00
|
|
|
unsigned Num = VTy->getNumElements();
|
2016-11-16 06:37:30 +08:00
|
|
|
auto Zero = ConstantInt::get(IntptrTy, 0);
|
|
|
|
for (unsigned Idx = 0; Idx < Num; ++Idx) {
|
2017-01-06 23:24:51 +08:00
|
|
|
Value *InstrumentedAddress = nullptr;
|
|
|
|
Instruction *InsertBefore = I;
|
|
|
|
if (auto *Vector = dyn_cast<ConstantVector>(Mask)) {
|
|
|
|
// dyn_cast as we might get UndefValue
|
|
|
|
if (auto *Masked = dyn_cast<ConstantInt>(Vector->getOperand(Idx))) {
|
2017-07-07 02:39:47 +08:00
|
|
|
if (Masked->isZero())
|
2017-01-06 23:24:51 +08:00
|
|
|
// Mask is constant false, so no instrumentation needed.
|
|
|
|
continue;
|
|
|
|
// If we have a true or undef value, fall through to doInstrumentAddress
|
|
|
|
// with InsertBefore == I
|
|
|
|
}
|
|
|
|
} else {
|
2016-11-16 06:37:30 +08:00
|
|
|
IRBuilder<> IRB(I);
|
2017-01-06 23:24:51 +08:00
|
|
|
Value *MaskElem = IRB.CreateExtractElement(Mask, Idx);
|
2018-10-15 17:34:05 +08:00
|
|
|
Instruction *ThenTerm = SplitBlockAndInsertIfThen(MaskElem, I, false);
|
2017-01-06 23:24:51 +08:00
|
|
|
InsertBefore = ThenTerm;
|
2016-11-16 06:37:30 +08:00
|
|
|
}
|
2017-01-06 23:24:51 +08:00
|
|
|
|
|
|
|
IRBuilder<> IRB(InsertBefore);
|
|
|
|
InstrumentedAddress =
|
2019-02-02 04:44:47 +08:00
|
|
|
IRB.CreateGEP(VTy, Addr, {Zero, ConstantInt::get(IntptrTy, Idx)});
|
2017-01-06 23:24:51 +08:00
|
|
|
doInstrumentAddress(Pass, I, InsertBefore, InstrumentedAddress, Alignment,
|
|
|
|
Granularity, ElemTypeSize, IsWrite, SizeArgument,
|
|
|
|
UseCalls, Exp);
|
2016-11-16 06:37:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
void AddressSanitizer::instrumentMop(ObjectSizeOffsetVisitor &ObjSizeVis,
|
2020-04-30 17:05:00 +08:00
|
|
|
InterestingMemoryOperand &O, bool UseCalls,
|
2015-03-10 10:37:25 +08:00
|
|
|
const DataLayout &DL) {
|
2020-04-30 17:05:00 +08:00
|
|
|
Value *Addr = O.getPtr();
|
2015-03-04 21:27:53 +08:00
|
|
|
|
2015-03-18 00:59:19 +08:00
|
|
|
// Optimization experiments.
|
|
|
|
// The experiments can be used to evaluate potential optimizations that remove
|
|
|
|
// instrumentation (assess false negatives). Instead of completely removing
|
|
|
|
// some instrumentation, you set Exp to a non-zero value (mask of optimization
|
|
|
|
// experiments that want to remove instrumentation of this instruction).
|
|
|
|
// If Exp is non-zero, this pass will emit special calls into runtime
|
|
|
|
// (e.g. __asan_report_exp_load1 instead of __asan_report_load1). These calls
|
|
|
|
// make runtime terminate the program in a special way (with a different
|
|
|
|
// exit status). Then you run the new compiler on a buggy corpus, collect
|
|
|
|
// the special terminations (ideally, you don't see them at all -- no false
|
|
|
|
// negatives) and make the decision on the optimization.
|
|
|
|
uint32_t Exp = ClForceExperiment;
|
|
|
|
|
2012-08-21 16:24:25 +08:00
|
|
|
if (ClOpt && ClOptGlobals) {
|
2015-03-04 21:27:53 +08:00
|
|
|
// If initialization order checking is disabled, a simple access to a
|
|
|
|
// dynamically initialized global is always valid.
|
2015-03-10 10:37:25 +08:00
|
|
|
GlobalVariable *G = dyn_cast<GlobalVariable>(GetUnderlyingObject(Addr, DL));
|
2015-10-07 07:24:35 +08:00
|
|
|
if (G && (!ClInitializers || GlobalIsLinkerInitialized(G)) &&
|
2020-04-30 17:05:00 +08:00
|
|
|
isSafeAccess(ObjSizeVis, Addr, O.TypeSize)) {
|
2015-03-04 21:27:53 +08:00
|
|
|
NumOptimizedAccessesToGlobalVar++;
|
|
|
|
return;
|
2012-08-21 16:24:25 +08:00
|
|
|
}
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
2012-08-21 16:24:25 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
if (ClOpt && ClOptStack) {
|
|
|
|
// A direct inbounds access to a stack variable is always valid.
|
2015-03-10 10:37:25 +08:00
|
|
|
if (isa<AllocaInst>(GetUnderlyingObject(Addr, DL)) &&
|
2020-04-30 17:05:00 +08:00
|
|
|
isSafeAccess(ObjSizeVis, Addr, O.TypeSize)) {
|
2015-03-04 21:27:53 +08:00
|
|
|
NumOptimizedAccessesToStackVar++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2020-04-30 17:05:00 +08:00
|
|
|
if (O.IsWrite)
|
2013-10-16 22:06:14 +08:00
|
|
|
NumInstrumentedWrites++;
|
|
|
|
else
|
|
|
|
NumInstrumentedReads++;
|
|
|
|
|
2014-05-23 19:52:07 +08:00
|
|
|
unsigned Granularity = 1 << Mapping.Scale;
|
2020-04-30 17:05:00 +08:00
|
|
|
if (O.MaybeMask) {
|
|
|
|
instrumentMaskedLoadOrStore(this, DL, IntptrTy, O.MaybeMask, O.getInsn(),
|
|
|
|
Addr, O.Alignment, Granularity, O.TypeSize,
|
|
|
|
O.IsWrite, nullptr, UseCalls, Exp);
|
2016-11-16 06:37:30 +08:00
|
|
|
} else {
|
2020-04-30 17:05:00 +08:00
|
|
|
doInstrumentAddress(this, O.getInsn(), O.getInsn(), Addr, O.Alignment,
|
|
|
|
Granularity, O.TypeSize, O.IsWrite, nullptr, UseCalls,
|
|
|
|
Exp);
|
2016-11-16 06:37:30 +08:00
|
|
|
}
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
Instruction *AddressSanitizer::generateCrashCode(Instruction *InsertBefore,
|
|
|
|
Value *Addr, bool IsWrite,
|
|
|
|
size_t AccessSizeIndex,
|
2015-03-18 00:59:19 +08:00
|
|
|
Value *SizeArgument,
|
|
|
|
uint32_t Exp) {
|
2012-08-14 22:04:51 +08:00
|
|
|
IRBuilder<> IRB(InsertBefore);
|
2015-03-18 00:59:19 +08:00
|
|
|
Value *ExpVal = Exp == 0 ? nullptr : ConstantInt::get(IRB.getInt32Ty(), Exp);
|
|
|
|
CallInst *Call = nullptr;
|
|
|
|
if (SizeArgument) {
|
|
|
|
if (Exp == 0)
|
2015-05-19 06:13:54 +08:00
|
|
|
Call = IRB.CreateCall(AsanErrorCallbackSized[IsWrite][0],
|
|
|
|
{Addr, SizeArgument});
|
2015-03-18 00:59:19 +08:00
|
|
|
else
|
2015-05-19 06:13:54 +08:00
|
|
|
Call = IRB.CreateCall(AsanErrorCallbackSized[IsWrite][1],
|
|
|
|
{Addr, SizeArgument, ExpVal});
|
2015-03-18 00:59:19 +08:00
|
|
|
} else {
|
|
|
|
if (Exp == 0)
|
|
|
|
Call =
|
|
|
|
IRB.CreateCall(AsanErrorCallback[IsWrite][0][AccessSizeIndex], Addr);
|
|
|
|
else
|
2015-05-19 06:13:54 +08:00
|
|
|
Call = IRB.CreateCall(AsanErrorCallback[IsWrite][1][AccessSizeIndex],
|
|
|
|
{Addr, ExpVal});
|
2015-03-18 00:59:19 +08:00
|
|
|
}
|
2013-02-19 19:29:21 +08:00
|
|
|
|
2020-06-23 02:43:52 +08:00
|
|
|
Call->setCannotMerge();
|
2012-01-07 02:09:21 +08:00
|
|
|
return Call;
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
2012-07-17 01:12:07 +08:00
|
|
|
Value *AddressSanitizer::createSlowPathCmp(IRBuilder<> &IRB, Value *AddrLong,
|
2015-03-04 21:27:53 +08:00
|
|
|
Value *ShadowValue,
|
|
|
|
uint32_t TypeSize) {
|
2016-03-31 05:30:00 +08:00
|
|
|
size_t Granularity = static_cast<size_t>(1) << Mapping.Scale;
|
2012-07-17 00:15:40 +08:00
|
|
|
// Addr & (Granularity - 1)
|
2015-03-04 21:27:53 +08:00
|
|
|
Value *LastAccessedByte =
|
|
|
|
IRB.CreateAnd(AddrLong, ConstantInt::get(IntptrTy, Granularity - 1));
|
2012-07-17 00:15:40 +08:00
|
|
|
// (Addr & (Granularity - 1)) + size - 1
|
|
|
|
if (TypeSize / 8 > 1)
|
|
|
|
LastAccessedByte = IRB.CreateAdd(
|
|
|
|
LastAccessedByte, ConstantInt::get(IntptrTy, TypeSize / 8 - 1));
|
|
|
|
// (uint8_t) ((Addr & (Granularity-1)) + size - 1)
|
2015-03-04 21:27:53 +08:00
|
|
|
LastAccessedByte =
|
|
|
|
IRB.CreateIntCast(LastAccessedByte, ShadowValue->getType(), false);
|
2012-07-17 00:15:40 +08:00
|
|
|
// ((uint8_t) ((Addr & (Granularity-1)) + size - 1)) >= ShadowValue
|
|
|
|
return IRB.CreateICmpSGE(LastAccessedByte, ShadowValue);
|
|
|
|
}
|
|
|
|
|
2012-10-15 22:20:06 +08:00
|
|
|
void AddressSanitizer::instrumentAddress(Instruction *OrigIns,
|
2014-04-16 20:12:19 +08:00
|
|
|
Instruction *InsertBefore, Value *Addr,
|
|
|
|
uint32_t TypeSize, bool IsWrite,
|
2015-03-18 00:59:19 +08:00
|
|
|
Value *SizeArgument, bool UseCalls,
|
|
|
|
uint32_t Exp) {
|
2018-05-18 12:10:38 +08:00
|
|
|
bool IsMyriad = TargetTriple.getVendor() == llvm::Triple::Myriad;
|
|
|
|
|
2013-02-19 19:29:21 +08:00
|
|
|
IRBuilder<> IRB(InsertBefore);
|
2011-11-16 09:35:23 +08:00
|
|
|
Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
|
2014-04-16 20:12:19 +08:00
|
|
|
size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
|
|
|
|
|
|
|
|
if (UseCalls) {
|
2015-03-18 00:59:19 +08:00
|
|
|
if (Exp == 0)
|
|
|
|
IRB.CreateCall(AsanMemoryAccessCallback[IsWrite][0][AccessSizeIndex],
|
|
|
|
AddrLong);
|
|
|
|
else
|
2015-05-19 06:13:54 +08:00
|
|
|
IRB.CreateCall(AsanMemoryAccessCallback[IsWrite][1][AccessSizeIndex],
|
|
|
|
{AddrLong, ConstantInt::get(IRB.getInt32Ty(), Exp)});
|
2014-04-16 20:12:19 +08:00
|
|
|
return;
|
|
|
|
}
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2018-05-18 12:10:38 +08:00
|
|
|
if (IsMyriad) {
|
|
|
|
// Strip the cache bit and do range check.
|
|
|
|
// AddrLong &= ~kMyriadCacheBitMask32
|
|
|
|
AddrLong = IRB.CreateAnd(AddrLong, ~kMyriadCacheBitMask32);
|
|
|
|
// Tag = AddrLong >> kMyriadTagShift
|
|
|
|
Value *Tag = IRB.CreateLShr(AddrLong, kMyriadTagShift);
|
|
|
|
// Tag == kMyriadDDRTag
|
|
|
|
Value *TagCheck =
|
|
|
|
IRB.CreateICmpEQ(Tag, ConstantInt::get(IntptrTy, kMyriadDDRTag));
|
|
|
|
|
2018-10-15 17:34:05 +08:00
|
|
|
Instruction *TagCheckTerm =
|
|
|
|
SplitBlockAndInsertIfThen(TagCheck, InsertBefore, false,
|
|
|
|
MDBuilder(*C).createBranchWeights(1, 100000));
|
2018-05-18 12:10:38 +08:00
|
|
|
assert(cast<BranchInst>(TagCheckTerm)->isUnconditional());
|
|
|
|
IRB.SetInsertPoint(TagCheckTerm);
|
|
|
|
InsertBefore = TagCheckTerm;
|
|
|
|
}
|
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
Type *ShadowTy =
|
|
|
|
IntegerType::get(*C, std::max(8U, TypeSize >> Mapping.Scale));
|
2011-11-16 09:35:23 +08:00
|
|
|
Type *ShadowPtrTy = PointerType::get(ShadowTy, 0);
|
|
|
|
Value *ShadowPtr = memToShadow(AddrLong, IRB);
|
|
|
|
Value *CmpVal = Constant::getNullValue(ShadowTy);
|
2015-03-04 21:27:53 +08:00
|
|
|
Value *ShadowValue =
|
2019-02-02 04:44:24 +08:00
|
|
|
IRB.CreateLoad(ShadowTy, IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy));
|
2011-11-16 09:35:23 +08:00
|
|
|
|
|
|
|
Value *Cmp = IRB.CreateICmpNE(ShadowValue, CmpVal);
|
2016-03-31 05:30:00 +08:00
|
|
|
size_t Granularity = 1ULL << Mapping.Scale;
|
2018-10-15 17:34:05 +08:00
|
|
|
Instruction *CrashTerm = nullptr;
|
2012-08-14 22:04:51 +08:00
|
|
|
|
2012-08-15 16:58:58 +08:00
|
|
|
if (ClAlwaysSlowPath || (TypeSize < 8 * Granularity)) {
|
2014-09-03 05:46:51 +08:00
|
|
|
// We use branch weights for the slow path check, to indicate that the slow
|
|
|
|
// path is rarely taken. This seems to be the case for SPEC benchmarks.
|
2018-10-15 17:34:05 +08:00
|
|
|
Instruction *CheckTerm = SplitBlockAndInsertIfThen(
|
2015-03-04 21:27:53 +08:00
|
|
|
Cmp, InsertBefore, false, MDBuilder(*C).createBranchWeights(1, 100000));
|
2015-04-10 19:24:51 +08:00
|
|
|
assert(cast<BranchInst>(CheckTerm)->isUnconditional());
|
2012-07-20 17:54:50 +08:00
|
|
|
BasicBlock *NextBB = CheckTerm->getSuccessor(0);
|
2012-07-17 00:15:40 +08:00
|
|
|
IRB.SetInsertPoint(CheckTerm);
|
|
|
|
Value *Cmp2 = createSlowPathCmp(IRB, AddrLong, ShadowValue, TypeSize);
|
2015-11-11 18:36:49 +08:00
|
|
|
if (Recover) {
|
|
|
|
CrashTerm = SplitBlockAndInsertIfThen(Cmp2, CheckTerm, false);
|
|
|
|
} else {
|
|
|
|
BasicBlock *CrashBlock =
|
2012-10-15 22:20:06 +08:00
|
|
|
BasicBlock::Create(*C, "", NextBB->getParent(), NextBB);
|
2015-11-11 18:36:49 +08:00
|
|
|
CrashTerm = new UnreachableInst(*C, CrashBlock);
|
|
|
|
BranchInst *NewTerm = BranchInst::Create(CrashBlock, NextBB, Cmp2);
|
|
|
|
ReplaceInstWithInst(CheckTerm, NewTerm);
|
|
|
|
}
|
2012-07-17 00:15:40 +08:00
|
|
|
} else {
|
2015-11-11 18:36:49 +08:00
|
|
|
CrashTerm = SplitBlockAndInsertIfThen(Cmp, InsertBefore, !Recover);
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
2012-08-14 22:04:51 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
Instruction *Crash = generateCrashCode(CrashTerm, AddrLong, IsWrite,
|
2015-03-18 00:59:19 +08:00
|
|
|
AccessSizeIndex, SizeArgument, Exp);
|
2012-08-14 22:04:51 +08:00
|
|
|
Crash->setDebugLoc(OrigIns->getDebugLoc());
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
2015-03-18 00:59:19 +08:00
|
|
|
// Instrument unusual size or unusual alignment.
|
|
|
|
// We can not do it with a single check, so we do 1-byte check for the first
|
|
|
|
// and the last bytes. We call __asan_report_*_n(addr, real_size) to be able
|
|
|
|
// to report the actual access size.
|
|
|
|
void AddressSanitizer::instrumentUnusualSizeOrAlignment(
|
2017-01-06 23:24:51 +08:00
|
|
|
Instruction *I, Instruction *InsertBefore, Value *Addr, uint32_t TypeSize,
|
|
|
|
bool IsWrite, Value *SizeArgument, bool UseCalls, uint32_t Exp) {
|
|
|
|
IRBuilder<> IRB(InsertBefore);
|
2015-03-18 00:59:19 +08:00
|
|
|
Value *Size = ConstantInt::get(IntptrTy, TypeSize / 8);
|
|
|
|
Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
|
|
|
|
if (UseCalls) {
|
|
|
|
if (Exp == 0)
|
2015-05-19 06:13:54 +08:00
|
|
|
IRB.CreateCall(AsanMemoryAccessCallbackSized[IsWrite][0],
|
|
|
|
{AddrLong, Size});
|
2015-03-18 00:59:19 +08:00
|
|
|
else
|
2015-05-19 06:13:54 +08:00
|
|
|
IRB.CreateCall(AsanMemoryAccessCallbackSized[IsWrite][1],
|
|
|
|
{AddrLong, Size, ConstantInt::get(IRB.getInt32Ty(), Exp)});
|
2015-03-18 00:59:19 +08:00
|
|
|
} else {
|
|
|
|
Value *LastByte = IRB.CreateIntToPtr(
|
|
|
|
IRB.CreateAdd(AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8 - 1)),
|
|
|
|
Addr->getType());
|
2017-01-06 23:24:51 +08:00
|
|
|
instrumentAddress(I, InsertBefore, Addr, 8, IsWrite, Size, false, Exp);
|
|
|
|
instrumentAddress(I, InsertBefore, LastByte, 8, IsWrite, Size, false, Exp);
|
2015-03-18 00:59:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
void ModuleAddressSanitizer::poisonOneInitializer(Function &GlobalInit,
|
2014-05-29 08:51:15 +08:00
|
|
|
GlobalValue *ModuleName) {
|
2012-08-21 16:24:25 +08:00
|
|
|
// Set up the arguments to our poison/unpoison functions.
|
2015-10-14 01:39:10 +08:00
|
|
|
IRBuilder<> IRB(&GlobalInit.front(),
|
|
|
|
GlobalInit.front().getFirstInsertionPt());
|
2012-08-21 16:24:25 +08:00
|
|
|
|
|
|
|
// Add a call to poison all external globals before the given function starts.
|
2013-03-26 21:05:41 +08:00
|
|
|
Value *ModuleNameAddr = ConstantExpr::getPointerCast(ModuleName, IntptrTy);
|
|
|
|
IRB.CreateCall(AsanPoisonGlobals, ModuleNameAddr);
|
2012-08-21 16:24:25 +08:00
|
|
|
|
|
|
|
// Add calls to unpoison all globals before each return instruction.
|
2014-05-29 08:51:15 +08:00
|
|
|
for (auto &BB : GlobalInit.getBasicBlockList())
|
|
|
|
if (ReturnInst *RI = dyn_cast<ReturnInst>(BB.getTerminator()))
|
2012-08-21 16:24:25 +08:00
|
|
|
CallInst::Create(AsanUnpoisonGlobals, "", RI);
|
2014-05-29 08:51:15 +08:00
|
|
|
}
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
void ModuleAddressSanitizer::createInitializerPoisonCalls(
|
2014-05-29 08:51:15 +08:00
|
|
|
Module &M, GlobalValue *ModuleName) {
|
|
|
|
GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors");
|
2017-04-28 04:27:23 +08:00
|
|
|
if (!GV)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ConstantArray *CA = dyn_cast<ConstantArray>(GV->getInitializer());
|
|
|
|
if (!CA)
|
|
|
|
return;
|
2014-05-29 08:51:15 +08:00
|
|
|
|
|
|
|
for (Use &OP : CA->operands()) {
|
2015-03-04 21:27:53 +08:00
|
|
|
if (isa<ConstantAggregateZero>(OP)) continue;
|
2014-05-29 08:51:15 +08:00
|
|
|
ConstantStruct *CS = cast<ConstantStruct>(OP);
|
|
|
|
|
|
|
|
// Must have a function or null ptr.
|
2015-03-04 21:27:53 +08:00
|
|
|
if (Function *F = dyn_cast<Function>(CS->getOperand(1))) {
|
2014-09-25 06:41:55 +08:00
|
|
|
if (F->getName() == kAsanModuleCtorName) continue;
|
2019-09-21 04:52:21 +08:00
|
|
|
auto *Priority = cast<ConstantInt>(CS->getOperand(0));
|
2014-09-25 06:41:55 +08:00
|
|
|
// Don't instrument CTORs that will run before asan.module_ctor.
|
[WebAssembly] Lower ASan constructor priority on Emscripten
Summary:
This change gives Emscripten the ability to use more than one constructor
priorities that runs before ASan. By convention, constructor priorites 0-100
are reserved for use by the system. ASan on Emscripten now uses priority 50,
leaving plenty of room for use by Emscripten before and after ASan.
This change is done in response to:
https://github.com/emscripten-core/emscripten/pull/9076#discussion_r310323723
Reviewers: kripken, tlively, aheejin
Reviewed By: tlively
Subscribers: cfe-commits, dschuff, sbc100, jgravelle-google, hiraditya, sunfish, llvm-commits
Tags: #llvm, #clang
Differential Revision: https://reviews.llvm.org/D65684
llvm-svn: 368101
2019-08-07 05:52:58 +08:00
|
|
|
if (Priority->getLimitedValue() <= GetCtorAndDtorPriority(TargetTriple))
|
|
|
|
continue;
|
2014-09-25 06:41:55 +08:00
|
|
|
poisonOneInitializer(*F, ModuleName);
|
2012-08-21 16:24:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-10 21:01:40 +08:00
|
|
|
bool ModuleAddressSanitizer::canInstrumentAliasedGlobal(
|
|
|
|
const GlobalAlias &GA) const {
|
|
|
|
// In case this function should be expanded to include rules that do not just
|
|
|
|
// apply when CompileKernel is true, either guard all existing rules with an
|
|
|
|
// 'if (CompileKernel) { ... }' or be absolutely sure that all these rules
|
|
|
|
// should also apply to user space.
|
|
|
|
assert(CompileKernel && "Only expecting to be called when compiling kernel");
|
|
|
|
|
|
|
|
// When compiling the kernel, globals that are aliased by symbols prefixed
|
|
|
|
// by "__" are special and cannot be padded with a redzone.
|
|
|
|
if (GA.getName().startswith("__"))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ModuleAddressSanitizer::shouldInstrumentGlobal(GlobalVariable *G) const {
|
2016-01-17 04:30:46 +08:00
|
|
|
Type *Ty = G->getValueType();
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "GLOBAL: " << *G << "\n");
|
2012-08-21 16:24:25 +08:00
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
// FIXME: Metadata should be attched directly to the global directly instead
|
|
|
|
// of being added to llvm.asan.globals.
|
2020-06-20 15:42:26 +08:00
|
|
|
if (GlobalsMD.get(G).IsExcluded) return false;
|
2012-08-21 16:24:25 +08:00
|
|
|
if (!Ty->isSized()) return false;
|
|
|
|
if (!G->hasInitializer()) return false;
|
2019-10-30 14:45:39 +08:00
|
|
|
// Only instrument globals of default address spaces
|
|
|
|
if (G->getAddressSpace()) return false;
|
2016-06-23 01:30:58 +08:00
|
|
|
if (GlobalWasGeneratedByCompiler(G)) return false; // Our own globals.
|
2012-08-21 16:24:25 +08:00
|
|
|
// Two problems with thread-locals:
|
|
|
|
// - The address of the main thread's copy can't be computed at link-time.
|
|
|
|
// - Need to poison all copies, not just the main thread's one.
|
2015-03-04 21:27:53 +08:00
|
|
|
if (G->isThreadLocal()) return false;
|
2013-12-06 17:00:17 +08:00
|
|
|
// For now, just ignore this Global if the alignment is large.
|
2020-06-12 20:58:00 +08:00
|
|
|
if (G->getAlignment() > getMinRedzoneSizeForGlobal()) return false;
|
2012-08-21 16:24:25 +08:00
|
|
|
|
2018-08-21 07:35:45 +08:00
|
|
|
// For non-COFF targets, only instrument globals known to be defined by this
|
|
|
|
// TU.
|
|
|
|
// FIXME: We can instrument comdat globals on ELF if we are using the
|
|
|
|
// GC-friendly metadata scheme.
|
|
|
|
if (!TargetTriple.isOSBinFormatCOFF()) {
|
|
|
|
if (!G->hasExactDefinition() || G->hasComdat())
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
// On COFF, don't instrument non-ODR linkages.
|
|
|
|
if (G->isInterposable())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If a comdat is present, it must have a selection kind that implies ODR
|
|
|
|
// semantics: no duplicates, any, or exact match.
|
|
|
|
if (Comdat *C = G->getComdat()) {
|
|
|
|
switch (C->getSelectionKind()) {
|
|
|
|
case Comdat::Any:
|
|
|
|
case Comdat::ExactMatch:
|
|
|
|
case Comdat::NoDuplicates:
|
|
|
|
break;
|
|
|
|
case Comdat::Largest:
|
|
|
|
case Comdat::SameSize:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-21 16:24:25 +08:00
|
|
|
if (G->hasSection()) {
|
2020-06-10 21:01:40 +08:00
|
|
|
// The kernel uses explicit sections for mostly special global variables
|
|
|
|
// that we should not instrument. E.g. the kernel may rely on their layout
|
|
|
|
// without redzones, or remove them at link time ("discard.*"), etc.
|
|
|
|
if (CompileKernel)
|
|
|
|
return false;
|
|
|
|
|
2016-05-12 02:21:59 +08:00
|
|
|
StringRef Section = G->getSection();
|
2014-05-05 22:28:38 +08:00
|
|
|
|
2015-06-09 08:58:08 +08:00
|
|
|
// Globals from llvm.metadata aren't emitted, do not instrument them.
|
|
|
|
if (Section == "llvm.metadata") return false;
|
2015-06-26 07:35:48 +08:00
|
|
|
// Do not instrument globals from special LLVM sections.
|
2016-02-25 06:12:18 +08:00
|
|
|
if (Section.find("__llvm") != StringRef::npos || Section.find("__LLVM") != StringRef::npos) return false;
|
2015-06-09 08:58:08 +08:00
|
|
|
|
2015-09-16 07:05:48 +08:00
|
|
|
// Do not instrument function pointers to initialization and termination
|
|
|
|
// routines: dynamic linker will not properly handle redzones.
|
|
|
|
if (Section.startswith(".preinit_array") ||
|
|
|
|
Section.startswith(".init_array") ||
|
|
|
|
Section.startswith(".fini_array")) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-06-14 04:47:21 +08:00
|
|
|
// On COFF, if the section name contains '$', it is highly likely that the
|
|
|
|
// user is using section sorting to create an array of globals similar to
|
|
|
|
// the way initialization callbacks are registered in .init_array and
|
|
|
|
// .CRT$XCU. The ATL also registers things in .ATL$__[azm]. Adding redzones
|
|
|
|
// to such globals is counterproductive, because the intent is that they
|
|
|
|
// will form an array, and out-of-bounds accesses are expected.
|
2017-11-14 07:47:58 +08:00
|
|
|
// See https://github.com/google/sanitizers/issues/305
|
2015-06-09 08:58:08 +08:00
|
|
|
// and http://msdn.microsoft.com/en-US/en-en/library/bb918180(v=vs.120).aspx
|
2018-06-14 04:47:21 +08:00
|
|
|
if (TargetTriple.isOSBinFormatCOFF() && Section.contains('$')) {
|
|
|
|
LLVM_DEBUG(dbgs() << "Ignoring global in sorted section (contains '$'): "
|
|
|
|
<< *G << "\n");
|
2015-06-09 08:58:08 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-12-06 06:19:18 +08:00
|
|
|
if (TargetTriple.isOSBinFormatMachO()) {
|
|
|
|
StringRef ParsedSegment, ParsedSection;
|
|
|
|
unsigned TAA = 0, StubSize = 0;
|
|
|
|
bool TAAParsed;
|
2015-03-04 21:27:53 +08:00
|
|
|
std::string ErrorCode = MCSectionMachO::ParseSectionSpecifier(
|
|
|
|
Section, ParsedSegment, ParsedSection, TAA, TAAParsed, StubSize);
|
2015-11-20 05:50:08 +08:00
|
|
|
assert(ErrorCode.empty() && "Invalid section specifier.");
|
2014-12-06 06:19:18 +08:00
|
|
|
|
|
|
|
// Ignore the globals from the __OBJC section. The ObjC runtime assumes
|
|
|
|
// those conform to /usr/lib/objc/runtime.h, so we can't add redzones to
|
|
|
|
// them.
|
|
|
|
if (ParsedSegment == "__OBJC" ||
|
|
|
|
(ParsedSegment == "__DATA" && ParsedSection.startswith("__objc_"))) {
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "Ignoring ObjC runtime global: " << *G << "\n");
|
2014-12-06 06:19:18 +08:00
|
|
|
return false;
|
|
|
|
}
|
2017-11-14 07:47:58 +08:00
|
|
|
// See https://github.com/google/sanitizers/issues/32
|
2014-12-06 06:19:18 +08:00
|
|
|
// Constant CFString instances are compiled in the following way:
|
|
|
|
// -- the string buffer is emitted into
|
|
|
|
// __TEXT,__cstring,cstring_literals
|
|
|
|
// -- the constant NSConstantString structure referencing that buffer
|
|
|
|
// is placed into __DATA,__cfstring
|
|
|
|
// Therefore there's no point in placing redzones into __DATA,__cfstring.
|
|
|
|
// Moreover, it causes the linker to crash on OS X 10.7
|
|
|
|
if (ParsedSegment == "__DATA" && ParsedSection == "__cfstring") {
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "Ignoring CFString: " << *G << "\n");
|
2014-12-06 06:19:18 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// The linker merges the contents of cstring_literals and removes the
|
|
|
|
// trailing zeroes.
|
|
|
|
if (ParsedSegment == "__TEXT" && (TAA & MachO::S_CSTRING_LITERALS)) {
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "Ignoring a cstring literal: " << *G << "\n");
|
2014-12-06 06:19:18 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2012-08-21 16:24:25 +08:00
|
|
|
}
|
|
|
|
|
2020-06-10 21:01:40 +08:00
|
|
|
if (CompileKernel) {
|
|
|
|
// Globals that prefixed by "__" are special and cannot be padded with a
|
|
|
|
// redzone.
|
|
|
|
if (G->getName().startswith("__"))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-08-21 16:24:25 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-03-29 04:28:57 +08:00
|
|
|
// On Mach-O platforms, we emit global metadata in a separate section of the
|
|
|
|
// binary in order to allow the linker to properly dead strip. This is only
|
|
|
|
// supported on recent versions of ld64.
|
2019-02-14 06:22:48 +08:00
|
|
|
bool ModuleAddressSanitizer::ShouldUseMachOGlobalsSection() const {
|
2016-03-29 04:28:57 +08:00
|
|
|
if (!TargetTriple.isOSBinFormatMachO())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (TargetTriple.isMacOSX() && !TargetTriple.isMacOSXVersionLT(10, 11))
|
|
|
|
return true;
|
|
|
|
if (TargetTriple.isiOS() /* or tvOS */ && !TargetTriple.isOSVersionLT(9))
|
2016-04-22 06:00:13 +08:00
|
|
|
return true;
|
2016-03-29 04:28:57 +08:00
|
|
|
if (TargetTriple.isWatchOS() && !TargetTriple.isOSVersionLT(2))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
StringRef ModuleAddressSanitizer::getGlobalMetadataSection() const {
|
[asan] Make ASan compatible with linker dead stripping on Windows
Summary:
This is similar to what was done for Darwin in rL264645 /
http://reviews.llvm.org/D16737, but it uses COFF COMDATs to achive the
same result instead of relying on new custom linker features.
As on MachO, this creates one metadata global per instrumented global.
The metadata global is placed in the custom .ASAN$GL section, which the
ASan runtime will iterate over during initialization. There are no other
references to the metadata, so normal linker dead stripping would
discard it. However, the metadata is put in a COMDAT group with the
instrumented global, so that it will be discarded if and only if the
instrumented global is discarded.
I didn't update the ASan ABI version check since this doesn't affect
non-Windows platforms, and the WinASan ABI isn't really stable yet.
Implementing this for ELF will require extending LLVM IR and MC a bit so
that we can use non-COMDAT section groups.
Reviewers: pcc, kcc, mehdi_amini, kubabrecka
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D26770
llvm-svn: 287576
2016-11-22 04:40:37 +08:00
|
|
|
switch (TargetTriple.getObjectFormat()) {
|
|
|
|
case Triple::COFF: return ".ASAN$GL";
|
|
|
|
case Triple::ELF: return "asan_globals";
|
|
|
|
case Triple::MachO: return "__DATA,__asan_globals,regular";
|
[sanitizers] Use covering ObjectFormatType switches
Summary:
This patch removes the `default` case from some switches on
`llvm::Triple::ObjectFormatType`, and cases for the missing enumerators
(`UnknownObjectFormat`, `Wasm`, and `XCOFF`) are then added.
For `UnknownObjectFormat`, the effect of the action for the `default`
case is maintained; otherwise, where `llvm_unreachable` is called,
`report_fatal_error` is used instead.
Where the `default` case returns a default value, `report_fatal_error`
is used for XCOFF as a placeholder. For `Wasm`, the effect of the action
for the `default` case in maintained.
The code is structured to avoid strongly implying that the `Wasm` case
is present for any reason other than to make the switch cover all
`ObjectFormatType` enumerator values.
Reviewers: sfertile, jasonliu, daltenty
Reviewed By: sfertile
Subscribers: hiraditya, aheejin, sunfish, llvm-commits, cfe-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D64222
llvm-svn: 366544
2019-07-19 16:46:18 +08:00
|
|
|
case Triple::Wasm:
|
|
|
|
case Triple::XCOFF:
|
|
|
|
report_fatal_error(
|
|
|
|
"ModuleAddressSanitizer not implemented for object file format.");
|
|
|
|
case Triple::UnknownObjectFormat:
|
|
|
|
break;
|
[asan] Make ASan compatible with linker dead stripping on Windows
Summary:
This is similar to what was done for Darwin in rL264645 /
http://reviews.llvm.org/D16737, but it uses COFF COMDATs to achive the
same result instead of relying on new custom linker features.
As on MachO, this creates one metadata global per instrumented global.
The metadata global is placed in the custom .ASAN$GL section, which the
ASan runtime will iterate over during initialization. There are no other
references to the metadata, so normal linker dead stripping would
discard it. However, the metadata is put in a COMDAT group with the
instrumented global, so that it will be discarded if and only if the
instrumented global is discarded.
I didn't update the ASan ABI version check since this doesn't affect
non-Windows platforms, and the WinASan ABI isn't really stable yet.
Implementing this for ELF will require extending LLVM IR and MC a bit so
that we can use non-COMDAT section groups.
Reviewers: pcc, kcc, mehdi_amini, kubabrecka
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D26770
llvm-svn: 287576
2016-11-22 04:40:37 +08:00
|
|
|
}
|
|
|
|
llvm_unreachable("unsupported object format");
|
|
|
|
}
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
void ModuleAddressSanitizer::initializeCallbacks(Module &M) {
|
2012-12-25 20:28:20 +08:00
|
|
|
IRBuilder<> IRB(*C);
|
2016-03-29 04:28:57 +08:00
|
|
|
|
2012-12-25 20:28:20 +08:00
|
|
|
// Declare our poisoning and unpoisoning functions.
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
AsanPoisonGlobals =
|
|
|
|
M.getOrInsertFunction(kAsanPoisonGlobalsName, IRB.getVoidTy(), IntptrTy);
|
|
|
|
AsanUnpoisonGlobals =
|
|
|
|
M.getOrInsertFunction(kAsanUnpoisonGlobalsName, IRB.getVoidTy());
|
2016-03-29 04:28:57 +08:00
|
|
|
|
2012-12-25 20:28:20 +08:00
|
|
|
// Declare functions that register/unregister globals.
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
AsanRegisterGlobals = M.getOrInsertFunction(
|
|
|
|
kAsanRegisterGlobalsName, IRB.getVoidTy(), IntptrTy, IntptrTy);
|
|
|
|
AsanUnregisterGlobals = M.getOrInsertFunction(
|
|
|
|
kAsanUnregisterGlobalsName, IRB.getVoidTy(), IntptrTy, IntptrTy);
|
2016-03-29 04:28:57 +08:00
|
|
|
|
|
|
|
// Declare the functions that find globals in a shared object and then invoke
|
|
|
|
// the (un)register function on them.
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
AsanRegisterImageGlobals = M.getOrInsertFunction(
|
|
|
|
kAsanRegisterImageGlobalsName, IRB.getVoidTy(), IntptrTy);
|
|
|
|
AsanUnregisterImageGlobals = M.getOrInsertFunction(
|
|
|
|
kAsanUnregisterImageGlobalsName, IRB.getVoidTy(), IntptrTy);
|
2016-04-22 06:00:13 +08:00
|
|
|
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
AsanRegisterElfGlobals =
|
2017-04-28 04:27:27 +08:00
|
|
|
M.getOrInsertFunction(kAsanRegisterElfGlobalsName, IRB.getVoidTy(),
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
IntptrTy, IntptrTy, IntptrTy);
|
|
|
|
AsanUnregisterElfGlobals =
|
2017-04-28 04:27:27 +08:00
|
|
|
M.getOrInsertFunction(kAsanUnregisterElfGlobalsName, IRB.getVoidTy(),
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
IntptrTy, IntptrTy, IntptrTy);
|
2012-12-25 20:28:20 +08:00
|
|
|
}
|
|
|
|
|
2017-01-13 07:03:03 +08:00
|
|
|
// Put the metadata and the instrumented global in the same group. This ensures
|
|
|
|
// that the metadata is discarded if the instrumented global is discarded.
|
2019-02-14 06:22:48 +08:00
|
|
|
void ModuleAddressSanitizer::SetComdatForGlobalMetadata(
|
2017-04-28 04:27:27 +08:00
|
|
|
GlobalVariable *G, GlobalVariable *Metadata, StringRef InternalSuffix) {
|
2017-01-13 07:03:03 +08:00
|
|
|
Module &M = *G->getParent();
|
|
|
|
Comdat *C = G->getComdat();
|
|
|
|
if (!C) {
|
|
|
|
if (!G->hasName()) {
|
|
|
|
// If G is unnamed, it must be internal. Give it an artificial name
|
|
|
|
// so we can put it in a comdat.
|
|
|
|
assert(G->hasLocalLinkage());
|
|
|
|
G->setName(Twine(kAsanGenPrefix) + "_anon_global");
|
|
|
|
}
|
2017-04-28 04:27:27 +08:00
|
|
|
|
|
|
|
if (!InternalSuffix.empty() && G->hasLocalLinkage()) {
|
2020-01-29 03:23:46 +08:00
|
|
|
std::string Name = std::string(G->getName());
|
2017-04-28 04:27:27 +08:00
|
|
|
Name += InternalSuffix;
|
|
|
|
C = M.getOrInsertComdat(Name);
|
|
|
|
} else {
|
|
|
|
C = M.getOrInsertComdat(G->getName());
|
|
|
|
}
|
|
|
|
|
2017-11-01 00:16:08 +08:00
|
|
|
// Make this IMAGE_COMDAT_SELECT_NODUPLICATES on COFF. Also upgrade private
|
|
|
|
// linkage to internal linkage so that a symbol table entry is emitted. This
|
|
|
|
// is necessary in order to create the comdat group.
|
|
|
|
if (TargetTriple.isOSBinFormatCOFF()) {
|
2017-01-13 07:03:03 +08:00
|
|
|
C->setSelectionKind(Comdat::NoDuplicates);
|
2017-11-01 00:16:08 +08:00
|
|
|
if (G->hasPrivateLinkage())
|
|
|
|
G->setLinkage(GlobalValue::InternalLinkage);
|
|
|
|
}
|
2017-01-13 07:03:03 +08:00
|
|
|
G->setComdat(C);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(G->hasComdat());
|
|
|
|
Metadata->setComdat(G->getComdat());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a separate metadata global and put it in the appropriate ASan
|
|
|
|
// global registration section.
|
|
|
|
GlobalVariable *
|
2019-02-14 06:22:48 +08:00
|
|
|
ModuleAddressSanitizer::CreateMetadataGlobal(Module &M, Constant *Initializer,
|
2017-01-13 07:03:03 +08:00
|
|
|
StringRef OriginalName) {
|
2017-04-12 06:28:13 +08:00
|
|
|
auto Linkage = TargetTriple.isOSBinFormatMachO()
|
|
|
|
? GlobalVariable::InternalLinkage
|
|
|
|
: GlobalVariable::PrivateLinkage;
|
|
|
|
GlobalVariable *Metadata = new GlobalVariable(
|
|
|
|
M, Initializer->getType(), false, Linkage, Initializer,
|
2017-05-16 08:39:01 +08:00
|
|
|
Twine("__asan_global_") + GlobalValue::dropLLVMManglingEscape(OriginalName));
|
2017-01-13 07:03:03 +08:00
|
|
|
Metadata->setSection(getGlobalMetadataSection());
|
|
|
|
return Metadata;
|
|
|
|
}
|
|
|
|
|
2020-02-17 00:46:26 +08:00
|
|
|
Instruction *ModuleAddressSanitizer::CreateAsanModuleDtor(Module &M) {
|
2017-04-28 04:27:23 +08:00
|
|
|
AsanDtorFunction =
|
2017-01-13 07:03:03 +08:00
|
|
|
Function::Create(FunctionType::get(Type::getVoidTy(*C), false),
|
|
|
|
GlobalValue::InternalLinkage, kAsanModuleDtorName, &M);
|
|
|
|
BasicBlock *AsanDtorBB = BasicBlock::Create(*C, "", AsanDtorFunction);
|
|
|
|
|
2020-02-17 00:46:26 +08:00
|
|
|
return ReturnInst::Create(*C, AsanDtorBB);
|
2017-01-13 07:03:03 +08:00
|
|
|
}
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
void ModuleAddressSanitizer::InstrumentGlobalsCOFF(
|
2017-01-13 07:03:03 +08:00
|
|
|
IRBuilder<> &IRB, Module &M, ArrayRef<GlobalVariable *> ExtendedGlobals,
|
|
|
|
ArrayRef<Constant *> MetadataInitializers) {
|
|
|
|
assert(ExtendedGlobals.size() == MetadataInitializers.size());
|
2017-01-13 07:26:20 +08:00
|
|
|
auto &DL = M.getDataLayout();
|
2017-01-13 07:03:03 +08:00
|
|
|
|
2020-06-05 00:48:42 +08:00
|
|
|
SmallVector<GlobalValue *, 16> MetadataGlobals(ExtendedGlobals.size());
|
2017-01-13 07:03:03 +08:00
|
|
|
for (size_t i = 0; i < ExtendedGlobals.size(); i++) {
|
2017-01-13 07:26:20 +08:00
|
|
|
Constant *Initializer = MetadataInitializers[i];
|
2017-01-13 07:03:03 +08:00
|
|
|
GlobalVariable *G = ExtendedGlobals[i];
|
|
|
|
GlobalVariable *Metadata =
|
2017-01-13 07:26:20 +08:00
|
|
|
CreateMetadataGlobal(M, Initializer, G->getName());
|
2020-06-05 00:48:42 +08:00
|
|
|
MDNode *MD = MDNode::get(M.getContext(), ValueAsMetadata::get(G));
|
|
|
|
Metadata->setMetadata(LLVMContext::MD_associated, MD);
|
|
|
|
MetadataGlobals[i] = Metadata;
|
2017-01-13 07:26:20 +08:00
|
|
|
|
|
|
|
// The MSVC linker always inserts padding when linking incrementally. We
|
|
|
|
// cope with that by aligning each struct to its size, which must be a power
|
|
|
|
// of two.
|
|
|
|
unsigned SizeOfGlobalStruct = DL.getTypeAllocSize(Initializer->getType());
|
|
|
|
assert(isPowerOf2_32(SizeOfGlobalStruct) &&
|
|
|
|
"global metadata will not be padded appropriately");
|
2019-10-15 19:24:36 +08:00
|
|
|
Metadata->setAlignment(assumeAligned(SizeOfGlobalStruct));
|
2017-01-13 07:26:20 +08:00
|
|
|
|
2017-04-28 04:27:27 +08:00
|
|
|
SetComdatForGlobalMetadata(G, Metadata, "");
|
2017-01-13 07:03:03 +08:00
|
|
|
}
|
2020-06-05 00:48:42 +08:00
|
|
|
|
|
|
|
// Update llvm.compiler.used, adding the new metadata globals. This is
|
|
|
|
// needed so that during LTO these variables stay alive.
|
|
|
|
if (!MetadataGlobals.empty())
|
|
|
|
appendToCompilerUsed(M, MetadataGlobals);
|
2017-01-13 07:03:03 +08:00
|
|
|
}
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
void ModuleAddressSanitizer::InstrumentGlobalsELF(
|
2017-04-28 04:27:27 +08:00
|
|
|
IRBuilder<> &IRB, Module &M, ArrayRef<GlobalVariable *> ExtendedGlobals,
|
|
|
|
ArrayRef<Constant *> MetadataInitializers,
|
|
|
|
const std::string &UniqueModuleId) {
|
|
|
|
assert(ExtendedGlobals.size() == MetadataInitializers.size());
|
|
|
|
|
|
|
|
SmallVector<GlobalValue *, 16> MetadataGlobals(ExtendedGlobals.size());
|
|
|
|
for (size_t i = 0; i < ExtendedGlobals.size(); i++) {
|
|
|
|
GlobalVariable *G = ExtendedGlobals[i];
|
|
|
|
GlobalVariable *Metadata =
|
|
|
|
CreateMetadataGlobal(M, MetadataInitializers[i], G->getName());
|
|
|
|
MDNode *MD = MDNode::get(M.getContext(), ValueAsMetadata::get(G));
|
|
|
|
Metadata->setMetadata(LLVMContext::MD_associated, MD);
|
|
|
|
MetadataGlobals[i] = Metadata;
|
|
|
|
|
|
|
|
SetComdatForGlobalMetadata(G, Metadata, UniqueModuleId);
|
|
|
|
}
|
|
|
|
|
2020-06-05 11:18:35 +08:00
|
|
|
// This should never be called when there are no globals, by the logic that
|
|
|
|
// computes the UniqueModuleId string, which is "" when there are no globals.
|
|
|
|
// It's important that this path is only used when there are actually some
|
|
|
|
// globals, because that means that there will certainly be a live
|
|
|
|
// `asan_globals` input section at link time and thus `__start_asan_globals`
|
|
|
|
// and `__stop_asan_globals` symbols will definitely be defined at link time.
|
|
|
|
// This means there's no need for the references to them to be weak, which
|
|
|
|
// enables better code generation because ExternalWeakLinkage implies
|
|
|
|
// isInterposable() and thus requires GOT indirection for PIC. Since these
|
|
|
|
// are known-defined hidden/dso_local symbols, direct PIC accesses without
|
|
|
|
// dynamic relocation are always sufficient.
|
|
|
|
assert(!MetadataGlobals.empty());
|
|
|
|
assert(!UniqueModuleId.empty());
|
|
|
|
|
2017-04-28 04:27:27 +08:00
|
|
|
// Update llvm.compiler.used, adding the new metadata globals. This is
|
|
|
|
// needed so that during LTO these variables stay alive.
|
2020-06-05 11:18:35 +08:00
|
|
|
appendToCompilerUsed(M, MetadataGlobals);
|
2017-04-28 04:27:27 +08:00
|
|
|
|
|
|
|
// RegisteredFlag serves two purposes. First, we can pass it to dladdr()
|
|
|
|
// to look up the loaded image that contains it. Second, we can store in it
|
|
|
|
// whether registration has already occurred, to prevent duplicate
|
|
|
|
// registration.
|
|
|
|
//
|
|
|
|
// Common linkage ensures that there is only one global per shared library.
|
|
|
|
GlobalVariable *RegisteredFlag = new GlobalVariable(
|
|
|
|
M, IntptrTy, false, GlobalVariable::CommonLinkage,
|
|
|
|
ConstantInt::get(IntptrTy, 0), kAsanGlobalsRegisteredFlagName);
|
|
|
|
RegisteredFlag->setVisibility(GlobalVariable::HiddenVisibility);
|
|
|
|
|
2020-06-05 11:18:35 +08:00
|
|
|
// Create start and stop symbols. These are known to be defined by
|
|
|
|
// the linker, see comment above.
|
|
|
|
auto MakeStartStopGV = [&](const char *Prefix) {
|
|
|
|
GlobalVariable *StartStop =
|
|
|
|
new GlobalVariable(M, IntptrTy, false, GlobalVariable::ExternalLinkage,
|
|
|
|
nullptr, Prefix + getGlobalMetadataSection());
|
|
|
|
StartStop->setVisibility(GlobalVariable::HiddenVisibility);
|
|
|
|
assert(StartStop->isImplicitDSOLocal());
|
|
|
|
return StartStop;
|
|
|
|
};
|
|
|
|
GlobalVariable *StartELFMetadata = MakeStartStopGV("__start_");
|
|
|
|
GlobalVariable *StopELFMetadata = MakeStartStopGV("__stop_");
|
2017-04-28 04:27:27 +08:00
|
|
|
|
|
|
|
// Create a call to register the globals with the runtime.
|
|
|
|
IRB.CreateCall(AsanRegisterElfGlobals,
|
|
|
|
{IRB.CreatePointerCast(RegisteredFlag, IntptrTy),
|
|
|
|
IRB.CreatePointerCast(StartELFMetadata, IntptrTy),
|
|
|
|
IRB.CreatePointerCast(StopELFMetadata, IntptrTy)});
|
|
|
|
|
|
|
|
// We also need to unregister globals at the end, e.g., when a shared library
|
|
|
|
// gets closed.
|
2020-02-17 00:46:26 +08:00
|
|
|
IRBuilder<> IRB_Dtor(CreateAsanModuleDtor(M));
|
2017-04-28 04:27:27 +08:00
|
|
|
IRB_Dtor.CreateCall(AsanUnregisterElfGlobals,
|
|
|
|
{IRB.CreatePointerCast(RegisteredFlag, IntptrTy),
|
|
|
|
IRB.CreatePointerCast(StartELFMetadata, IntptrTy),
|
|
|
|
IRB.CreatePointerCast(StopELFMetadata, IntptrTy)});
|
|
|
|
}
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
void ModuleAddressSanitizer::InstrumentGlobalsMachO(
|
2017-01-13 07:03:03 +08:00
|
|
|
IRBuilder<> &IRB, Module &M, ArrayRef<GlobalVariable *> ExtendedGlobals,
|
|
|
|
ArrayRef<Constant *> MetadataInitializers) {
|
|
|
|
assert(ExtendedGlobals.size() == MetadataInitializers.size());
|
|
|
|
|
|
|
|
// On recent Mach-O platforms, use a structure which binds the liveness of
|
|
|
|
// the global variable to the metadata struct. Keep the list of "Liveness" GV
|
|
|
|
// created to be added to llvm.compiler.used
|
2017-05-10 03:31:13 +08:00
|
|
|
StructType *LivenessTy = StructType::get(IntptrTy, IntptrTy);
|
2017-01-13 07:03:03 +08:00
|
|
|
SmallVector<GlobalValue *, 16> LivenessGlobals(ExtendedGlobals.size());
|
|
|
|
|
|
|
|
for (size_t i = 0; i < ExtendedGlobals.size(); i++) {
|
|
|
|
Constant *Initializer = MetadataInitializers[i];
|
|
|
|
GlobalVariable *G = ExtendedGlobals[i];
|
|
|
|
GlobalVariable *Metadata =
|
|
|
|
CreateMetadataGlobal(M, Initializer, G->getName());
|
|
|
|
|
|
|
|
// On recent Mach-O platforms, we emit the global metadata in a way that
|
|
|
|
// allows the linker to properly strip dead globals.
|
2017-05-10 03:31:13 +08:00
|
|
|
auto LivenessBinder =
|
|
|
|
ConstantStruct::get(LivenessTy, Initializer->getAggregateElement(0u),
|
|
|
|
ConstantExpr::getPointerCast(Metadata, IntptrTy));
|
2017-01-13 07:03:03 +08:00
|
|
|
GlobalVariable *Liveness = new GlobalVariable(
|
|
|
|
M, LivenessTy, false, GlobalVariable::InternalLinkage, LivenessBinder,
|
|
|
|
Twine("__asan_binder_") + G->getName());
|
|
|
|
Liveness->setSection("__DATA,__asan_liveness,regular,live_support");
|
|
|
|
LivenessGlobals[i] = Liveness;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update llvm.compiler.used, adding the new liveness globals. This is
|
|
|
|
// needed so that during LTO these variables stay alive. The alternative
|
|
|
|
// would be to have the linker handling the LTO symbols, but libLTO
|
|
|
|
// current API does not expose access to the section for each symbol.
|
|
|
|
if (!LivenessGlobals.empty())
|
|
|
|
appendToCompilerUsed(M, LivenessGlobals);
|
|
|
|
|
|
|
|
// RegisteredFlag serves two purposes. First, we can pass it to dladdr()
|
|
|
|
// to look up the loaded image that contains it. Second, we can store in it
|
|
|
|
// whether registration has already occurred, to prevent duplicate
|
|
|
|
// registration.
|
|
|
|
//
|
|
|
|
// common linkage ensures that there is only one global per shared library.
|
|
|
|
GlobalVariable *RegisteredFlag = new GlobalVariable(
|
|
|
|
M, IntptrTy, false, GlobalVariable::CommonLinkage,
|
|
|
|
ConstantInt::get(IntptrTy, 0), kAsanGlobalsRegisteredFlagName);
|
|
|
|
RegisteredFlag->setVisibility(GlobalVariable::HiddenVisibility);
|
|
|
|
|
|
|
|
IRB.CreateCall(AsanRegisterImageGlobals,
|
|
|
|
{IRB.CreatePointerCast(RegisteredFlag, IntptrTy)});
|
|
|
|
|
|
|
|
// We also need to unregister globals at the end, e.g., when a shared library
|
|
|
|
// gets closed.
|
2020-02-17 00:46:26 +08:00
|
|
|
IRBuilder<> IRB_Dtor(CreateAsanModuleDtor(M));
|
2017-01-13 07:03:03 +08:00
|
|
|
IRB_Dtor.CreateCall(AsanUnregisterImageGlobals,
|
|
|
|
{IRB.CreatePointerCast(RegisteredFlag, IntptrTy)});
|
|
|
|
}
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
void ModuleAddressSanitizer::InstrumentGlobalsWithMetadataArray(
|
2017-01-13 07:03:03 +08:00
|
|
|
IRBuilder<> &IRB, Module &M, ArrayRef<GlobalVariable *> ExtendedGlobals,
|
|
|
|
ArrayRef<Constant *> MetadataInitializers) {
|
|
|
|
assert(ExtendedGlobals.size() == MetadataInitializers.size());
|
|
|
|
unsigned N = ExtendedGlobals.size();
|
|
|
|
assert(N > 0);
|
|
|
|
|
|
|
|
// On platforms that don't have a custom metadata section, we emit an array
|
|
|
|
// of global metadata structures.
|
|
|
|
ArrayType *ArrayOfGlobalStructTy =
|
|
|
|
ArrayType::get(MetadataInitializers[0]->getType(), N);
|
|
|
|
auto AllGlobals = new GlobalVariable(
|
|
|
|
M, ArrayOfGlobalStructTy, false, GlobalVariable::InternalLinkage,
|
|
|
|
ConstantArray::get(ArrayOfGlobalStructTy, MetadataInitializers), "");
|
2017-11-16 20:57:19 +08:00
|
|
|
if (Mapping.Scale > 3)
|
2019-10-15 19:24:36 +08:00
|
|
|
AllGlobals->setAlignment(Align(1ULL << Mapping.Scale));
|
2017-01-13 07:03:03 +08:00
|
|
|
|
|
|
|
IRB.CreateCall(AsanRegisterGlobals,
|
|
|
|
{IRB.CreatePointerCast(AllGlobals, IntptrTy),
|
|
|
|
ConstantInt::get(IntptrTy, N)});
|
|
|
|
|
|
|
|
// We also need to unregister globals at the end, e.g., when a shared library
|
|
|
|
// gets closed.
|
2020-02-17 00:46:26 +08:00
|
|
|
IRBuilder<> IRB_Dtor(CreateAsanModuleDtor(M));
|
2017-01-13 07:03:03 +08:00
|
|
|
IRB_Dtor.CreateCall(AsanUnregisterGlobals,
|
|
|
|
{IRB.CreatePointerCast(AllGlobals, IntptrTy),
|
|
|
|
ConstantInt::get(IntptrTy, N)});
|
|
|
|
}
|
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
// This function replaces all global variables with new variables that have
|
|
|
|
// trailing redzones. It also creates a function that poisons
|
|
|
|
// redzones and inserts this function into llvm.global_ctors.
|
2017-04-28 04:27:23 +08:00
|
|
|
// Sets *CtorComdat to true if the global registration code emitted into the
|
|
|
|
// asan constructor is comdat-compatible.
|
2019-02-14 06:22:48 +08:00
|
|
|
bool ModuleAddressSanitizer::InstrumentGlobals(IRBuilder<> &IRB, Module &M,
|
|
|
|
bool *CtorComdat) {
|
2017-04-28 04:27:23 +08:00
|
|
|
*CtorComdat = false;
|
2012-11-22 11:18:50 +08:00
|
|
|
|
2020-06-10 21:01:40 +08:00
|
|
|
// Build set of globals that are aliased by some GA, where
|
|
|
|
// canInstrumentAliasedGlobal(GA) returns false.
|
2020-06-20 15:42:26 +08:00
|
|
|
SmallPtrSet<const GlobalVariable *, 16> AliasedGlobalExclusions;
|
2020-06-10 21:01:40 +08:00
|
|
|
if (CompileKernel) {
|
|
|
|
for (auto &GA : M.aliases()) {
|
|
|
|
if (const auto *GV = dyn_cast<GlobalVariable>(GA.getAliasee())) {
|
|
|
|
if (!canInstrumentAliasedGlobal(GA))
|
2020-06-20 15:42:26 +08:00
|
|
|
AliasedGlobalExclusions.insert(GV);
|
2020-06-10 21:01:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2020-06-10 21:01:40 +08:00
|
|
|
SmallVector<GlobalVariable *, 16> GlobalsToChange;
|
2014-05-30 02:40:48 +08:00
|
|
|
for (auto &G : M.globals()) {
|
2020-06-20 15:42:26 +08:00
|
|
|
if (!AliasedGlobalExclusions.count(&G) && shouldInstrumentGlobal(&G))
|
2020-06-10 21:01:40 +08:00
|
|
|
GlobalsToChange.push_back(&G);
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t n = GlobalsToChange.size();
|
2017-04-28 04:27:23 +08:00
|
|
|
if (n == 0) {
|
|
|
|
*CtorComdat = true;
|
|
|
|
return false;
|
|
|
|
}
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2016-11-29 09:32:21 +08:00
|
|
|
auto &DL = M.getDataLayout();
|
[asan] Make ASan compatible with linker dead stripping on Windows
Summary:
This is similar to what was done for Darwin in rL264645 /
http://reviews.llvm.org/D16737, but it uses COFF COMDATs to achive the
same result instead of relying on new custom linker features.
As on MachO, this creates one metadata global per instrumented global.
The metadata global is placed in the custom .ASAN$GL section, which the
ASan runtime will iterate over during initialization. There are no other
references to the metadata, so normal linker dead stripping would
discard it. However, the metadata is put in a COMDAT group with the
instrumented global, so that it will be discarded if and only if the
instrumented global is discarded.
I didn't update the ASan ABI version check since this doesn't affect
non-Windows platforms, and the WinASan ABI isn't really stable yet.
Implementing this for ELF will require extending LLVM IR and MC a bit so
that we can use non-COMDAT section groups.
Reviewers: pcc, kcc, mehdi_amini, kubabrecka
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D26770
llvm-svn: 287576
2016-11-22 04:40:37 +08:00
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
// A global is described by a structure
|
|
|
|
// size_t beg;
|
|
|
|
// size_t size;
|
|
|
|
// size_t size_with_redzone;
|
|
|
|
// const char *name;
|
2013-03-18 16:05:29 +08:00
|
|
|
// const char *module_name;
|
2012-08-21 16:24:25 +08:00
|
|
|
// size_t has_dynamic_init;
|
2014-07-03 00:54:41 +08:00
|
|
|
// void *source_location;
|
2016-02-08 16:30:57 +08:00
|
|
|
// size_t odr_indicator;
|
2011-11-16 09:35:23 +08:00
|
|
|
// We initialize an array of such structures and pass it to a run-time call.
|
2014-07-03 00:54:41 +08:00
|
|
|
StructType *GlobalStructTy =
|
|
|
|
StructType::get(IntptrTy, IntptrTy, IntptrTy, IntptrTy, IntptrTy,
|
2017-05-10 03:31:13 +08:00
|
|
|
IntptrTy, IntptrTy, IntptrTy);
|
2017-01-13 07:03:03 +08:00
|
|
|
SmallVector<GlobalVariable *, 16> NewGlobals(n);
|
|
|
|
SmallVector<Constant *, 16> Initializers(n);
|
2012-11-22 11:18:50 +08:00
|
|
|
|
2013-03-26 21:05:41 +08:00
|
|
|
bool HasDynamicallyInitializedGlobals = false;
|
2012-08-21 16:24:25 +08:00
|
|
|
|
2013-03-26 21:05:41 +08:00
|
|
|
// We shouldn't merge same module names, as this string serves as unique
|
|
|
|
// module ID in runtime.
|
2013-12-25 22:22:15 +08:00
|
|
|
GlobalVariable *ModuleName = createPrivateGlobalForString(
|
2018-10-12 07:03:27 +08:00
|
|
|
M, M.getModuleIdentifier(), /*AllowMerging*/ false, kAsanGenPrefix);
|
2013-03-18 16:05:29 +08:00
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
for (size_t i = 0; i < n; i++) {
|
|
|
|
GlobalVariable *G = GlobalsToChange[i];
|
2014-07-12 08:42:52 +08:00
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
// FIXME: Metadata should be attched directly to the global directly instead
|
|
|
|
// of being added to llvm.asan.globals.
|
2014-07-12 08:42:52 +08:00
|
|
|
auto MD = GlobalsMD.get(G);
|
2016-02-08 16:30:57 +08:00
|
|
|
StringRef NameForGlobal = G->getName();
|
2014-08-02 08:35:50 +08:00
|
|
|
// Create string holding the global name (use global name from metadata
|
|
|
|
// if it's available, otherwise just write the name of global variable).
|
|
|
|
GlobalVariable *Name = createPrivateGlobalForString(
|
2016-02-08 16:30:57 +08:00
|
|
|
M, MD.Name.empty() ? NameForGlobal : MD.Name,
|
2018-10-12 07:03:27 +08:00
|
|
|
/*AllowMerging*/ true, kAsanGenPrefix);
|
2014-07-12 08:42:52 +08:00
|
|
|
|
2016-01-17 04:30:46 +08:00
|
|
|
Type *Ty = G->getValueType();
|
2020-06-12 20:58:00 +08:00
|
|
|
const uint64_t SizeInBytes = DL.getTypeAllocSize(Ty);
|
|
|
|
const uint64_t RightRedzoneSize = getRedzoneSizeForGlobal(SizeInBytes);
|
2011-11-16 09:35:23 +08:00
|
|
|
Type *RightRedZoneTy = ArrayType::get(IRB.getInt8Ty(), RightRedzoneSize);
|
|
|
|
|
2017-05-10 03:31:13 +08:00
|
|
|
StructType *NewTy = StructType::get(Ty, RightRedZoneTy);
|
|
|
|
Constant *NewInitializer = ConstantStruct::get(
|
|
|
|
NewTy, G->getInitializer(), Constant::getNullValue(RightRedZoneTy));
|
2011-11-16 09:35:23 +08:00
|
|
|
|
|
|
|
// Create a new global variable with enough space for a redzone.
|
2013-08-07 06:52:42 +08:00
|
|
|
GlobalValue::LinkageTypes Linkage = G->getLinkage();
|
|
|
|
if (G->isConstant() && Linkage == GlobalValue::PrivateLinkage)
|
|
|
|
Linkage = GlobalValue::InternalLinkage;
|
2015-03-04 21:27:53 +08:00
|
|
|
GlobalVariable *NewGlobal =
|
|
|
|
new GlobalVariable(M, NewTy, G->isConstant(), Linkage, NewInitializer,
|
|
|
|
"", G, G->getThreadLocalMode());
|
2011-11-16 09:35:23 +08:00
|
|
|
NewGlobal->copyAttributesFrom(G);
|
2018-08-21 07:35:45 +08:00
|
|
|
NewGlobal->setComdat(G->getComdat());
|
2020-06-12 20:58:00 +08:00
|
|
|
NewGlobal->setAlignment(MaybeAlign(getMinRedzoneSizeForGlobal()));
|
2018-12-20 08:30:18 +08:00
|
|
|
// Don't fold globals with redzones. ODR violation detector and redzone
|
|
|
|
// poisoning implicitly creates a dependence on the global's address, so it
|
|
|
|
// is no longer valid for it to be marked unnamed_addr.
|
|
|
|
NewGlobal->setUnnamedAddr(GlobalValue::UnnamedAddr::None);
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2016-11-01 02:51:58 +08:00
|
|
|
// Move null-terminated C strings to "__asan_cstring" section on Darwin.
|
|
|
|
if (TargetTriple.isOSBinFormatMachO() && !G->hasSection() &&
|
|
|
|
G->isConstant()) {
|
|
|
|
auto Seq = dyn_cast<ConstantDataSequential>(G->getInitializer());
|
|
|
|
if (Seq && Seq->isCString())
|
|
|
|
NewGlobal->setSection("__TEXT,__asan_cstring,regular");
|
|
|
|
}
|
|
|
|
|
2016-09-21 02:28:42 +08:00
|
|
|
// Transfer the debug info. The payload starts at offset zero so we can
|
|
|
|
// copy the debug info over as is.
|
2016-12-20 10:09:43 +08:00
|
|
|
SmallVector<DIGlobalVariableExpression *, 1> GVs;
|
2016-09-21 02:28:42 +08:00
|
|
|
G->getDebugInfo(GVs);
|
|
|
|
for (auto *GV : GVs)
|
|
|
|
NewGlobal->addDebugInfo(GV);
|
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
Value *Indices2[2];
|
|
|
|
Indices2[0] = IRB.getInt32(0);
|
|
|
|
Indices2[1] = IRB.getInt32(0);
|
|
|
|
|
|
|
|
G->replaceAllUsesWith(
|
2015-04-03 02:55:32 +08:00
|
|
|
ConstantExpr::getGetElementPtr(NewTy, NewGlobal, Indices2, true));
|
2011-11-16 09:35:23 +08:00
|
|
|
NewGlobal->takeName(G);
|
|
|
|
G->eraseFromParent();
|
2017-01-13 07:03:03 +08:00
|
|
|
NewGlobals[i] = NewGlobal;
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2014-08-02 08:35:50 +08:00
|
|
|
Constant *SourceLoc;
|
|
|
|
if (!MD.SourceLoc.empty()) {
|
|
|
|
auto SourceLocGlobal = createPrivateGlobalForSourceLoc(M, MD.SourceLoc);
|
|
|
|
SourceLoc = ConstantExpr::getPointerCast(SourceLocGlobal, IntptrTy);
|
|
|
|
} else {
|
|
|
|
SourceLoc = ConstantInt::get(IntptrTy, 0);
|
|
|
|
}
|
|
|
|
|
2016-02-08 16:30:57 +08:00
|
|
|
Constant *ODRIndicator = ConstantExpr::getNullValue(IRB.getInt8PtrTy());
|
|
|
|
GlobalValue *InstrumentedGlobal = NewGlobal;
|
|
|
|
|
2016-09-14 22:06:33 +08:00
|
|
|
bool CanUsePrivateAliases =
|
2017-01-18 04:34:09 +08:00
|
|
|
TargetTriple.isOSBinFormatELF() || TargetTriple.isOSBinFormatMachO() ||
|
|
|
|
TargetTriple.isOSBinFormatWasm();
|
2018-12-05 09:44:31 +08:00
|
|
|
if (CanUsePrivateAliases && UsePrivateAlias) {
|
2016-02-08 16:30:57 +08:00
|
|
|
// Create local alias for NewGlobal to avoid crash on ODR between
|
|
|
|
// instrumented and non-instrumented libraries.
|
2018-12-05 07:17:41 +08:00
|
|
|
InstrumentedGlobal =
|
2018-12-04 08:36:14 +08:00
|
|
|
GlobalAlias::create(GlobalValue::PrivateLinkage, "", NewGlobal);
|
2018-12-05 07:17:41 +08:00
|
|
|
}
|
2016-02-08 16:30:57 +08:00
|
|
|
|
2018-12-20 08:30:27 +08:00
|
|
|
// ODR should not happen for local linkage.
|
|
|
|
if (NewGlobal->hasLocalLinkage()) {
|
2018-12-13 17:47:39 +08:00
|
|
|
ODRIndicator = ConstantExpr::getIntToPtr(ConstantInt::get(IntptrTy, -1),
|
|
|
|
IRB.getInt8PtrTy());
|
|
|
|
} else if (UseOdrIndicator) {
|
2016-02-08 16:30:57 +08:00
|
|
|
// With local aliases, we need to provide another externally visible
|
|
|
|
// symbol __odr_asan_XXX to detect ODR violation.
|
|
|
|
auto *ODRIndicatorSym =
|
|
|
|
new GlobalVariable(M, IRB.getInt8Ty(), false, Linkage,
|
|
|
|
Constant::getNullValue(IRB.getInt8Ty()),
|
|
|
|
kODRGenPrefix + NameForGlobal, nullptr,
|
|
|
|
NewGlobal->getThreadLocalMode());
|
|
|
|
|
|
|
|
// Set meaningful attributes for indicator symbol.
|
|
|
|
ODRIndicatorSym->setVisibility(NewGlobal->getVisibility());
|
|
|
|
ODRIndicatorSym->setDLLStorageClass(NewGlobal->getDLLStorageClass());
|
[Alignment][NFC] Deprecate Align::None()
Summary:
This is a follow up on https://reviews.llvm.org/D71473#inline-647262.
There's a caveat here that `Align(1)` relies on the compiler understanding of `Log2_64` implementation to produce good code. One could use `Align()` as a replacement but I believe it is less clear that the alignment is one in that case.
Reviewers: xbolva00, courbet, bollu
Subscribers: arsenm, dylanmckay, sdardis, nemanjai, jvesely, nhaehnle, hiraditya, kbarton, jrtc27, atanasyan, jsji, Jim, kerbowa, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D73099
2020-01-21 22:00:04 +08:00
|
|
|
ODRIndicatorSym->setAlignment(Align(1));
|
2016-02-08 16:30:57 +08:00
|
|
|
ODRIndicator = ODRIndicatorSym;
|
|
|
|
}
|
|
|
|
|
[asan] Make ASan compatible with linker dead stripping on Windows
Summary:
This is similar to what was done for Darwin in rL264645 /
http://reviews.llvm.org/D16737, but it uses COFF COMDATs to achive the
same result instead of relying on new custom linker features.
As on MachO, this creates one metadata global per instrumented global.
The metadata global is placed in the custom .ASAN$GL section, which the
ASan runtime will iterate over during initialization. There are no other
references to the metadata, so normal linker dead stripping would
discard it. However, the metadata is put in a COMDAT group with the
instrumented global, so that it will be discarded if and only if the
instrumented global is discarded.
I didn't update the ASan ABI version check since this doesn't affect
non-Windows platforms, and the WinASan ABI isn't really stable yet.
Implementing this for ELF will require extending LLVM IR and MC a bit so
that we can use non-COMDAT section groups.
Reviewers: pcc, kcc, mehdi_amini, kubabrecka
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D26770
llvm-svn: 287576
2016-11-22 04:40:37 +08:00
|
|
|
Constant *Initializer = ConstantStruct::get(
|
2016-02-08 16:30:57 +08:00
|
|
|
GlobalStructTy,
|
|
|
|
ConstantExpr::getPointerCast(InstrumentedGlobal, IntptrTy),
|
2011-11-16 09:35:23 +08:00
|
|
|
ConstantInt::get(IntptrTy, SizeInBytes),
|
|
|
|
ConstantInt::get(IntptrTy, SizeInBytes + RightRedzoneSize),
|
|
|
|
ConstantExpr::getPointerCast(Name, IntptrTy),
|
2013-03-18 16:05:29 +08:00
|
|
|
ConstantExpr::getPointerCast(ModuleName, IntptrTy),
|
2016-02-08 16:30:57 +08:00
|
|
|
ConstantInt::get(IntptrTy, MD.IsDynInit), SourceLoc,
|
2017-05-10 03:31:13 +08:00
|
|
|
ConstantExpr::getPointerCast(ODRIndicator, IntptrTy));
|
2012-08-21 16:24:25 +08:00
|
|
|
|
2015-03-04 21:27:53 +08:00
|
|
|
if (ClInitializers && MD.IsDynInit) HasDynamicallyInitializedGlobals = true;
|
2012-08-21 16:24:25 +08:00
|
|
|
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "NEW GLOBAL: " << *NewGlobal << "\n");
|
[asan] Make ASan compatible with linker dead stripping on Windows
Summary:
This is similar to what was done for Darwin in rL264645 /
http://reviews.llvm.org/D16737, but it uses COFF COMDATs to achive the
same result instead of relying on new custom linker features.
As on MachO, this creates one metadata global per instrumented global.
The metadata global is placed in the custom .ASAN$GL section, which the
ASan runtime will iterate over during initialization. There are no other
references to the metadata, so normal linker dead stripping would
discard it. However, the metadata is put in a COMDAT group with the
instrumented global, so that it will be discarded if and only if the
instrumented global is discarded.
I didn't update the ASan ABI version check since this doesn't affect
non-Windows platforms, and the WinASan ABI isn't really stable yet.
Implementing this for ELF will require extending LLVM IR and MC a bit so
that we can use non-COMDAT section groups.
Reviewers: pcc, kcc, mehdi_amini, kubabrecka
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D26770
llvm-svn: 287576
2016-11-22 04:40:37 +08:00
|
|
|
|
2017-01-13 07:03:03 +08:00
|
|
|
Initializers[i] = Initializer;
|
|
|
|
}
|
[asan] Make ASan compatible with linker dead stripping on Windows
Summary:
This is similar to what was done for Darwin in rL264645 /
http://reviews.llvm.org/D16737, but it uses COFF COMDATs to achive the
same result instead of relying on new custom linker features.
As on MachO, this creates one metadata global per instrumented global.
The metadata global is placed in the custom .ASAN$GL section, which the
ASan runtime will iterate over during initialization. There are no other
references to the metadata, so normal linker dead stripping would
discard it. However, the metadata is put in a COMDAT group with the
instrumented global, so that it will be discarded if and only if the
instrumented global is discarded.
I didn't update the ASan ABI version check since this doesn't affect
non-Windows platforms, and the WinASan ABI isn't really stable yet.
Implementing this for ELF will require extending LLVM IR and MC a bit so
that we can use non-COMDAT section groups.
Reviewers: pcc, kcc, mehdi_amini, kubabrecka
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D26770
llvm-svn: 287576
2016-11-22 04:40:37 +08:00
|
|
|
|
2018-03-09 05:02:18 +08:00
|
|
|
// Add instrumented globals to llvm.compiler.used list to avoid LTO from
|
|
|
|
// ConstantMerge'ing them.
|
|
|
|
SmallVector<GlobalValue *, 16> GlobalsToAddToUsedList;
|
|
|
|
for (size_t i = 0; i < n; i++) {
|
|
|
|
GlobalVariable *G = NewGlobals[i];
|
|
|
|
if (G->getName().empty()) continue;
|
|
|
|
GlobalsToAddToUsedList.push_back(G);
|
|
|
|
}
|
|
|
|
appendToCompilerUsed(M, ArrayRef<GlobalValue *>(GlobalsToAddToUsedList));
|
|
|
|
|
2017-04-28 04:27:27 +08:00
|
|
|
std::string ELFUniqueModuleId =
|
|
|
|
(UseGlobalsGC && TargetTriple.isOSBinFormatELF()) ? getUniqueModuleId(&M)
|
|
|
|
: "";
|
|
|
|
|
|
|
|
if (!ELFUniqueModuleId.empty()) {
|
|
|
|
InstrumentGlobalsELF(IRB, M, NewGlobals, Initializers, ELFUniqueModuleId);
|
|
|
|
*CtorComdat = true;
|
|
|
|
} else if (UseGlobalsGC && TargetTriple.isOSBinFormatCOFF()) {
|
2017-01-13 07:03:03 +08:00
|
|
|
InstrumentGlobalsCOFF(IRB, M, NewGlobals, Initializers);
|
2017-04-25 03:34:13 +08:00
|
|
|
} else if (UseGlobalsGC && ShouldUseMachOGlobalsSection()) {
|
2017-01-13 07:03:03 +08:00
|
|
|
InstrumentGlobalsMachO(IRB, M, NewGlobals, Initializers);
|
|
|
|
} else {
|
|
|
|
InstrumentGlobalsWithMetadataArray(IRB, M, NewGlobals, Initializers);
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
[asan] Make ASan compatible with linker dead stripping on Windows
Summary:
This is similar to what was done for Darwin in rL264645 /
http://reviews.llvm.org/D16737, but it uses COFF COMDATs to achive the
same result instead of relying on new custom linker features.
As on MachO, this creates one metadata global per instrumented global.
The metadata global is placed in the custom .ASAN$GL section, which the
ASan runtime will iterate over during initialization. There are no other
references to the metadata, so normal linker dead stripping would
discard it. However, the metadata is put in a COMDAT group with the
instrumented global, so that it will be discarded if and only if the
instrumented global is discarded.
I didn't update the ASan ABI version check since this doesn't affect
non-Windows platforms, and the WinASan ABI isn't really stable yet.
Implementing this for ELF will require extending LLVM IR and MC a bit so
that we can use non-COMDAT section groups.
Reviewers: pcc, kcc, mehdi_amini, kubabrecka
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D26770
llvm-svn: 287576
2016-11-22 04:40:37 +08:00
|
|
|
// Create calls for poisoning before initializers run and unpoisoning after.
|
|
|
|
if (HasDynamicallyInitializedGlobals)
|
|
|
|
createInitializerPoisonCalls(M, ModuleName);
|
|
|
|
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << M);
|
2011-11-16 09:35:23 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-12 20:58:00 +08:00
|
|
|
uint64_t
|
|
|
|
ModuleAddressSanitizer::getRedzoneSizeForGlobal(uint64_t SizeInBytes) const {
|
|
|
|
constexpr uint64_t kMaxRZ = 1 << 18;
|
|
|
|
const uint64_t MinRZ = getMinRedzoneSizeForGlobal();
|
|
|
|
|
|
|
|
// Calculate RZ, where MinRZ <= RZ <= MaxRZ, and RZ ~ 1/4 * SizeInBytes.
|
|
|
|
uint64_t RZ =
|
|
|
|
std::max(MinRZ, std::min(kMaxRZ, (SizeInBytes / MinRZ / 4) * MinRZ));
|
|
|
|
|
|
|
|
// Round up to multiple of MinRZ.
|
|
|
|
if (SizeInBytes % MinRZ)
|
|
|
|
RZ += MinRZ - (SizeInBytes % MinRZ);
|
|
|
|
assert((RZ + SizeInBytes) % MinRZ == 0);
|
|
|
|
|
|
|
|
return RZ;
|
|
|
|
}
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
int ModuleAddressSanitizer::GetAsanVersion(const Module &M) const {
|
2017-11-21 01:41:57 +08:00
|
|
|
int LongSize = M.getDataLayout().getPointerSizeInBits();
|
|
|
|
bool isAndroid = Triple(M.getTargetTriple()).isAndroid();
|
|
|
|
int Version = 8;
|
|
|
|
// 32-bit Android is one version ahead because of the switch to dynamic
|
|
|
|
// shadow.
|
|
|
|
Version += (LongSize == 32 && isAndroid);
|
|
|
|
return Version;
|
|
|
|
}
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
bool ModuleAddressSanitizer::instrumentModule(Module &M) {
|
2014-06-03 22:16:00 +08:00
|
|
|
initializeCallbacks(M);
|
|
|
|
|
2017-04-28 04:27:23 +08:00
|
|
|
// Create a module constructor. A destructor is created lazily because not all
|
|
|
|
// platforms, and not all modules need it.
|
2020-06-10 21:01:40 +08:00
|
|
|
if (CompileKernel) {
|
|
|
|
// The kernel always builds with its own runtime, and therefore does not
|
|
|
|
// need the init and version check calls.
|
|
|
|
AsanCtorFunction = createSanitizerCtor(M, kAsanModuleCtorName);
|
|
|
|
} else {
|
|
|
|
std::string AsanVersion = std::to_string(GetAsanVersion(M));
|
|
|
|
std::string VersionCheckName =
|
|
|
|
ClInsertVersionCheck ? (kAsanVersionCheckNamePrefix + AsanVersion) : "";
|
|
|
|
std::tie(AsanCtorFunction, std::ignore) =
|
|
|
|
createSanitizerCtorAndInitFunctions(M, kAsanModuleCtorName,
|
|
|
|
kAsanInitName, /*InitArgTypes=*/{},
|
|
|
|
/*InitArgs=*/{}, VersionCheckName);
|
|
|
|
}
|
2017-03-28 07:11:50 +08:00
|
|
|
|
2017-04-28 04:27:23 +08:00
|
|
|
bool CtorComdat = true;
|
2017-04-07 03:55:09 +08:00
|
|
|
if (ClGlobals) {
|
|
|
|
IRBuilder<> IRB(AsanCtorFunction->getEntryBlock().getTerminator());
|
2019-10-12 09:50:36 +08:00
|
|
|
InstrumentGlobals(IRB, M, &CtorComdat);
|
2017-04-28 04:27:23 +08:00
|
|
|
}
|
|
|
|
|
[WebAssembly] Lower ASan constructor priority on Emscripten
Summary:
This change gives Emscripten the ability to use more than one constructor
priorities that runs before ASan. By convention, constructor priorites 0-100
are reserved for use by the system. ASan on Emscripten now uses priority 50,
leaving plenty of room for use by Emscripten before and after ASan.
This change is done in response to:
https://github.com/emscripten-core/emscripten/pull/9076#discussion_r310323723
Reviewers: kripken, tlively, aheejin
Reviewed By: tlively
Subscribers: cfe-commits, dschuff, sbc100, jgravelle-google, hiraditya, sunfish, llvm-commits
Tags: #llvm, #clang
Differential Revision: https://reviews.llvm.org/D65684
llvm-svn: 368101
2019-08-07 05:52:58 +08:00
|
|
|
const uint64_t Priority = GetCtorAndDtorPriority(TargetTriple);
|
|
|
|
|
2017-04-28 04:27:23 +08:00
|
|
|
// Put the constructor and destructor in comdat if both
|
|
|
|
// (1) global instrumentation is not TU-specific
|
|
|
|
// (2) target is ELF.
|
2017-05-16 04:43:42 +08:00
|
|
|
if (UseCtorComdat && TargetTriple.isOSBinFormatELF() && CtorComdat) {
|
2017-04-28 04:27:23 +08:00
|
|
|
AsanCtorFunction->setComdat(M.getOrInsertComdat(kAsanModuleCtorName));
|
[WebAssembly] Lower ASan constructor priority on Emscripten
Summary:
This change gives Emscripten the ability to use more than one constructor
priorities that runs before ASan. By convention, constructor priorites 0-100
are reserved for use by the system. ASan on Emscripten now uses priority 50,
leaving plenty of room for use by Emscripten before and after ASan.
This change is done in response to:
https://github.com/emscripten-core/emscripten/pull/9076#discussion_r310323723
Reviewers: kripken, tlively, aheejin
Reviewed By: tlively
Subscribers: cfe-commits, dschuff, sbc100, jgravelle-google, hiraditya, sunfish, llvm-commits
Tags: #llvm, #clang
Differential Revision: https://reviews.llvm.org/D65684
llvm-svn: 368101
2019-08-07 05:52:58 +08:00
|
|
|
appendToGlobalCtors(M, AsanCtorFunction, Priority, AsanCtorFunction);
|
2017-04-28 04:27:23 +08:00
|
|
|
if (AsanDtorFunction) {
|
|
|
|
AsanDtorFunction->setComdat(M.getOrInsertComdat(kAsanModuleDtorName));
|
[WebAssembly] Lower ASan constructor priority on Emscripten
Summary:
This change gives Emscripten the ability to use more than one constructor
priorities that runs before ASan. By convention, constructor priorites 0-100
are reserved for use by the system. ASan on Emscripten now uses priority 50,
leaving plenty of room for use by Emscripten before and after ASan.
This change is done in response to:
https://github.com/emscripten-core/emscripten/pull/9076#discussion_r310323723
Reviewers: kripken, tlively, aheejin
Reviewed By: tlively
Subscribers: cfe-commits, dschuff, sbc100, jgravelle-google, hiraditya, sunfish, llvm-commits
Tags: #llvm, #clang
Differential Revision: https://reviews.llvm.org/D65684
llvm-svn: 368101
2019-08-07 05:52:58 +08:00
|
|
|
appendToGlobalDtors(M, AsanDtorFunction, Priority, AsanDtorFunction);
|
2017-04-28 04:27:23 +08:00
|
|
|
}
|
|
|
|
} else {
|
[WebAssembly] Lower ASan constructor priority on Emscripten
Summary:
This change gives Emscripten the ability to use more than one constructor
priorities that runs before ASan. By convention, constructor priorites 0-100
are reserved for use by the system. ASan on Emscripten now uses priority 50,
leaving plenty of room for use by Emscripten before and after ASan.
This change is done in response to:
https://github.com/emscripten-core/emscripten/pull/9076#discussion_r310323723
Reviewers: kripken, tlively, aheejin
Reviewed By: tlively
Subscribers: cfe-commits, dschuff, sbc100, jgravelle-google, hiraditya, sunfish, llvm-commits
Tags: #llvm, #clang
Differential Revision: https://reviews.llvm.org/D65684
llvm-svn: 368101
2019-08-07 05:52:58 +08:00
|
|
|
appendToGlobalCtors(M, AsanCtorFunction, Priority);
|
2017-04-28 04:27:23 +08:00
|
|
|
if (AsanDtorFunction)
|
[WebAssembly] Lower ASan constructor priority on Emscripten
Summary:
This change gives Emscripten the ability to use more than one constructor
priorities that runs before ASan. By convention, constructor priorites 0-100
are reserved for use by the system. ASan on Emscripten now uses priority 50,
leaving plenty of room for use by Emscripten before and after ASan.
This change is done in response to:
https://github.com/emscripten-core/emscripten/pull/9076#discussion_r310323723
Reviewers: kripken, tlively, aheejin
Reviewed By: tlively
Subscribers: cfe-commits, dschuff, sbc100, jgravelle-google, hiraditya, sunfish, llvm-commits
Tags: #llvm, #clang
Differential Revision: https://reviews.llvm.org/D65684
llvm-svn: 368101
2019-08-07 05:52:58 +08:00
|
|
|
appendToGlobalDtors(M, AsanDtorFunction, Priority);
|
2015-06-19 20:19:07 +08:00
|
|
|
}
|
2014-06-03 22:16:00 +08:00
|
|
|
|
2019-10-12 09:50:36 +08:00
|
|
|
return true;
|
2014-06-03 22:16:00 +08:00
|
|
|
}
|
|
|
|
|
2012-11-29 17:54:21 +08:00
|
|
|
void AddressSanitizer::initializeCallbacks(Module &M) {
|
|
|
|
IRBuilder<> IRB(*C);
|
2012-07-16 22:09:42 +08:00
|
|
|
// Create __asan_report* callbacks.
|
2015-03-18 00:59:19 +08:00
|
|
|
// IsWrite, TypeSize and Exp are encoded in the function name.
|
|
|
|
for (int Exp = 0; Exp < 2; Exp++) {
|
|
|
|
for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
|
|
|
|
const std::string TypeStr = AccessIsWrite ? "store" : "load";
|
|
|
|
const std::string ExpStr = Exp ? "exp_" : "";
|
2015-11-11 18:36:49 +08:00
|
|
|
const std::string EndingStr = Recover ? "_noabort" : "";
|
2017-04-11 23:01:18 +08:00
|
|
|
|
|
|
|
SmallVector<Type *, 3> Args2 = {IntptrTy, IntptrTy};
|
|
|
|
SmallVector<Type *, 2> Args1{1, IntptrTy};
|
|
|
|
if (Exp) {
|
|
|
|
Type *ExpType = Type::getInt32Ty(*C);
|
|
|
|
Args2.push_back(ExpType);
|
|
|
|
Args1.push_back(ExpType);
|
2015-03-18 00:59:19 +08:00
|
|
|
}
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
AsanErrorCallbackSized[AccessIsWrite][Exp] = M.getOrInsertFunction(
|
|
|
|
kAsanReportErrorTemplate + ExpStr + TypeStr + "_n" + EndingStr,
|
|
|
|
FunctionType::get(IRB.getVoidTy(), Args2, false));
|
2017-08-28 14:47:47 +08:00
|
|
|
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
AsanMemoryAccessCallbackSized[AccessIsWrite][Exp] = M.getOrInsertFunction(
|
|
|
|
ClMemoryAccessCallbackPrefix + ExpStr + TypeStr + "N" + EndingStr,
|
|
|
|
FunctionType::get(IRB.getVoidTy(), Args2, false));
|
2017-08-28 14:47:47 +08:00
|
|
|
|
|
|
|
for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
|
|
|
|
AccessSizeIndex++) {
|
|
|
|
const std::string Suffix = TypeStr + itostr(1ULL << AccessSizeIndex);
|
|
|
|
AsanErrorCallback[AccessIsWrite][Exp][AccessSizeIndex] =
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
M.getOrInsertFunction(
|
2017-08-28 14:47:47 +08:00
|
|
|
kAsanReportErrorTemplate + ExpStr + Suffix + EndingStr,
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionType::get(IRB.getVoidTy(), Args1, false));
|
2017-08-28 14:47:47 +08:00
|
|
|
|
|
|
|
AsanMemoryAccessCallback[AccessIsWrite][Exp][AccessSizeIndex] =
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
M.getOrInsertFunction(
|
2017-08-28 14:47:47 +08:00
|
|
|
ClMemoryAccessCallbackPrefix + ExpStr + Suffix + EndingStr,
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionType::get(IRB.getVoidTy(), Args1, false));
|
2017-08-28 14:47:47 +08:00
|
|
|
}
|
|
|
|
}
|
2012-07-16 22:09:42 +08:00
|
|
|
}
|
2014-04-21 15:10:43 +08:00
|
|
|
|
2015-06-19 20:19:07 +08:00
|
|
|
const std::string MemIntrinCallbackPrefix =
|
|
|
|
CompileKernel ? std::string("") : ClMemoryAccessCallbackPrefix;
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
AsanMemmove = M.getOrInsertFunction(MemIntrinCallbackPrefix + "memmove",
|
|
|
|
IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
|
|
|
|
IRB.getInt8PtrTy(), IntptrTy);
|
|
|
|
AsanMemcpy = M.getOrInsertFunction(MemIntrinCallbackPrefix + "memcpy",
|
|
|
|
IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
|
|
|
|
IRB.getInt8PtrTy(), IntptrTy);
|
|
|
|
AsanMemset = M.getOrInsertFunction(MemIntrinCallbackPrefix + "memset",
|
|
|
|
IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
|
|
|
|
IRB.getInt32Ty(), IntptrTy);
|
|
|
|
|
|
|
|
AsanHandleNoReturnFunc =
|
|
|
|
M.getOrInsertFunction(kAsanHandleNoReturnName, IRB.getVoidTy());
|
|
|
|
|
|
|
|
AsanPtrCmpFunction =
|
|
|
|
M.getOrInsertFunction(kAsanPtrCmp, IRB.getVoidTy(), IntptrTy, IntptrTy);
|
|
|
|
AsanPtrSubFunction =
|
|
|
|
M.getOrInsertFunction(kAsanPtrSub, IRB.getVoidTy(), IntptrTy, IntptrTy);
|
2017-11-21 01:41:57 +08:00
|
|
|
if (Mapping.InGlobal)
|
|
|
|
AsanShadowGlobal = M.getOrInsertGlobal("__asan_shadow",
|
|
|
|
ArrayType::get(IRB.getInt8Ty(), 0));
|
2012-11-29 17:54:21 +08:00
|
|
|
}
|
|
|
|
|
2012-01-31 07:50:10 +08:00
|
|
|
bool AddressSanitizer::maybeInsertAsanInitAtFunctionEntry(Function &F) {
|
|
|
|
// For each NSObject descendant having a +load method, this method is invoked
|
|
|
|
// by the ObjC runtime before any of the static constructors is called.
|
|
|
|
// Therefore we need to instrument such methods with a call to __asan_init
|
|
|
|
// at the beginning in order to initialize our runtime before any access to
|
|
|
|
// the shadow memory.
|
|
|
|
// We cannot just ignore these methods, because they may call other
|
|
|
|
// instrumented functions.
|
|
|
|
if (F.getName().find(" load]") != std::string::npos) {
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee AsanInitFunction =
|
2017-04-07 03:55:09 +08:00
|
|
|
declareSanitizerInitFunction(*F.getParent(), kAsanInitName, {});
|
2015-10-14 01:39:10 +08:00
|
|
|
IRBuilder<> IRB(&F.front(), F.front().begin());
|
2015-05-19 06:13:54 +08:00
|
|
|
IRB.CreateCall(AsanInitFunction, {});
|
2012-01-31 07:50:10 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-04 15:13:11 +08:00
|
|
|
bool AddressSanitizer::maybeInsertDynamicShadowAtFunctionEntry(Function &F) {
|
2016-10-01 01:46:32 +08:00
|
|
|
// Generate code only when dynamic addressing is needed.
|
2017-11-15 08:11:51 +08:00
|
|
|
if (Mapping.Offset != kDynamicShadowSentinel)
|
2020-06-04 15:13:11 +08:00
|
|
|
return false;
|
2016-10-01 01:46:32 +08:00
|
|
|
|
|
|
|
IRBuilder<> IRB(&F.front().front());
|
2017-11-21 01:41:57 +08:00
|
|
|
if (Mapping.InGlobal) {
|
|
|
|
if (ClWithIfuncSuppressRemat) {
|
|
|
|
// An empty inline asm with input reg == output reg.
|
|
|
|
// An opaque pointer-to-int cast, basically.
|
|
|
|
InlineAsm *Asm = InlineAsm::get(
|
|
|
|
FunctionType::get(IntptrTy, {AsanShadowGlobal->getType()}, false),
|
|
|
|
StringRef(""), StringRef("=r,0"),
|
|
|
|
/*hasSideEffects=*/false);
|
|
|
|
LocalDynamicShadow =
|
|
|
|
IRB.CreateCall(Asm, {AsanShadowGlobal}, ".asan.shadow");
|
|
|
|
} else {
|
|
|
|
LocalDynamicShadow =
|
|
|
|
IRB.CreatePointerCast(AsanShadowGlobal, IntptrTy, ".asan.shadow");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal(
|
|
|
|
kAsanShadowMemoryDynamicAddress, IntptrTy);
|
2019-02-02 04:44:24 +08:00
|
|
|
LocalDynamicShadow = IRB.CreateLoad(IntptrTy, GlobalDynamicAddress);
|
2017-11-21 01:41:57 +08:00
|
|
|
}
|
2020-06-04 15:13:11 +08:00
|
|
|
return true;
|
2016-10-01 01:46:32 +08:00
|
|
|
}
|
|
|
|
|
2015-07-22 01:40:14 +08:00
|
|
|
void AddressSanitizer::markEscapedLocalAllocas(Function &F) {
|
|
|
|
// Find the one possible call to llvm.localescape and pre-mark allocas passed
|
|
|
|
// to it as uninteresting. This assumes we haven't started processing allocas
|
|
|
|
// yet. This check is done up front because iterating the use list in
|
|
|
|
// isInterestingAlloca would be algorithmically slower.
|
|
|
|
assert(ProcessedAllocas.empty() && "must process localescape before allocas");
|
|
|
|
|
|
|
|
// Try to get the declaration of llvm.localescape. If it's not in the module,
|
|
|
|
// we can exit early.
|
|
|
|
if (!F.getParent()->getFunction("llvm.localescape")) return;
|
|
|
|
|
|
|
|
// Look for a call to llvm.localescape call in the entry block. It can't be in
|
|
|
|
// any other block.
|
|
|
|
for (Instruction &I : F.getEntryBlock()) {
|
|
|
|
IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);
|
|
|
|
if (II && II->getIntrinsicID() == Intrinsic::localescape) {
|
|
|
|
// We found a call. Mark all the allocas passed in as uninteresting.
|
|
|
|
for (Value *Arg : II->arg_operands()) {
|
|
|
|
AllocaInst *AI = dyn_cast<AllocaInst>(Arg->stripPointerCasts());
|
|
|
|
assert(AI && AI->isStaticAlloca() &&
|
|
|
|
"non-static alloca arg to localescape");
|
|
|
|
ProcessedAllocas[AI] = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 17:04:51 +08:00
|
|
|
bool AddressSanitizer::suppressInstrumentationSiteForDebug(int &Instrumented) {
|
|
|
|
bool ShouldInstrument =
|
|
|
|
ClDebugMin < 0 || ClDebugMax < 0 ||
|
|
|
|
(Instrumented >= ClDebugMin && Instrumented <= ClDebugMax);
|
|
|
|
Instrumented++;
|
|
|
|
return !ShouldInstrument;
|
|
|
|
}
|
|
|
|
|
2019-02-14 06:22:48 +08:00
|
|
|
bool AddressSanitizer::instrumentFunction(Function &F,
|
|
|
|
const TargetLibraryInfo *TLI) {
|
2013-03-18 15:33:49 +08:00
|
|
|
if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return false;
|
2016-09-15 01:18:37 +08:00
|
|
|
if (!ClDebugFunc.empty() && ClDebugFunc == F.getName()) return false;
|
2016-09-15 23:35:59 +08:00
|
|
|
if (F.getName().startswith("__asan_")) return false;
|
2014-12-01 16:47:58 +08:00
|
|
|
|
2016-09-15 23:45:05 +08:00
|
|
|
bool FunctionModified = false;
|
|
|
|
|
2013-02-26 14:58:09 +08:00
|
|
|
// If needed, insert __asan_init before checking for SanitizeAddress attr.
|
2016-09-15 01:18:37 +08:00
|
|
|
// This function needs to be called even if the function body is not
|
2018-07-31 03:41:25 +08:00
|
|
|
// instrumented.
|
2016-09-15 23:45:05 +08:00
|
|
|
if (maybeInsertAsanInitAtFunctionEntry(F))
|
|
|
|
FunctionModified = true;
|
2018-07-31 03:41:25 +08:00
|
|
|
|
2016-09-15 01:18:37 +08:00
|
|
|
// Leave if the function doesn't need instrumentation.
|
2016-09-15 23:45:05 +08:00
|
|
|
if (!F.hasFnAttribute(Attribute::SanitizeAddress)) return FunctionModified;
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "ASAN instrumenting:\n" << F << "\n");
|
2016-09-15 01:18:37 +08:00
|
|
|
|
|
|
|
initializeCallbacks(*F.getParent());
|
2012-10-09 15:45:08 +08:00
|
|
|
|
2015-07-22 01:40:14 +08:00
|
|
|
FunctionStateRAII CleanupObj(this);
|
|
|
|
|
2020-06-04 15:13:11 +08:00
|
|
|
FunctionModified |= maybeInsertDynamicShadowAtFunctionEntry(F);
|
2016-10-01 01:46:32 +08:00
|
|
|
|
2015-07-22 01:40:14 +08:00
|
|
|
// We can't instrument allocas used with llvm.localescape. Only static allocas
|
|
|
|
// can be passed to that intrinsic.
|
|
|
|
markEscapedLocalAllocas(F);
|
|
|
|
|
2012-10-09 15:45:08 +08:00
|
|
|
// We want to instrument every address only once per basic block (unless there
|
|
|
|
// are calls between uses).
|
2018-06-12 19:16:56 +08:00
|
|
|
SmallPtrSet<Value *, 16> TempsToInstrument;
|
2020-04-30 17:05:00 +08:00
|
|
|
SmallVector<InterestingMemoryOperand, 16> OperandsToInstrument;
|
2020-04-30 17:04:55 +08:00
|
|
|
SmallVector<MemIntrinsic *, 16> IntrinToInstrument;
|
2015-03-04 21:27:53 +08:00
|
|
|
SmallVector<Instruction *, 8> NoReturnCalls;
|
|
|
|
SmallVector<BasicBlock *, 16> AllBlocks;
|
|
|
|
SmallVector<Instruction *, 16> PointerComparisonsOrSubtracts;
|
2013-06-26 17:18:17 +08:00
|
|
|
int NumAllocas = 0;
|
2011-11-16 09:35:23 +08:00
|
|
|
|
|
|
|
// Fill the set of memory operations to instrument.
|
2014-05-30 02:40:48 +08:00
|
|
|
for (auto &BB : F) {
|
|
|
|
AllBlocks.push_back(&BB);
|
2011-11-16 09:35:23 +08:00
|
|
|
TempsToInstrument.clear();
|
2012-06-28 17:34:41 +08:00
|
|
|
int NumInsnsPerBB = 0;
|
2014-05-30 02:40:48 +08:00
|
|
|
for (auto &Inst : BB) {
|
|
|
|
if (LooksLikeCodeInBug11395(&Inst)) return false;
|
2020-04-30 17:05:00 +08:00
|
|
|
SmallVector<InterestingMemoryOperand, 1> InterestingOperands;
|
|
|
|
getInterestingMemoryOperands(&Inst, InterestingOperands);
|
|
|
|
|
|
|
|
if (!InterestingOperands.empty()) {
|
|
|
|
for (auto &Operand : InterestingOperands) {
|
|
|
|
if (ClOpt && ClOptSameTemp) {
|
|
|
|
Value *Ptr = Operand.getPtr();
|
|
|
|
// If we have a mask, skip instrumentation if we've already
|
|
|
|
// instrumented the full object. But don't add to TempsToInstrument
|
|
|
|
// because we might get another load/store with a different mask.
|
|
|
|
if (Operand.MaybeMask) {
|
|
|
|
if (TempsToInstrument.count(Ptr))
|
|
|
|
continue; // We've seen this (whole) temp in the current BB.
|
|
|
|
} else {
|
|
|
|
if (!TempsToInstrument.insert(Ptr).second)
|
|
|
|
continue; // We've seen this temp in the current BB.
|
|
|
|
}
|
2016-12-15 05:57:04 +08:00
|
|
|
}
|
2020-04-30 17:05:00 +08:00
|
|
|
OperandsToInstrument.push_back(Operand);
|
|
|
|
NumInsnsPerBB++;
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
2019-03-28 18:51:24 +08:00
|
|
|
} else if (((ClInvalidPointerPairs || ClInvalidPointerCmp) &&
|
|
|
|
isInterestingPointerComparison(&Inst)) ||
|
|
|
|
((ClInvalidPointerPairs || ClInvalidPointerSub) &&
|
|
|
|
isInterestingPointerSubtraction(&Inst))) {
|
2014-05-30 02:40:48 +08:00
|
|
|
PointerComparisonsOrSubtracts.push_back(&Inst);
|
2020-04-30 17:04:55 +08:00
|
|
|
} else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(&Inst)) {
|
2011-11-16 09:35:23 +08:00
|
|
|
// ok, take it.
|
2020-04-30 17:04:55 +08:00
|
|
|
IntrinToInstrument.push_back(MI);
|
|
|
|
NumInsnsPerBB++;
|
2011-11-16 09:35:23 +08:00
|
|
|
} else {
|
2015-03-04 21:27:53 +08:00
|
|
|
if (isa<AllocaInst>(Inst)) NumAllocas++;
|
2020-04-21 12:34:35 +08:00
|
|
|
if (auto *CB = dyn_cast<CallBase>(&Inst)) {
|
2011-11-16 09:35:23 +08:00
|
|
|
// A call inside BB.
|
|
|
|
TempsToInstrument.clear();
|
2020-04-21 12:34:35 +08:00
|
|
|
if (CB->doesNotReturn() && !CB->hasMetadata("nosanitize"))
|
|
|
|
NoReturnCalls.push_back(CB);
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
2016-06-18 18:10:37 +08:00
|
|
|
if (CallInst *CI = dyn_cast<CallInst>(&Inst))
|
|
|
|
maybeMarkSanitizerLibraryCallNoBuiltin(CI, TLI);
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
2015-03-04 21:27:53 +08:00
|
|
|
if (NumInsnsPerBB >= ClMaxInsnsToInstrumentPerBB) break;
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 17:04:55 +08:00
|
|
|
bool UseCalls = (ClInstrumentationWithCallsThreshold >= 0 &&
|
2020-04-30 17:05:00 +08:00
|
|
|
OperandsToInstrument.size() + IntrinToInstrument.size() >
|
2020-04-30 17:04:55 +08:00
|
|
|
(unsigned)ClInstrumentationWithCallsThreshold);
|
2015-03-10 10:37:25 +08:00
|
|
|
const DataLayout &DL = F.getParent()->getDataLayout();
|
2017-03-22 04:08:59 +08:00
|
|
|
ObjectSizeOpts ObjSizeOpts;
|
|
|
|
ObjSizeOpts.RoundToAlign = true;
|
|
|
|
ObjectSizeOffsetVisitor ObjSizeVis(DL, TLI, F.getContext(), ObjSizeOpts);
|
2015-03-04 21:27:53 +08:00
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
// Instrument.
|
|
|
|
int NumInstrumented = 0;
|
2020-04-30 17:05:00 +08:00
|
|
|
for (auto &Operand : OperandsToInstrument) {
|
|
|
|
if (!suppressInstrumentationSiteForDebug(NumInstrumented))
|
|
|
|
instrumentMop(ObjSizeVis, Operand, UseCalls,
|
|
|
|
F.getParent()->getDataLayout());
|
|
|
|
FunctionModified = true;
|
2020-04-30 17:04:55 +08:00
|
|
|
}
|
|
|
|
for (auto Inst : IntrinToInstrument) {
|
|
|
|
if (!suppressInstrumentationSiteForDebug(NumInstrumented))
|
|
|
|
instrumentMemIntrinsic(Inst);
|
2020-04-30 17:04:51 +08:00
|
|
|
FunctionModified = true;
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
2012-12-25 20:04:36 +08:00
|
|
|
FunctionStackPoisoner FSP(F, *this);
|
|
|
|
bool ChangedStack = FSP.runOnFunction();
|
2012-02-09 05:36:17 +08:00
|
|
|
|
2019-02-02 10:05:16 +08:00
|
|
|
// We must unpoison the stack before NoReturn calls (throw, _exit, etc).
|
2017-11-14 07:47:58 +08:00
|
|
|
// See e.g. https://github.com/google/sanitizers/issues/37
|
2014-05-30 02:40:48 +08:00
|
|
|
for (auto CI : NoReturnCalls) {
|
2012-02-09 05:36:17 +08:00
|
|
|
IRBuilder<> IRB(CI);
|
2015-05-19 06:13:54 +08:00
|
|
|
IRB.CreateCall(AsanHandleNoReturnFunc, {});
|
2012-02-09 05:36:17 +08:00
|
|
|
}
|
|
|
|
|
2014-05-30 02:40:48 +08:00
|
|
|
for (auto Inst : PointerComparisonsOrSubtracts) {
|
|
|
|
instrumentPointerComparisonOrSubtraction(Inst);
|
2020-04-30 17:04:51 +08:00
|
|
|
FunctionModified = true;
|
2014-02-27 20:45:36 +08:00
|
|
|
}
|
|
|
|
|
2020-04-30 17:04:51 +08:00
|
|
|
if (ChangedStack || !NoReturnCalls.empty())
|
2016-09-15 23:45:05 +08:00
|
|
|
FunctionModified = true;
|
2013-11-15 15:16:09 +08:00
|
|
|
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "ASAN done instrumenting: " << FunctionModified << " "
|
|
|
|
<< F << "\n");
|
2013-06-26 17:18:17 +08:00
|
|
|
|
2016-09-15 23:45:05 +08:00
|
|
|
return FunctionModified;
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
2012-12-25 20:04:36 +08:00
|
|
|
// Workaround for bug 11395: we don't want to instrument stack in functions
|
|
|
|
// with large assembly blobs (32-bit only), otherwise reg alloc may crash.
|
|
|
|
// FIXME: remove once the bug 11395 is fixed.
|
|
|
|
bool AddressSanitizer::LooksLikeCodeInBug11395(Instruction *I) {
|
|
|
|
if (LongSize != 32) return false;
|
|
|
|
CallInst *CI = dyn_cast<CallInst>(I);
|
|
|
|
if (!CI || !CI->isInlineAsm()) return false;
|
|
|
|
if (CI->getNumArgOperands() <= 5) return false;
|
|
|
|
// We have inline assembly with quite a few arguments.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionStackPoisoner::initializeCallbacks(Module &M) {
|
|
|
|
IRBuilder<> IRB(*C);
|
2013-09-10 21:16:56 +08:00
|
|
|
for (int i = 0; i <= kMaxAsanStackMallocSizeClass; i++) {
|
|
|
|
std::string Suffix = itostr(i);
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
AsanStackMallocFunc[i] = M.getOrInsertFunction(
|
|
|
|
kAsanStackMallocNameTemplate + Suffix, IntptrTy, IntptrTy);
|
|
|
|
AsanStackFreeFunc[i] =
|
2014-12-12 05:53:03 +08:00
|
|
|
M.getOrInsertFunction(kAsanStackFreeNameTemplate + Suffix,
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
IRB.getVoidTy(), IntptrTy, IntptrTy);
|
2013-09-10 21:16:56 +08:00
|
|
|
}
|
2016-06-10 07:05:35 +08:00
|
|
|
if (ASan.UseAfterScope) {
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
AsanPoisonStackMemoryFunc = M.getOrInsertFunction(
|
|
|
|
kAsanPoisonStackMemoryName, IRB.getVoidTy(), IntptrTy, IntptrTy);
|
|
|
|
AsanUnpoisonStackMemoryFunc = M.getOrInsertFunction(
|
|
|
|
kAsanUnpoisonStackMemoryName, IRB.getVoidTy(), IntptrTy, IntptrTy);
|
2016-06-10 07:05:35 +08:00
|
|
|
}
|
|
|
|
|
2016-10-19 02:04:59 +08:00
|
|
|
for (size_t Val : {0x00, 0xf1, 0xf2, 0xf3, 0xf5, 0xf8}) {
|
|
|
|
std::ostringstream Name;
|
|
|
|
Name << kAsanSetShadowPrefix;
|
|
|
|
Name << std::setw(2) << std::setfill('0') << std::hex << Val;
|
2017-04-07 04:23:57 +08:00
|
|
|
AsanSetShadowFunc[Val] =
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
M.getOrInsertFunction(Name.str(), IRB.getVoidTy(), IntptrTy, IntptrTy);
|
2016-08-21 02:34:39 +08:00
|
|
|
}
|
|
|
|
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
AsanAllocaPoisonFunc = M.getOrInsertFunction(
|
|
|
|
kAsanAllocaPoison, IRB.getVoidTy(), IntptrTy, IntptrTy);
|
|
|
|
AsanAllocasUnpoisonFunc = M.getOrInsertFunction(
|
|
|
|
kAsanAllocasUnpoison, IRB.getVoidTy(), IntptrTy, IntptrTy);
|
2012-12-25 20:04:36 +08:00
|
|
|
}
|
|
|
|
|
2016-08-30 02:17:21 +08:00
|
|
|
void FunctionStackPoisoner::copyToShadowInline(ArrayRef<uint8_t> ShadowMask,
|
|
|
|
ArrayRef<uint8_t> ShadowBytes,
|
|
|
|
size_t Begin, size_t End,
|
|
|
|
IRBuilder<> &IRB,
|
|
|
|
Value *ShadowBase) {
|
2016-08-21 04:23:50 +08:00
|
|
|
if (Begin >= End)
|
|
|
|
return;
|
2016-08-21 02:34:36 +08:00
|
|
|
|
|
|
|
const size_t LargestStoreSizeInBytes =
|
|
|
|
std::min<size_t>(sizeof(uint64_t), ASan.LongSize / 8);
|
|
|
|
|
|
|
|
const bool IsLittleEndian = F.getParent()->getDataLayout().isLittleEndian();
|
|
|
|
|
|
|
|
// Poison given range in shadow using larges store size with out leading and
|
2016-08-30 02:17:21 +08:00
|
|
|
// trailing zeros in ShadowMask. Zeros never change, so they need neither
|
|
|
|
// poisoning nor up-poisoning. Still we don't mind if some of them get into a
|
|
|
|
// middle of a store.
|
2016-08-21 04:23:50 +08:00
|
|
|
for (size_t i = Begin; i < End;) {
|
2016-08-30 02:17:21 +08:00
|
|
|
if (!ShadowMask[i]) {
|
|
|
|
assert(!ShadowBytes[i]);
|
2016-08-21 02:34:36 +08:00
|
|
|
++i;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t StoreSizeInBytes = LargestStoreSizeInBytes;
|
|
|
|
// Fit store size into the range.
|
|
|
|
while (StoreSizeInBytes > End - i)
|
|
|
|
StoreSizeInBytes /= 2;
|
|
|
|
|
|
|
|
// Minimize store size by trimming trailing zeros.
|
2016-08-30 02:17:21 +08:00
|
|
|
for (size_t j = StoreSizeInBytes - 1; j && !ShadowMask[i + j]; --j) {
|
2016-08-21 02:34:36 +08:00
|
|
|
while (j <= StoreSizeInBytes / 2)
|
|
|
|
StoreSizeInBytes /= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t Val = 0;
|
2016-08-30 02:17:21 +08:00
|
|
|
for (size_t j = 0; j < StoreSizeInBytes; j++) {
|
|
|
|
if (IsLittleEndian)
|
|
|
|
Val |= (uint64_t)ShadowBytes[i + j] << (8 * j);
|
|
|
|
else
|
|
|
|
Val = (Val << 8) | ShadowBytes[i + j];
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
2016-08-21 02:34:36 +08:00
|
|
|
|
|
|
|
Value *Ptr = IRB.CreateAdd(ShadowBase, ConstantInt::get(IntptrTy, i));
|
|
|
|
Value *Poison = IRB.getIntN(StoreSizeInBytes * 8, Val);
|
2016-08-22 12:16:14 +08:00
|
|
|
IRB.CreateAlignedStore(
|
2020-01-23 23:18:34 +08:00
|
|
|
Poison, IRB.CreateIntToPtr(Ptr, Poison->getType()->getPointerTo()),
|
|
|
|
Align(1));
|
2016-08-21 02:34:36 +08:00
|
|
|
|
|
|
|
i += StoreSizeInBytes;
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-30 02:17:21 +08:00
|
|
|
void FunctionStackPoisoner::copyToShadow(ArrayRef<uint8_t> ShadowMask,
|
|
|
|
ArrayRef<uint8_t> ShadowBytes,
|
|
|
|
IRBuilder<> &IRB, Value *ShadowBase) {
|
|
|
|
copyToShadow(ShadowMask, ShadowBytes, 0, ShadowMask.size(), IRB, ShadowBase);
|
|
|
|
}
|
2016-08-21 04:23:50 +08:00
|
|
|
|
2016-08-30 02:17:21 +08:00
|
|
|
void FunctionStackPoisoner::copyToShadow(ArrayRef<uint8_t> ShadowMask,
|
|
|
|
ArrayRef<uint8_t> ShadowBytes,
|
|
|
|
size_t Begin, size_t End,
|
|
|
|
IRBuilder<> &IRB, Value *ShadowBase) {
|
|
|
|
assert(ShadowMask.size() == ShadowBytes.size());
|
|
|
|
size_t Done = Begin;
|
|
|
|
for (size_t i = Begin, j = Begin + 1; i < End; i = j++) {
|
|
|
|
if (!ShadowMask[i]) {
|
|
|
|
assert(!ShadowBytes[i]);
|
2016-08-21 04:23:50 +08:00
|
|
|
continue;
|
2016-08-30 02:17:21 +08:00
|
|
|
}
|
|
|
|
uint8_t Val = ShadowBytes[i];
|
2016-08-21 04:23:50 +08:00
|
|
|
if (!AsanSetShadowFunc[Val])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Skip same values.
|
2016-08-30 02:17:21 +08:00
|
|
|
for (; j < End && ShadowMask[j] && Val == ShadowBytes[j]; ++j) {
|
2016-08-21 04:23:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (j - i >= ClMaxInlinePoisoningSize) {
|
2016-08-30 02:17:21 +08:00
|
|
|
copyToShadowInline(ShadowMask, ShadowBytes, Done, i, IRB, ShadowBase);
|
2016-08-21 04:23:50 +08:00
|
|
|
IRB.CreateCall(AsanSetShadowFunc[Val],
|
|
|
|
{IRB.CreateAdd(ShadowBase, ConstantInt::get(IntptrTy, i)),
|
|
|
|
ConstantInt::get(IntptrTy, j - i)});
|
|
|
|
Done = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-30 02:17:21 +08:00
|
|
|
copyToShadowInline(ShadowMask, ShadowBytes, Done, End, IRB, ShadowBase);
|
2016-08-21 04:23:50 +08:00
|
|
|
}
|
|
|
|
|
2013-09-10 21:16:56 +08:00
|
|
|
// Fake stack allocator (asan_fake_stack.h) has 11 size classes
|
|
|
|
// for every power of 2 from kMinStackMallocSize to kMaxAsanStackMallocSizeClass
|
|
|
|
static int StackMallocSizeClass(uint64_t LocalStackSize) {
|
|
|
|
assert(LocalStackSize <= kMaxStackMallocSize);
|
|
|
|
uint64_t MaxSize = kMinStackMallocSize;
|
2015-03-04 21:27:53 +08:00
|
|
|
for (int i = 0;; i++, MaxSize *= 2)
|
|
|
|
if (LocalStackSize <= MaxSize) return i;
|
2013-09-10 21:16:56 +08:00
|
|
|
llvm_unreachable("impossible LocalStackSize");
|
|
|
|
}
|
|
|
|
|
2017-07-19 06:28:03 +08:00
|
|
|
void FunctionStackPoisoner::copyArgsPassedByValToAllocas() {
|
2017-08-10 01:59:43 +08:00
|
|
|
Instruction *CopyInsertPoint = &F.front().front();
|
|
|
|
if (CopyInsertPoint == ASan.LocalDynamicShadow) {
|
|
|
|
// Insert after the dynamic shadow location is determined
|
|
|
|
CopyInsertPoint = CopyInsertPoint->getNextNode();
|
|
|
|
assert(CopyInsertPoint);
|
|
|
|
}
|
|
|
|
IRBuilder<> IRB(CopyInsertPoint);
|
2017-07-19 06:28:03 +08:00
|
|
|
const DataLayout &DL = F.getParent()->getDataLayout();
|
|
|
|
for (Argument &Arg : F.args()) {
|
|
|
|
if (Arg.hasByValAttr()) {
|
2020-05-19 03:50:15 +08:00
|
|
|
Type *Ty = Arg.getParamByValType();
|
2019-12-16 22:24:13 +08:00
|
|
|
const Align Alignment =
|
|
|
|
DL.getValueOrABITypeAlignment(Arg.getParamAlign(), Ty);
|
2017-07-19 06:28:03 +08:00
|
|
|
|
2017-12-29 00:58:54 +08:00
|
|
|
AllocaInst *AI = IRB.CreateAlloca(
|
|
|
|
Ty, nullptr,
|
|
|
|
(Arg.hasName() ? Arg.getName() : "Arg" + Twine(Arg.getArgNo())) +
|
|
|
|
".byval");
|
2019-12-16 22:24:13 +08:00
|
|
|
AI->setAlignment(Alignment);
|
2017-07-19 06:28:03 +08:00
|
|
|
Arg.replaceAllUsesWith(AI);
|
|
|
|
|
|
|
|
uint64_t AllocSize = DL.getTypeAllocSize(Ty);
|
2019-09-30 21:34:44 +08:00
|
|
|
IRB.CreateMemCpy(AI, Alignment, &Arg, Alignment, AllocSize);
|
2017-07-19 06:28:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 05:53:03 +08:00
|
|
|
PHINode *FunctionStackPoisoner::createPHI(IRBuilder<> &IRB, Value *Cond,
|
|
|
|
Value *ValueIfTrue,
|
|
|
|
Instruction *ThenTerm,
|
|
|
|
Value *ValueIfFalse) {
|
|
|
|
PHINode *PHI = IRB.CreatePHI(IntptrTy, 2);
|
|
|
|
BasicBlock *CondBlock = cast<Instruction>(Cond)->getParent();
|
|
|
|
PHI->addIncoming(ValueIfFalse, CondBlock);
|
|
|
|
BasicBlock *ThenBlock = ThenTerm->getParent();
|
|
|
|
PHI->addIncoming(ValueIfTrue, ThenBlock);
|
|
|
|
return PHI;
|
|
|
|
}
|
|
|
|
|
|
|
|
Value *FunctionStackPoisoner::createAllocaForLayout(
|
|
|
|
IRBuilder<> &IRB, const ASanStackFrameLayout &L, bool Dynamic) {
|
|
|
|
AllocaInst *Alloca;
|
|
|
|
if (Dynamic) {
|
|
|
|
Alloca = IRB.CreateAlloca(IRB.getInt8Ty(),
|
|
|
|
ConstantInt::get(IRB.getInt64Ty(), L.FrameSize),
|
|
|
|
"MyAlloca");
|
|
|
|
} else {
|
|
|
|
Alloca = IRB.CreateAlloca(ArrayType::get(IRB.getInt8Ty(), L.FrameSize),
|
|
|
|
nullptr, "MyAlloca");
|
|
|
|
assert(Alloca->isStaticAlloca());
|
|
|
|
}
|
|
|
|
assert((ClRealignStack & (ClRealignStack - 1)) == 0);
|
|
|
|
size_t FrameAlignment = std::max(L.FrameAlignment, (size_t)ClRealignStack);
|
2020-05-16 04:23:14 +08:00
|
|
|
Alloca->setAlignment(Align(FrameAlignment));
|
2014-12-12 05:53:03 +08:00
|
|
|
return IRB.CreatePointerCast(Alloca, IntptrTy);
|
|
|
|
}
|
|
|
|
|
2015-05-28 15:51:49 +08:00
|
|
|
void FunctionStackPoisoner::createDynamicAllocasInitStorage() {
|
|
|
|
BasicBlock &FirstBB = *F.begin();
|
|
|
|
IRBuilder<> IRB(dyn_cast<Instruction>(FirstBB.begin()));
|
|
|
|
DynamicAllocaLayout = IRB.CreateAlloca(IntptrTy, nullptr);
|
|
|
|
IRB.CreateStore(Constant::getNullValue(IntptrTy), DynamicAllocaLayout);
|
2019-09-30 21:34:44 +08:00
|
|
|
DynamicAllocaLayout->setAlignment(Align(32));
|
2015-05-28 15:51:49 +08:00
|
|
|
}
|
|
|
|
|
2016-08-21 01:22:27 +08:00
|
|
|
void FunctionStackPoisoner::processDynamicAllocas() {
|
|
|
|
if (!ClInstrumentDynamicAllocas || DynamicAllocaVec.empty()) {
|
|
|
|
assert(DynamicAllocaPoisonCallVec.empty());
|
|
|
|
return;
|
|
|
|
}
|
2014-11-21 18:29:50 +08:00
|
|
|
|
2016-08-21 01:22:27 +08:00
|
|
|
// Insert poison calls for lifetime intrinsics for dynamic allocas.
|
|
|
|
for (const auto &APC : DynamicAllocaPoisonCallVec) {
|
2015-10-23 03:51:59 +08:00
|
|
|
assert(APC.InsBefore);
|
|
|
|
assert(APC.AI);
|
2016-06-10 07:31:59 +08:00
|
|
|
assert(ASan.isInterestingAlloca(*APC.AI));
|
2016-08-21 01:22:27 +08:00
|
|
|
assert(!APC.AI->isStaticAlloca());
|
2016-06-10 07:31:59 +08:00
|
|
|
|
2015-10-23 03:51:59 +08:00
|
|
|
IRBuilder<> IRB(APC.InsBefore);
|
|
|
|
poisonAlloca(APC.AI, APC.Size, IRB, APC.DoPoison);
|
2016-06-10 07:31:59 +08:00
|
|
|
// Dynamic allocas will be unpoisoned unconditionally below in
|
|
|
|
// unpoisonDynamicAllocas.
|
|
|
|
// Flag that we need unpoison static allocas.
|
2015-10-23 03:51:59 +08:00
|
|
|
}
|
|
|
|
|
2016-08-21 01:22:27 +08:00
|
|
|
// Handle dynamic allocas.
|
|
|
|
createDynamicAllocasInitStorage();
|
|
|
|
for (auto &AI : DynamicAllocaVec)
|
|
|
|
handleDynamicAllocaCall(AI);
|
|
|
|
unpoisonDynamicAllocas();
|
|
|
|
}
|
2015-05-28 15:51:49 +08:00
|
|
|
|
[AddressSanitizer] Fix for wrong argument values appearing in backtraces
Summary:
In some cases, ASan may insert instrumentation before function arguments
have been stored into their allocas. This causes two issues:
1) The argument value must be spilled until it can be stored into the
reserved alloca, wasting a stack slot.
2) Until the store occurs in a later basic block, the debug location
will point to the wrong frame offset, and backtraces will show an
uninitialized value.
The proposed solution is to move instructions which initialize allocas
for arguments up into the entry block, before the position where ASan
starts inserting its instrumentation.
For the motivating test case, before the patch we see:
```
| 0033: movq %rdi, 0x68(%rbx) | | DW_TAG_formal_parameter |
| ... | | DW_AT_name ("a") |
| 00d1: movq 0x68(%rbx), %rsi | | DW_AT_location (RBX+0x90) |
| 00d5: movq %rsi, 0x90(%rbx) | | ^ not correct ... |
```
and after the patch we see:
```
| 002f: movq %rdi, 0x70(%rbx) | | DW_TAG_formal_parameter |
| | | DW_AT_name ("a") |
| | | DW_AT_location (RBX+0x70) |
```
rdar://61122691
Reviewers: aprantl, eugenis
Subscribers: hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77182
2020-04-01 06:27:06 +08:00
|
|
|
/// Collect instructions in the entry block after \p InsBefore which initialize
|
|
|
|
/// permanent storage for a function argument. These instructions must remain in
|
|
|
|
/// the entry block so that uninitialized values do not appear in backtraces. An
|
|
|
|
/// added benefit is that this conserves spill slots. This does not move stores
|
|
|
|
/// before instrumented / "interesting" allocas.
|
|
|
|
static void findStoresToUninstrumentedArgAllocas(
|
|
|
|
AddressSanitizer &ASan, Instruction &InsBefore,
|
|
|
|
SmallVectorImpl<Instruction *> &InitInsts) {
|
|
|
|
Instruction *Start = InsBefore.getNextNonDebugInstruction();
|
|
|
|
for (Instruction *It = Start; It; It = It->getNextNonDebugInstruction()) {
|
|
|
|
// Argument initialization looks like:
|
|
|
|
// 1) store <Argument>, <Alloca> OR
|
|
|
|
// 2) <CastArgument> = cast <Argument> to ...
|
|
|
|
// store <CastArgument> to <Alloca>
|
|
|
|
// Do not consider any other kind of instruction.
|
|
|
|
//
|
|
|
|
// Note: This covers all known cases, but may not be exhaustive. An
|
|
|
|
// alternative to pattern-matching stores is to DFS over all Argument uses:
|
|
|
|
// this might be more general, but is probably much more complicated.
|
|
|
|
if (isa<AllocaInst>(It) || isa<CastInst>(It))
|
|
|
|
continue;
|
|
|
|
if (auto *Store = dyn_cast<StoreInst>(It)) {
|
|
|
|
// The store destination must be an alloca that isn't interesting for
|
|
|
|
// ASan to instrument. These are moved up before InsBefore, and they're
|
|
|
|
// not interesting because allocas for arguments can be mem2reg'd.
|
|
|
|
auto *Alloca = dyn_cast<AllocaInst>(Store->getPointerOperand());
|
|
|
|
if (!Alloca || ASan.isInterestingAlloca(*Alloca))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Value *Val = Store->getValueOperand();
|
|
|
|
bool IsDirectArgInit = isa<Argument>(Val);
|
|
|
|
bool IsArgInitViaCast =
|
|
|
|
isa<CastInst>(Val) &&
|
|
|
|
isa<Argument>(cast<CastInst>(Val)->getOperand(0)) &&
|
|
|
|
// Check that the cast appears directly before the store. Otherwise
|
|
|
|
// moving the cast before InsBefore may break the IR.
|
|
|
|
Val == It->getPrevNonDebugInstruction();
|
|
|
|
bool IsArgInit = IsDirectArgInit || IsArgInitViaCast;
|
|
|
|
if (!IsArgInit)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (IsArgInitViaCast)
|
|
|
|
InitInsts.push_back(cast<Instruction>(Val));
|
|
|
|
InitInsts.push_back(Store);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do not reorder past unknown instructions: argument initialization should
|
|
|
|
// only involve casts and stores.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-21 01:22:27 +08:00
|
|
|
void FunctionStackPoisoner::processStaticAllocas() {
|
|
|
|
if (AllocaVec.empty()) {
|
|
|
|
assert(StaticAllocaPoisonCallVec.empty());
|
|
|
|
return;
|
2015-02-24 17:47:05 +08:00
|
|
|
}
|
2014-11-21 18:29:50 +08:00
|
|
|
|
2013-09-10 21:16:56 +08:00
|
|
|
int StackMallocIdx = -1;
|
2015-06-26 08:00:47 +08:00
|
|
|
DebugLoc EntryDebugLocation;
|
2016-03-11 10:14:16 +08:00
|
|
|
if (auto SP = F.getSubprogram())
|
2015-06-26 08:00:47 +08:00
|
|
|
EntryDebugLocation = DebugLoc::get(SP->getScopeLine(), 0, SP);
|
2011-11-16 09:35:23 +08:00
|
|
|
|
|
|
|
Instruction *InsBefore = AllocaVec[0];
|
|
|
|
IRBuilder<> IRB(InsBefore);
|
|
|
|
|
2015-07-22 18:25:38 +08:00
|
|
|
// Make sure non-instrumented allocas stay in the entry block. Otherwise,
|
|
|
|
// debug info is broken, because only entry-block allocas are treated as
|
|
|
|
// regular stack slots.
|
|
|
|
auto InsBeforeB = InsBefore->getParent();
|
|
|
|
assert(InsBeforeB == &F.getEntryBlock());
|
2016-11-09 05:30:41 +08:00
|
|
|
for (auto *AI : StaticAllocasToMoveUp)
|
|
|
|
if (AI->getParent() == InsBeforeB)
|
|
|
|
AI->moveBefore(InsBefore);
|
2015-07-17 14:29:57 +08:00
|
|
|
|
[AddressSanitizer] Fix for wrong argument values appearing in backtraces
Summary:
In some cases, ASan may insert instrumentation before function arguments
have been stored into their allocas. This causes two issues:
1) The argument value must be spilled until it can be stored into the
reserved alloca, wasting a stack slot.
2) Until the store occurs in a later basic block, the debug location
will point to the wrong frame offset, and backtraces will show an
uninitialized value.
The proposed solution is to move instructions which initialize allocas
for arguments up into the entry block, before the position where ASan
starts inserting its instrumentation.
For the motivating test case, before the patch we see:
```
| 0033: movq %rdi, 0x68(%rbx) | | DW_TAG_formal_parameter |
| ... | | DW_AT_name ("a") |
| 00d1: movq 0x68(%rbx), %rsi | | DW_AT_location (RBX+0x90) |
| 00d5: movq %rsi, 0x90(%rbx) | | ^ not correct ... |
```
and after the patch we see:
```
| 002f: movq %rdi, 0x70(%rbx) | | DW_TAG_formal_parameter |
| | | DW_AT_name ("a") |
| | | DW_AT_location (RBX+0x70) |
```
rdar://61122691
Reviewers: aprantl, eugenis
Subscribers: hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77182
2020-04-01 06:27:06 +08:00
|
|
|
// Move stores of arguments into entry-block allocas as well. This prevents
|
|
|
|
// extra stack slots from being generated (to house the argument values until
|
|
|
|
// they can be stored into the allocas). This also prevents uninitialized
|
|
|
|
// values from being shown in backtraces.
|
|
|
|
SmallVector<Instruction *, 8> ArgInitInsts;
|
|
|
|
findStoresToUninstrumentedArgAllocas(ASan, *InsBefore, ArgInitInsts);
|
|
|
|
for (Instruction *ArgInitInst : ArgInitInsts)
|
|
|
|
ArgInitInst->moveBefore(InsBefore);
|
|
|
|
|
2015-07-22 01:40:14 +08:00
|
|
|
// If we have a call to llvm.localescape, keep it in the entry block.
|
|
|
|
if (LocalEscapeCall) LocalEscapeCall->moveBefore(InsBefore);
|
|
|
|
|
2013-12-06 17:00:17 +08:00
|
|
|
SmallVector<ASanStackVariableDescription, 16> SVD;
|
|
|
|
SVD.reserve(AllocaVec.size());
|
2014-05-30 02:40:48 +08:00
|
|
|
for (AllocaInst *AI : AllocaVec) {
|
2015-03-04 21:27:53 +08:00
|
|
|
ASanStackVariableDescription D = {AI->getName().data(),
|
2016-07-29 06:50:50 +08:00
|
|
|
ASan.getAllocaSizeInBytes(*AI),
|
2016-10-19 07:29:41 +08:00
|
|
|
0,
|
2016-08-21 00:48:24 +08:00
|
|
|
AI->getAlignment(),
|
|
|
|
AI,
|
2016-10-19 07:29:41 +08:00
|
|
|
0,
|
2016-08-21 00:48:24 +08:00
|
|
|
0};
|
2013-12-06 17:00:17 +08:00
|
|
|
SVD.push_back(D);
|
|
|
|
}
|
2016-10-19 07:29:52 +08:00
|
|
|
|
2013-12-06 17:00:17 +08:00
|
|
|
// Minimal header size (left redzone) is 4 pointers,
|
|
|
|
// i.e. 32 bytes on 64-bit platforms and 16 bytes in 32-bit platforms.
|
2017-11-16 20:57:19 +08:00
|
|
|
size_t Granularity = 1ULL << Mapping.Scale;
|
|
|
|
size_t MinHeaderSize = std::max((size_t)ASan.LongSize / 2, Granularity);
|
2016-08-30 01:41:29 +08:00
|
|
|
const ASanStackFrameLayout &L =
|
2017-11-16 20:57:19 +08:00
|
|
|
ComputeASanStackFrameLayout(SVD, Granularity, MinHeaderSize);
|
2016-08-30 02:17:21 +08:00
|
|
|
|
2016-10-19 07:29:52 +08:00
|
|
|
// Build AllocaToSVDMap for ASanStackVariableDescription lookup.
|
|
|
|
DenseMap<const AllocaInst *, ASanStackVariableDescription *> AllocaToSVDMap;
|
|
|
|
for (auto &Desc : SVD)
|
|
|
|
AllocaToSVDMap[Desc.AI] = &Desc;
|
|
|
|
|
|
|
|
// Update SVD with information from lifetime intrinsics.
|
|
|
|
for (const auto &APC : StaticAllocaPoisonCallVec) {
|
|
|
|
assert(APC.InsBefore);
|
|
|
|
assert(APC.AI);
|
|
|
|
assert(ASan.isInterestingAlloca(*APC.AI));
|
|
|
|
assert(APC.AI->isStaticAlloca());
|
|
|
|
|
|
|
|
ASanStackVariableDescription &Desc = *AllocaToSVDMap[APC.AI];
|
|
|
|
Desc.LifetimeSize = Desc.Size;
|
|
|
|
if (const DILocation *FnLoc = EntryDebugLocation.get()) {
|
|
|
|
if (const DILocation *LifetimeLoc = APC.InsBefore->getDebugLoc().get()) {
|
|
|
|
if (LifetimeLoc->getFile() == FnLoc->getFile())
|
|
|
|
if (unsigned Line = LifetimeLoc->getLine())
|
|
|
|
Desc.Line = std::min(Desc.Line ? Desc.Line : Line, Line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto DescriptionString = ComputeASanStackFrameDescription(SVD);
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << DescriptionString << " --- " << L.FrameSize << "\n");
|
2013-12-06 17:00:17 +08:00
|
|
|
uint64_t LocalStackSize = L.FrameSize;
|
2015-06-19 20:19:07 +08:00
|
|
|
bool DoStackMalloc = ClUseAfterReturn && !ASan.CompileKernel &&
|
|
|
|
LocalStackSize <= kMaxStackMallocSize;
|
[ASan] Disable dynamic alloca and UAR detection in presence of returns_twice calls.
Summary:
returns_twice (most importantly, setjmp) functions are
optimization-hostile: if local variable is promoted to register, and is
changed between setjmp() and longjmp() calls, this update will be
undone. This is the reason why "man setjmp" advises to mark all these
locals as "volatile".
This can not be enough for ASan, though: when it replaces static alloca
with dynamic one, optionally called if UAR mode is enabled, it adds a
whole lot of SSA values, and computations of local variable addresses,
that can involve virtual registers, and cause unexpected behavior, when
these registers are restored from buffer saved in setjmp.
To fix this, just disable dynamic alloca and UAR tricks whenever we see
a returns_twice call in the function.
Reviewers: rnk
Subscribers: llvm-commits, kcc
Differential Revision: http://reviews.llvm.org/D11495
llvm-svn: 243561
2015-07-30 03:36:08 +08:00
|
|
|
bool DoDynamicAlloca = ClDynamicAllocaStack;
|
|
|
|
// Don't do dynamic alloca or stack malloc if:
|
|
|
|
// 1) There is inline asm: too often it makes assumptions on which registers
|
|
|
|
// are available.
|
|
|
|
// 2) There is a returns_twice call (typically setjmp), which is
|
|
|
|
// optimization-hostile, and doesn't play well with introduced indirect
|
|
|
|
// register-relative calculation of local variable addresses.
|
2020-06-23 02:43:52 +08:00
|
|
|
DoDynamicAlloca &= !HasInlineAsm && !HasReturnsTwiceCall;
|
|
|
|
DoStackMalloc &= !HasInlineAsm && !HasReturnsTwiceCall;
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2014-12-12 05:53:03 +08:00
|
|
|
Value *StaticAlloca =
|
|
|
|
DoDynamicAlloca ? nullptr : createAllocaForLayout(IRB, L, false);
|
|
|
|
|
|
|
|
Value *FakeStack;
|
|
|
|
Value *LocalStackBase;
|
2017-12-12 04:43:21 +08:00
|
|
|
Value *LocalStackBaseAlloca;
|
2019-05-20 18:35:57 +08:00
|
|
|
uint8_t DIExprFlags = DIExpression::ApplyOffset;
|
2011-11-16 09:35:23 +08:00
|
|
|
|
|
|
|
if (DoStackMalloc) {
|
2017-12-12 04:43:21 +08:00
|
|
|
LocalStackBaseAlloca =
|
|
|
|
IRB.CreateAlloca(IntptrTy, nullptr, "asan_local_stack_base");
|
2014-12-12 05:53:03 +08:00
|
|
|
// void *FakeStack = __asan_option_detect_stack_use_after_return
|
|
|
|
// ? __asan_stack_malloc_N(LocalStackSize)
|
|
|
|
// : nullptr;
|
|
|
|
// void *LocalStackBase = (FakeStack) ? FakeStack : alloca(LocalStackSize);
|
2016-06-02 08:06:42 +08:00
|
|
|
Constant *OptionDetectUseAfterReturn = F.getParent()->getOrInsertGlobal(
|
|
|
|
kAsanOptionDetectUseAfterReturn, IRB.getInt32Ty());
|
2019-02-02 04:44:24 +08:00
|
|
|
Value *UseAfterReturnIsEnabled = IRB.CreateICmpNE(
|
|
|
|
IRB.CreateLoad(IRB.getInt32Ty(), OptionDetectUseAfterReturn),
|
|
|
|
Constant::getNullValue(IRB.getInt32Ty()));
|
2014-12-12 05:53:03 +08:00
|
|
|
Instruction *Term =
|
2016-06-02 08:06:42 +08:00
|
|
|
SplitBlockAndInsertIfThen(UseAfterReturnIsEnabled, InsBefore, false);
|
2013-09-18 22:07:14 +08:00
|
|
|
IRBuilder<> IRBIf(Term);
|
2014-12-12 05:53:03 +08:00
|
|
|
StackMallocIdx = StackMallocSizeClass(LocalStackSize);
|
|
|
|
assert(StackMallocIdx <= kMaxAsanStackMallocSizeClass);
|
|
|
|
Value *FakeStackValue =
|
|
|
|
IRBIf.CreateCall(AsanStackMallocFunc[StackMallocIdx],
|
|
|
|
ConstantInt::get(IntptrTy, LocalStackSize));
|
|
|
|
IRB.SetInsertPoint(InsBefore);
|
2016-06-02 08:06:42 +08:00
|
|
|
FakeStack = createPHI(IRB, UseAfterReturnIsEnabled, FakeStackValue, Term,
|
2014-12-12 05:53:03 +08:00
|
|
|
ConstantInt::get(IntptrTy, 0));
|
|
|
|
|
|
|
|
Value *NoFakeStack =
|
|
|
|
IRB.CreateICmpEQ(FakeStack, Constant::getNullValue(IntptrTy));
|
|
|
|
Term = SplitBlockAndInsertIfThen(NoFakeStack, InsBefore, false);
|
|
|
|
IRBIf.SetInsertPoint(Term);
|
|
|
|
Value *AllocaValue =
|
|
|
|
DoDynamicAlloca ? createAllocaForLayout(IRBIf, L, true) : StaticAlloca;
|
2017-12-12 04:43:21 +08:00
|
|
|
|
2013-09-18 22:07:14 +08:00
|
|
|
IRB.SetInsertPoint(InsBefore);
|
2014-12-12 05:53:03 +08:00
|
|
|
LocalStackBase = createPHI(IRB, NoFakeStack, AllocaValue, Term, FakeStack);
|
2017-12-12 04:43:21 +08:00
|
|
|
IRB.CreateStore(LocalStackBase, LocalStackBaseAlloca);
|
2019-05-20 18:35:57 +08:00
|
|
|
DIExprFlags |= DIExpression::DerefBefore;
|
2014-12-12 05:53:03 +08:00
|
|
|
} else {
|
|
|
|
// void *FakeStack = nullptr;
|
|
|
|
// void *LocalStackBase = alloca(LocalStackSize);
|
|
|
|
FakeStack = ConstantInt::get(IntptrTy, 0);
|
|
|
|
LocalStackBase =
|
|
|
|
DoDynamicAlloca ? createAllocaForLayout(IRB, L, true) : StaticAlloca;
|
2017-12-12 04:43:21 +08:00
|
|
|
LocalStackBaseAlloca = LocalStackBase;
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
[AddressSanitizer] Ensure only AllocaInst is passed to dbg.declare
Various parts of the LLVM code generator assume that the address
argument of a dbg.declare is not a `ptrtoint`-of-alloca. ASan breaks
this assumption, and this results in local variables sometimes being
unavailable at -O0.
GlobalISel, SelectionDAG, and FastISel all do not appear to expect
dbg.declares to have a `ptrtoint` as an operand. This means that they do
not place entry block allocas in the usual side table reserved for local
variables available in the whole function scope. This isn't always a
problem, as LLVM can try to lower the dbg.declare to a DBG_VALUE, but
those DBG_VALUEs can get dropped for all the usual reasons DBG_VALUEs
get dropped. In the ObjC test case I'm looking at, the cause happens to
be that `replaceDbgDeclare` has hoisted dbg.declares into the entry
block, causing LiveDebugValues to "kill" the DBG_VALUEs because the
lexical dominance check fails.
To address this, I propose:
1) Have ASan (always) pass an alloca to dbg.declares (this patch). This
is a narrow bugfix for -O0 debugging.
2) Make replaceDbgDeclare not move dbg.declares around. This should be a
generic improvement for optimized debug info, as it would prevent the
lexical dominance check in LiveDebugValues from killing as many
variables.
This means reverting llvm/r227544, which fixed an assertion failure
(llvm.org/PR22386) but no longer seems to be necessary. I was able to
complete a stage2 build with the revert in place.
rdar://54688991
Differential Revision: https://reviews.llvm.org/D74369
2020-02-11 08:22:27 +08:00
|
|
|
// It shouldn't matter whether we pass an `alloca` or a `ptrtoint` as the
|
|
|
|
// dbg.declare address opereand, but passing a `ptrtoint` seems to confuse
|
|
|
|
// later passes and can result in dropped variable coverage in debug info.
|
|
|
|
Value *LocalStackBaseAllocaPtr =
|
|
|
|
isa<PtrToIntInst>(LocalStackBaseAlloca)
|
|
|
|
? cast<PtrToIntInst>(LocalStackBaseAlloca)->getPointerOperand()
|
|
|
|
: LocalStackBaseAlloca;
|
|
|
|
assert(isa<AllocaInst>(LocalStackBaseAllocaPtr) &&
|
|
|
|
"Variable descriptions relative to ASan stack base will be dropped");
|
|
|
|
|
2011-11-16 09:35:23 +08:00
|
|
|
// Replace Alloca instructions with base+offset.
|
2014-05-30 02:40:48 +08:00
|
|
|
for (const auto &Desc : SVD) {
|
|
|
|
AllocaInst *AI = Desc.AI;
|
2020-02-11 07:37:56 +08:00
|
|
|
replaceDbgDeclare(AI, LocalStackBaseAllocaPtr, DIB, DIExprFlags,
|
|
|
|
Desc.Offset);
|
2012-12-04 09:34:23 +08:00
|
|
|
Value *NewAllocaPtr = IRB.CreateIntToPtr(
|
2014-05-30 02:40:48 +08:00
|
|
|
IRB.CreateAdd(LocalStackBase, ConstantInt::get(IntptrTy, Desc.Offset)),
|
2013-12-06 17:00:17 +08:00
|
|
|
AI->getType());
|
2012-12-04 09:34:23 +08:00
|
|
|
AI->replaceAllUsesWith(NewAllocaPtr);
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
|
[asan] Change the way we report the alloca frame on stack-buff-overflow.
Before: the function name was stored by the compiler as a constant string
and the run-time was printing it.
Now: the PC is stored instead and the run-time prints the full symbolized frame.
This adds a couple of instructions into every function with non-empty stack frame,
but also reduces the binary size because we store less strings (I saw 2% size reduction).
This change bumps the asan ABI version to v3.
llvm part.
Example of report (now):
==31711==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffa77cf1c5 at pc 0x41feb0 bp 0x7fffa77cefb0 sp 0x7fffa77cefa8
READ of size 1 at 0x7fffa77cf1c5 thread T0
#0 0x41feaf in Frame0(int, char*, char*, char*) stack-oob-frames.cc:20
#1 0x41f7ff in Frame1(int, char*, char*) stack-oob-frames.cc:24
#2 0x41f477 in Frame2(int, char*) stack-oob-frames.cc:28
#3 0x41f194 in Frame3(int) stack-oob-frames.cc:32
#4 0x41eee0 in main stack-oob-frames.cc:38
#5 0x7f0c5566f76c (/lib/x86_64-linux-gnu/libc.so.6+0x2176c)
#6 0x41eb1c (/usr/local/google/kcc/llvm_cmake/a.out+0x41eb1c)
Address 0x7fffa77cf1c5 is located in stack of thread T0 at offset 293 in frame
#0 0x41f87f in Frame0(int, char*, char*, char*) stack-oob-frames.cc:12 <<<<<<<<<<<<<< this is new
This frame has 6 object(s):
[32, 36) 'frame.addr'
[96, 104) 'a.addr'
[160, 168) 'b.addr'
[224, 232) 'c.addr'
[288, 292) 's'
[352, 360) 'd'
llvm-svn: 177724
2013-03-22 18:37:20 +08:00
|
|
|
// The left-most redzone has enough space for at least 4 pointers.
|
|
|
|
// Write the Magic value to redzone[0].
|
2011-11-16 09:35:23 +08:00
|
|
|
Value *BasePlus0 = IRB.CreateIntToPtr(LocalStackBase, IntptrPtrTy);
|
|
|
|
IRB.CreateStore(ConstantInt::get(IntptrTy, kCurrentStackFrameMagic),
|
|
|
|
BasePlus0);
|
[asan] Change the way we report the alloca frame on stack-buff-overflow.
Before: the function name was stored by the compiler as a constant string
and the run-time was printing it.
Now: the PC is stored instead and the run-time prints the full symbolized frame.
This adds a couple of instructions into every function with non-empty stack frame,
but also reduces the binary size because we store less strings (I saw 2% size reduction).
This change bumps the asan ABI version to v3.
llvm part.
Example of report (now):
==31711==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffa77cf1c5 at pc 0x41feb0 bp 0x7fffa77cefb0 sp 0x7fffa77cefa8
READ of size 1 at 0x7fffa77cf1c5 thread T0
#0 0x41feaf in Frame0(int, char*, char*, char*) stack-oob-frames.cc:20
#1 0x41f7ff in Frame1(int, char*, char*) stack-oob-frames.cc:24
#2 0x41f477 in Frame2(int, char*) stack-oob-frames.cc:28
#3 0x41f194 in Frame3(int) stack-oob-frames.cc:32
#4 0x41eee0 in main stack-oob-frames.cc:38
#5 0x7f0c5566f76c (/lib/x86_64-linux-gnu/libc.so.6+0x2176c)
#6 0x41eb1c (/usr/local/google/kcc/llvm_cmake/a.out+0x41eb1c)
Address 0x7fffa77cf1c5 is located in stack of thread T0 at offset 293 in frame
#0 0x41f87f in Frame0(int, char*, char*, char*) stack-oob-frames.cc:12 <<<<<<<<<<<<<< this is new
This frame has 6 object(s):
[32, 36) 'frame.addr'
[96, 104) 'a.addr'
[160, 168) 'b.addr'
[224, 232) 'c.addr'
[288, 292) 's'
[352, 360) 'd'
llvm-svn: 177724
2013-03-22 18:37:20 +08:00
|
|
|
// Write the frame description constant to redzone[1].
|
|
|
|
Value *BasePlus1 = IRB.CreateIntToPtr(
|
2015-03-04 21:27:53 +08:00
|
|
|
IRB.CreateAdd(LocalStackBase,
|
|
|
|
ConstantInt::get(IntptrTy, ASan.LongSize / 8)),
|
|
|
|
IntptrPtrTy);
|
2012-11-02 20:20:34 +08:00
|
|
|
GlobalVariable *StackDescriptionGlobal =
|
2016-10-19 07:29:52 +08:00
|
|
|
createPrivateGlobalForString(*F.getParent(), DescriptionString,
|
2018-10-12 07:03:27 +08:00
|
|
|
/*AllowMerging*/ true, kAsanGenPrefix);
|
2015-03-04 21:27:53 +08:00
|
|
|
Value *Description = IRB.CreatePointerCast(StackDescriptionGlobal, IntptrTy);
|
2011-11-16 09:35:23 +08:00
|
|
|
IRB.CreateStore(Description, BasePlus1);
|
[asan] Change the way we report the alloca frame on stack-buff-overflow.
Before: the function name was stored by the compiler as a constant string
and the run-time was printing it.
Now: the PC is stored instead and the run-time prints the full symbolized frame.
This adds a couple of instructions into every function with non-empty stack frame,
but also reduces the binary size because we store less strings (I saw 2% size reduction).
This change bumps the asan ABI version to v3.
llvm part.
Example of report (now):
==31711==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffa77cf1c5 at pc 0x41feb0 bp 0x7fffa77cefb0 sp 0x7fffa77cefa8
READ of size 1 at 0x7fffa77cf1c5 thread T0
#0 0x41feaf in Frame0(int, char*, char*, char*) stack-oob-frames.cc:20
#1 0x41f7ff in Frame1(int, char*, char*) stack-oob-frames.cc:24
#2 0x41f477 in Frame2(int, char*) stack-oob-frames.cc:28
#3 0x41f194 in Frame3(int) stack-oob-frames.cc:32
#4 0x41eee0 in main stack-oob-frames.cc:38
#5 0x7f0c5566f76c (/lib/x86_64-linux-gnu/libc.so.6+0x2176c)
#6 0x41eb1c (/usr/local/google/kcc/llvm_cmake/a.out+0x41eb1c)
Address 0x7fffa77cf1c5 is located in stack of thread T0 at offset 293 in frame
#0 0x41f87f in Frame0(int, char*, char*, char*) stack-oob-frames.cc:12 <<<<<<<<<<<<<< this is new
This frame has 6 object(s):
[32, 36) 'frame.addr'
[96, 104) 'a.addr'
[160, 168) 'b.addr'
[224, 232) 'c.addr'
[288, 292) 's'
[352, 360) 'd'
llvm-svn: 177724
2013-03-22 18:37:20 +08:00
|
|
|
// Write the PC to redzone[2].
|
|
|
|
Value *BasePlus2 = IRB.CreateIntToPtr(
|
2015-03-04 21:27:53 +08:00
|
|
|
IRB.CreateAdd(LocalStackBase,
|
|
|
|
ConstantInt::get(IntptrTy, 2 * ASan.LongSize / 8)),
|
|
|
|
IntptrPtrTy);
|
[asan] Change the way we report the alloca frame on stack-buff-overflow.
Before: the function name was stored by the compiler as a constant string
and the run-time was printing it.
Now: the PC is stored instead and the run-time prints the full symbolized frame.
This adds a couple of instructions into every function with non-empty stack frame,
but also reduces the binary size because we store less strings (I saw 2% size reduction).
This change bumps the asan ABI version to v3.
llvm part.
Example of report (now):
==31711==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffa77cf1c5 at pc 0x41feb0 bp 0x7fffa77cefb0 sp 0x7fffa77cefa8
READ of size 1 at 0x7fffa77cf1c5 thread T0
#0 0x41feaf in Frame0(int, char*, char*, char*) stack-oob-frames.cc:20
#1 0x41f7ff in Frame1(int, char*, char*) stack-oob-frames.cc:24
#2 0x41f477 in Frame2(int, char*) stack-oob-frames.cc:28
#3 0x41f194 in Frame3(int) stack-oob-frames.cc:32
#4 0x41eee0 in main stack-oob-frames.cc:38
#5 0x7f0c5566f76c (/lib/x86_64-linux-gnu/libc.so.6+0x2176c)
#6 0x41eb1c (/usr/local/google/kcc/llvm_cmake/a.out+0x41eb1c)
Address 0x7fffa77cf1c5 is located in stack of thread T0 at offset 293 in frame
#0 0x41f87f in Frame0(int, char*, char*, char*) stack-oob-frames.cc:12 <<<<<<<<<<<<<< this is new
This frame has 6 object(s):
[32, 36) 'frame.addr'
[96, 104) 'a.addr'
[160, 168) 'b.addr'
[224, 232) 'c.addr'
[288, 292) 's'
[352, 360) 'd'
llvm-svn: 177724
2013-03-22 18:37:20 +08:00
|
|
|
IRB.CreateStore(IRB.CreatePointerCast(&F, IntptrTy), BasePlus2);
|
2011-11-16 09:35:23 +08:00
|
|
|
|
2016-08-30 02:17:21 +08:00
|
|
|
const auto &ShadowAfterScope = GetShadowBytesAfterScope(SVD, L);
|
|
|
|
|
|
|
|
// Poison the stack red zones at the entry.
|
2012-12-25 20:04:36 +08:00
|
|
|
Value *ShadowBase = ASan.memToShadow(LocalStackBase, IRB);
|
2016-08-30 02:17:21 +08:00
|
|
|
// As mask we must use most poisoned case: red zones and after scope.
|
|
|
|
// As bytes we can use either the same or just red zones only.
|
|
|
|
copyToShadow(ShadowAfterScope, ShadowAfterScope, IRB, ShadowBase);
|
|
|
|
|
2016-10-19 02:04:59 +08:00
|
|
|
if (!StaticAllocaPoisonCallVec.empty()) {
|
2016-08-30 02:17:21 +08:00
|
|
|
const auto &ShadowInScope = GetShadowBytes(SVD, L);
|
|
|
|
|
|
|
|
// Poison static allocas near lifetime intrinsics.
|
|
|
|
for (const auto &APC : StaticAllocaPoisonCallVec) {
|
2016-10-19 07:29:52 +08:00
|
|
|
const ASanStackVariableDescription &Desc = *AllocaToSVDMap[APC.AI];
|
2016-08-30 02:17:21 +08:00
|
|
|
assert(Desc.Offset % L.Granularity == 0);
|
|
|
|
size_t Begin = Desc.Offset / L.Granularity;
|
|
|
|
size_t End = Begin + (APC.Size + L.Granularity - 1) / L.Granularity;
|
|
|
|
|
|
|
|
IRBuilder<> IRB(APC.InsBefore);
|
|
|
|
copyToShadow(ShadowAfterScope,
|
|
|
|
APC.DoPoison ? ShadowAfterScope : ShadowInScope, Begin, End,
|
|
|
|
IRB, ShadowBase);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SmallVector<uint8_t, 64> ShadowClean(ShadowAfterScope.size(), 0);
|
|
|
|
SmallVector<uint8_t, 64> ShadowAfterReturn;
|
2016-08-21 02:34:36 +08:00
|
|
|
|
2013-12-23 22:15:08 +08:00
|
|
|
// (Un)poison the stack before all ret instructions.
|
2014-05-30 02:40:48 +08:00
|
|
|
for (auto Ret : RetVec) {
|
2011-11-16 09:35:23 +08:00
|
|
|
IRBuilder<> IRBRet(Ret);
|
|
|
|
// Mark the current frame as retired.
|
|
|
|
IRBRet.CreateStore(ConstantInt::get(IntptrTy, kRetiredStackFrameMagic),
|
|
|
|
BasePlus0);
|
|
|
|
if (DoStackMalloc) {
|
2013-09-10 21:16:56 +08:00
|
|
|
assert(StackMallocIdx >= 0);
|
2014-12-12 05:53:03 +08:00
|
|
|
// if FakeStack != 0 // LocalStackBase == FakeStack
|
2013-12-23 22:15:08 +08:00
|
|
|
// // In use-after-return mode, poison the whole stack frame.
|
|
|
|
// if StackMallocIdx <= 4
|
|
|
|
// // For small sizes inline the whole thing:
|
|
|
|
// memset(ShadowBase, kAsanStackAfterReturnMagic, ShadowSize);
|
2014-12-12 05:53:03 +08:00
|
|
|
// **SavedFlagPtr(FakeStack) = 0
|
2013-12-23 22:15:08 +08:00
|
|
|
// else
|
2014-12-12 05:53:03 +08:00
|
|
|
// __asan_stack_free_N(FakeStack, LocalStackSize)
|
2013-12-23 22:15:08 +08:00
|
|
|
// else
|
|
|
|
// <This is not a fake stack; unpoison the redzones>
|
2014-12-12 05:53:03 +08:00
|
|
|
Value *Cmp =
|
|
|
|
IRBRet.CreateICmpNE(FakeStack, Constant::getNullValue(IntptrTy));
|
2018-10-15 17:34:05 +08:00
|
|
|
Instruction *ThenTerm, *ElseTerm;
|
2013-12-23 22:15:08 +08:00
|
|
|
SplitBlockAndInsertIfThenElse(Cmp, Ret, &ThenTerm, &ElseTerm);
|
|
|
|
|
|
|
|
IRBuilder<> IRBPoison(ThenTerm);
|
2013-09-17 20:14:50 +08:00
|
|
|
if (StackMallocIdx <= 4) {
|
|
|
|
int ClassSize = kMinStackMallocSize << StackMallocIdx;
|
2016-08-30 02:17:21 +08:00
|
|
|
ShadowAfterReturn.resize(ClassSize / L.Granularity,
|
|
|
|
kAsanStackUseAfterReturnMagic);
|
|
|
|
copyToShadow(ShadowAfterReturn, ShadowAfterReturn, IRBPoison,
|
|
|
|
ShadowBase);
|
2013-09-17 20:14:50 +08:00
|
|
|
Value *SavedFlagPtrPtr = IRBPoison.CreateAdd(
|
2014-12-12 05:53:03 +08:00
|
|
|
FakeStack,
|
2013-09-17 20:14:50 +08:00
|
|
|
ConstantInt::get(IntptrTy, ClassSize - ASan.LongSize / 8));
|
|
|
|
Value *SavedFlagPtr = IRBPoison.CreateLoad(
|
2019-02-02 04:44:24 +08:00
|
|
|
IntptrTy, IRBPoison.CreateIntToPtr(SavedFlagPtrPtr, IntptrPtrTy));
|
2013-09-17 20:14:50 +08:00
|
|
|
IRBPoison.CreateStore(
|
|
|
|
Constant::getNullValue(IRBPoison.getInt8Ty()),
|
|
|
|
IRBPoison.CreateIntToPtr(SavedFlagPtr, IRBPoison.getInt8PtrTy()));
|
|
|
|
} else {
|
|
|
|
// For larger frames call __asan_stack_free_*.
|
2015-05-19 06:13:54 +08:00
|
|
|
IRBPoison.CreateCall(
|
|
|
|
AsanStackFreeFunc[StackMallocIdx],
|
|
|
|
{FakeStack, ConstantInt::get(IntptrTy, LocalStackSize)});
|
2013-09-17 20:14:50 +08:00
|
|
|
}
|
2013-12-23 22:15:08 +08:00
|
|
|
|
|
|
|
IRBuilder<> IRBElse(ElseTerm);
|
2016-10-19 02:04:59 +08:00
|
|
|
copyToShadow(ShadowAfterScope, ShadowClean, IRBElse, ShadowBase);
|
2013-12-23 22:15:08 +08:00
|
|
|
} else {
|
2016-10-19 02:04:59 +08:00
|
|
|
copyToShadow(ShadowAfterScope, ShadowClean, IRBRet, ShadowBase);
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-19 14:20:53 +08:00
|
|
|
// We are done. Remove the old unused alloca instructions.
|
2015-03-04 21:27:53 +08:00
|
|
|
for (auto AI : AllocaVec) AI->eraseFromParent();
|
2011-11-16 09:35:23 +08:00
|
|
|
}
|
2012-12-04 09:34:23 +08:00
|
|
|
|
2012-12-25 20:04:36 +08:00
|
|
|
void FunctionStackPoisoner::poisonAlloca(Value *V, uint64_t Size,
|
2013-08-10 04:53:48 +08:00
|
|
|
IRBuilder<> &IRB, bool DoPoison) {
|
2012-12-04 09:34:23 +08:00
|
|
|
// For now just insert the call to ASan runtime.
|
|
|
|
Value *AddrArg = IRB.CreatePointerCast(V, IntptrTy);
|
|
|
|
Value *SizeArg = ConstantInt::get(IntptrTy, Size);
|
2015-06-12 19:27:06 +08:00
|
|
|
IRB.CreateCall(
|
|
|
|
DoPoison ? AsanPoisonStackMemoryFunc : AsanUnpoisonStackMemoryFunc,
|
|
|
|
{AddrArg, SizeArg});
|
2012-12-04 09:34:23 +08:00
|
|
|
}
|
2012-12-25 20:04:36 +08:00
|
|
|
|
|
|
|
// Handling llvm.lifetime intrinsics for a given %alloca:
|
|
|
|
// (1) collect all llvm.lifetime.xxx(%size, %value) describing the alloca.
|
|
|
|
// (2) if %size is constant, poison memory for llvm.lifetime.end (to detect
|
|
|
|
// invalid accesses) and unpoison it for llvm.lifetime.start (the memory
|
|
|
|
// could be poisoned by previous llvm.lifetime.end instruction, as the
|
|
|
|
// variable may go in and out of scope several times, e.g. in loops).
|
|
|
|
// (3) if we poisoned at least one %alloca in a function,
|
|
|
|
// unpoison the whole stack frame at function exit.
|
2015-05-28 15:51:49 +08:00
|
|
|
void FunctionStackPoisoner::handleDynamicAllocaCall(AllocaInst *AI) {
|
2014-11-21 18:29:50 +08:00
|
|
|
IRBuilder<> IRB(AI);
|
|
|
|
|
2020-05-16 04:23:14 +08:00
|
|
|
const unsigned Alignment = std::max(kAllocaRzSize, AI->getAlignment());
|
2014-11-21 18:29:50 +08:00
|
|
|
const uint64_t AllocaRedzoneMask = kAllocaRzSize - 1;
|
|
|
|
|
|
|
|
Value *Zero = Constant::getNullValue(IntptrTy);
|
|
|
|
Value *AllocaRzSize = ConstantInt::get(IntptrTy, kAllocaRzSize);
|
|
|
|
Value *AllocaRzMask = ConstantInt::get(IntptrTy, AllocaRedzoneMask);
|
|
|
|
|
|
|
|
// Since we need to extend alloca with additional memory to locate
|
|
|
|
// redzones, and OldSize is number of allocated blocks with
|
|
|
|
// ElementSize size, get allocated memory size in bytes by
|
|
|
|
// OldSize * ElementSize.
|
2015-05-28 15:51:49 +08:00
|
|
|
const unsigned ElementSize =
|
2015-03-10 10:37:25 +08:00
|
|
|
F.getParent()->getDataLayout().getTypeAllocSize(AI->getAllocatedType());
|
2015-05-28 15:51:49 +08:00
|
|
|
Value *OldSize =
|
|
|
|
IRB.CreateMul(IRB.CreateIntCast(AI->getArraySize(), IntptrTy, false),
|
|
|
|
ConstantInt::get(IntptrTy, ElementSize));
|
2014-11-21 18:29:50 +08:00
|
|
|
|
|
|
|
// PartialSize = OldSize % 32
|
|
|
|
Value *PartialSize = IRB.CreateAnd(OldSize, AllocaRzMask);
|
|
|
|
|
|
|
|
// Misalign = kAllocaRzSize - PartialSize;
|
|
|
|
Value *Misalign = IRB.CreateSub(AllocaRzSize, PartialSize);
|
|
|
|
|
|
|
|
// PartialPadding = Misalign != kAllocaRzSize ? Misalign : 0;
|
|
|
|
Value *Cond = IRB.CreateICmpNE(Misalign, AllocaRzSize);
|
|
|
|
Value *PartialPadding = IRB.CreateSelect(Cond, Misalign, Zero);
|
|
|
|
|
2020-05-16 04:23:14 +08:00
|
|
|
// AdditionalChunkSize = Alignment + PartialPadding + kAllocaRzSize
|
|
|
|
// Alignment is added to locate left redzone, PartialPadding for possible
|
2014-11-21 18:29:50 +08:00
|
|
|
// partial redzone and kAllocaRzSize for right redzone respectively.
|
|
|
|
Value *AdditionalChunkSize = IRB.CreateAdd(
|
2020-05-16 04:23:14 +08:00
|
|
|
ConstantInt::get(IntptrTy, Alignment + kAllocaRzSize), PartialPadding);
|
2014-11-21 18:29:50 +08:00
|
|
|
|
|
|
|
Value *NewSize = IRB.CreateAdd(OldSize, AdditionalChunkSize);
|
|
|
|
|
2020-05-16 04:23:14 +08:00
|
|
|
// Insert new alloca with new NewSize and Alignment params.
|
2014-11-21 18:29:50 +08:00
|
|
|
AllocaInst *NewAlloca = IRB.CreateAlloca(IRB.getInt8Ty(), NewSize);
|
2020-05-16 04:23:14 +08:00
|
|
|
NewAlloca->setAlignment(Align(Alignment));
|
2014-11-21 18:29:50 +08:00
|
|
|
|
2020-05-16 04:23:14 +08:00
|
|
|
// NewAddress = Address + Alignment
|
2014-11-21 18:29:50 +08:00
|
|
|
Value *NewAddress = IRB.CreateAdd(IRB.CreatePtrToInt(NewAlloca, IntptrTy),
|
2020-05-16 04:23:14 +08:00
|
|
|
ConstantInt::get(IntptrTy, Alignment));
|
2014-11-21 18:29:50 +08:00
|
|
|
|
2015-05-28 15:51:49 +08:00
|
|
|
// Insert __asan_alloca_poison call for new created alloca.
|
2015-05-28 16:03:28 +08:00
|
|
|
IRB.CreateCall(AsanAllocaPoisonFunc, {NewAddress, OldSize});
|
2014-11-21 18:29:50 +08:00
|
|
|
|
2015-05-28 15:51:49 +08:00
|
|
|
// Store the last alloca's address to DynamicAllocaLayout. We'll need this
|
|
|
|
// for unpoisoning stuff.
|
|
|
|
IRB.CreateStore(IRB.CreatePtrToInt(NewAlloca, IntptrTy), DynamicAllocaLayout);
|
2014-11-21 18:29:50 +08:00
|
|
|
|
2015-05-28 15:51:49 +08:00
|
|
|
Value *NewAddressPtr = IRB.CreateIntToPtr(NewAddress, AI->getType());
|
2014-11-21 18:29:50 +08:00
|
|
|
|
2015-05-28 15:51:49 +08:00
|
|
|
// Replace all uses of AddessReturnedByAlloca with NewAddressPtr.
|
2014-11-21 18:29:50 +08:00
|
|
|
AI->replaceAllUsesWith(NewAddressPtr);
|
|
|
|
|
2015-05-28 15:51:49 +08:00
|
|
|
// We are done. Erase old alloca from parent.
|
2014-11-21 18:29:50 +08:00
|
|
|
AI->eraseFromParent();
|
|
|
|
}
|
2015-03-04 21:27:53 +08:00
|
|
|
|
|
|
|
// isSafeAccess returns true if Addr is always inbounds with respect to its
|
|
|
|
// base object. For example, it is a field access or an array access with
|
|
|
|
// constant inbounds index.
|
|
|
|
bool AddressSanitizer::isSafeAccess(ObjectSizeOffsetVisitor &ObjSizeVis,
|
|
|
|
Value *Addr, uint64_t TypeSize) const {
|
|
|
|
SizeOffsetType SizeOffset = ObjSizeVis.compute(Addr);
|
|
|
|
if (!ObjSizeVis.bothKnown(SizeOffset)) return false;
|
2015-03-16 16:04:26 +08:00
|
|
|
uint64_t Size = SizeOffset.first.getZExtValue();
|
2015-03-04 21:27:53 +08:00
|
|
|
int64_t Offset = SizeOffset.second.getSExtValue();
|
|
|
|
// Three checks are required to ensure safety:
|
|
|
|
// . Offset >= 0 (since the offset is given from the base ptr)
|
|
|
|
// . Size >= Offset (unsigned)
|
|
|
|
// . Size - Offset >= NeededSize (unsigned)
|
2015-03-16 16:04:26 +08:00
|
|
|
return Offset >= 0 && Size >= uint64_t(Offset) &&
|
|
|
|
Size - uint64_t(Offset) >= TypeSize / 8;
|
2015-03-04 21:27:53 +08:00
|
|
|
}
|