269 lines
7.7 KiB
C++
269 lines
7.7 KiB
C++
//===-- asan_descriptions.h -------------------------------------*- C++ -*-===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file is a part of AddressSanitizer, an address sanity checker.
|
|
//
|
|
// ASan-private header for asan_descriptions.cpp.
|
|
// TODO(filcab): Most struct definitions should move to the interface headers.
|
|
//===----------------------------------------------------------------------===//
|
|
#ifndef ASAN_DESCRIPTIONS_H
|
|
#define ASAN_DESCRIPTIONS_H
|
|
|
|
#include "asan_allocator.h"
|
|
#include "asan_thread.h"
|
|
#include "sanitizer_common/sanitizer_common.h"
|
|
#include "sanitizer_common/sanitizer_report_decorator.h"
|
|
|
|
namespace __asan {
|
|
|
|
void DescribeThread(AsanThreadContext *context);
|
|
static inline void DescribeThread(AsanThread *t) {
|
|
if (t) DescribeThread(t->context());
|
|
}
|
|
|
|
class AsanThreadIdAndName {
|
|
public:
|
|
explicit AsanThreadIdAndName(AsanThreadContext *t);
|
|
explicit AsanThreadIdAndName(u32 tid);
|
|
|
|
// Contains "T%tid (%name)" or "T%tid" if the name is empty.
|
|
const char *c_str() const { return &name[0]; }
|
|
|
|
private:
|
|
void Init(u32 tid, const char *tname);
|
|
|
|
char name[128];
|
|
};
|
|
|
|
class Decorator : public __sanitizer::SanitizerCommonDecorator {
|
|
public:
|
|
Decorator() : SanitizerCommonDecorator() {}
|
|
const char *Access() { return Blue(); }
|
|
const char *Location() { return Green(); }
|
|
const char *Allocation() { return Magenta(); }
|
|
|
|
const char *ShadowByte(u8 byte) {
|
|
switch (byte) {
|
|
case kAsanHeapLeftRedzoneMagic:
|
|
case kAsanArrayCookieMagic:
|
|
return Red();
|
|
case kAsanHeapFreeMagic:
|
|
return Magenta();
|
|
case kAsanStackLeftRedzoneMagic:
|
|
case kAsanStackMidRedzoneMagic:
|
|
case kAsanStackRightRedzoneMagic:
|
|
return Red();
|
|
case kAsanStackAfterReturnMagic:
|
|
return Magenta();
|
|
case kAsanInitializationOrderMagic:
|
|
return Cyan();
|
|
case kAsanUserPoisonedMemoryMagic:
|
|
case kAsanContiguousContainerOOBMagic:
|
|
case kAsanAllocaLeftMagic:
|
|
case kAsanAllocaRightMagic:
|
|
return Blue();
|
|
case kAsanStackUseAfterScopeMagic:
|
|
return Magenta();
|
|
case kAsanGlobalRedzoneMagic:
|
|
return Red();
|
|
case kAsanInternalHeapMagic:
|
|
return Yellow();
|
|
case kAsanIntraObjectRedzone:
|
|
return Yellow();
|
|
default:
|
|
return Default();
|
|
}
|
|
}
|
|
};
|
|
|
|
enum ShadowKind : u8 {
|
|
kShadowKindLow,
|
|
kShadowKindGap,
|
|
kShadowKindHigh,
|
|
};
|
|
static const char *const ShadowNames[] = {"low shadow", "shadow gap",
|
|
"high shadow"};
|
|
|
|
struct ShadowAddressDescription {
|
|
uptr addr;
|
|
ShadowKind kind;
|
|
u8 shadow_byte;
|
|
|
|
void Print() const;
|
|
};
|
|
|
|
bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr);
|
|
bool DescribeAddressIfShadow(uptr addr);
|
|
|
|
enum AccessType {
|
|
kAccessTypeLeft,
|
|
kAccessTypeRight,
|
|
kAccessTypeInside,
|
|
kAccessTypeUnknown, // This means we have an AddressSanitizer bug!
|
|
};
|
|
|
|
struct ChunkAccess {
|
|
uptr bad_addr;
|
|
sptr offset;
|
|
uptr chunk_begin;
|
|
uptr chunk_size;
|
|
u32 user_requested_alignment : 12;
|
|
u32 access_type : 2;
|
|
u32 alloc_type : 2;
|
|
};
|
|
|
|
struct HeapAddressDescription {
|
|
uptr addr;
|
|
uptr alloc_tid;
|
|
uptr free_tid;
|
|
u32 alloc_stack_id;
|
|
u32 free_stack_id;
|
|
ChunkAccess chunk_access;
|
|
|
|
void Print() const;
|
|
};
|
|
|
|
bool GetHeapAddressInformation(uptr addr, uptr access_size,
|
|
HeapAddressDescription *descr);
|
|
bool DescribeAddressIfHeap(uptr addr, uptr access_size = 1);
|
|
|
|
struct StackAddressDescription {
|
|
uptr addr;
|
|
uptr tid;
|
|
uptr offset;
|
|
uptr frame_pc;
|
|
uptr access_size;
|
|
const char *frame_descr;
|
|
|
|
void Print() const;
|
|
};
|
|
|
|
bool GetStackAddressInformation(uptr addr, uptr access_size,
|
|
StackAddressDescription *descr);
|
|
|
|
struct WildAddressDescription {
|
|
uptr addr;
|
|
uptr access_size;
|
|
|
|
void Print() const;
|
|
};
|
|
|
|
struct GlobalAddressDescription {
|
|
uptr addr;
|
|
// Assume address is close to at most four globals.
|
|
static const int kMaxGlobals = 4;
|
|
__asan_global globals[kMaxGlobals];
|
|
u32 reg_sites[kMaxGlobals];
|
|
uptr access_size;
|
|
u8 size;
|
|
|
|
void Print(const char *bug_type = "") const;
|
|
|
|
// Returns true when this descriptions points inside the same global variable
|
|
// as other. Descriptions can have different address within the variable
|
|
bool PointsInsideTheSameVariable(const GlobalAddressDescription &other) const;
|
|
};
|
|
|
|
bool GetGlobalAddressInformation(uptr addr, uptr access_size,
|
|
GlobalAddressDescription *descr);
|
|
bool DescribeAddressIfGlobal(uptr addr, uptr access_size, const char *bug_type);
|
|
|
|
// General function to describe an address. Will try to describe the address as
|
|
// a shadow, global (variable), stack, or heap address.
|
|
// bug_type is optional and is used for checking if we're reporting an
|
|
// initialization-order-fiasco
|
|
// The proper access_size should be passed for stack, global, and heap
|
|
// addresses. Defaults to 1.
|
|
// Each of the *AddressDescription functions has its own Print() member, which
|
|
// may take access_size and bug_type parameters if needed.
|
|
void PrintAddressDescription(uptr addr, uptr access_size = 1,
|
|
const char *bug_type = "");
|
|
|
|
enum AddressKind {
|
|
kAddressKindWild,
|
|
kAddressKindShadow,
|
|
kAddressKindHeap,
|
|
kAddressKindStack,
|
|
kAddressKindGlobal,
|
|
};
|
|
|
|
class AddressDescription {
|
|
struct AddressDescriptionData {
|
|
AddressKind kind;
|
|
union {
|
|
ShadowAddressDescription shadow;
|
|
HeapAddressDescription heap;
|
|
StackAddressDescription stack;
|
|
GlobalAddressDescription global;
|
|
WildAddressDescription wild;
|
|
};
|
|
};
|
|
|
|
AddressDescriptionData data;
|
|
|
|
public:
|
|
AddressDescription() = default;
|
|
// shouldLockThreadRegistry allows us to skip locking if we're sure we already
|
|
// have done it.
|
|
explicit AddressDescription(uptr addr, bool shouldLockThreadRegistry = true)
|
|
: AddressDescription(addr, 1, shouldLockThreadRegistry) {}
|
|
AddressDescription(uptr addr, uptr access_size,
|
|
bool shouldLockThreadRegistry = true);
|
|
|
|
uptr Address() const {
|
|
switch (data.kind) {
|
|
case kAddressKindWild:
|
|
return data.wild.addr;
|
|
case kAddressKindShadow:
|
|
return data.shadow.addr;
|
|
case kAddressKindHeap:
|
|
return data.heap.addr;
|
|
case kAddressKindStack:
|
|
return data.stack.addr;
|
|
case kAddressKindGlobal:
|
|
return data.global.addr;
|
|
}
|
|
UNREACHABLE("AddressInformation kind is invalid");
|
|
}
|
|
void Print(const char *bug_descr = nullptr) const {
|
|
switch (data.kind) {
|
|
case kAddressKindWild:
|
|
data.wild.Print();
|
|
return;
|
|
case kAddressKindShadow:
|
|
return data.shadow.Print();
|
|
case kAddressKindHeap:
|
|
return data.heap.Print();
|
|
case kAddressKindStack:
|
|
return data.stack.Print();
|
|
case kAddressKindGlobal:
|
|
// initialization-order-fiasco has a special Print()
|
|
return data.global.Print(bug_descr);
|
|
}
|
|
UNREACHABLE("AddressInformation kind is invalid");
|
|
}
|
|
|
|
void StoreTo(AddressDescriptionData *dst) const { *dst = data; }
|
|
|
|
const ShadowAddressDescription *AsShadow() const {
|
|
return data.kind == kAddressKindShadow ? &data.shadow : nullptr;
|
|
}
|
|
const HeapAddressDescription *AsHeap() const {
|
|
return data.kind == kAddressKindHeap ? &data.heap : nullptr;
|
|
}
|
|
const StackAddressDescription *AsStack() const {
|
|
return data.kind == kAddressKindStack ? &data.stack : nullptr;
|
|
}
|
|
const GlobalAddressDescription *AsGlobal() const {
|
|
return data.kind == kAddressKindGlobal ? &data.global : nullptr;
|
|
}
|
|
};
|
|
|
|
} // namespace __asan
|
|
|
|
#endif // ASAN_DESCRIPTIONS_H
|