Path: blob/main/contrib/llvm-project/compiler-rt/lib/ubsan/ubsan_diag.h
35233 views
//===-- ubsan_diag.h --------------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Diagnostics emission for Clang's undefined behavior sanitizer.9//10//===----------------------------------------------------------------------===//11#ifndef UBSAN_DIAG_H12#define UBSAN_DIAG_H1314#include "ubsan_value.h"15#include "sanitizer_common/sanitizer_stacktrace.h"16#include "sanitizer_common/sanitizer_symbolizer.h"1718namespace __ubsan {1920SymbolizedStack *getSymbolizedLocation(uptr PC);2122inline SymbolizedStack *getCallerLocation(uptr CallerPC) {23CHECK(CallerPC);24uptr PC = StackTrace::GetPreviousInstructionPc(CallerPC);25return getSymbolizedLocation(PC);26}2728/// A location of some data within the program's address space.29typedef uptr MemoryLocation;3031/// \brief Location at which a diagnostic can be emitted. Either a32/// SourceLocation, a MemoryLocation, or a SymbolizedStack.33class Location {34public:35enum LocationKind { LK_Null, LK_Source, LK_Memory, LK_Symbolized };3637private:38LocationKind Kind;39// FIXME: In C++11, wrap these in an anonymous union.40SourceLocation SourceLoc;41MemoryLocation MemoryLoc;42const SymbolizedStack *SymbolizedLoc; // Not owned.4344public:45Location() : Kind(LK_Null) {}46Location(SourceLocation Loc) :47Kind(LK_Source), SourceLoc(Loc) {}48Location(MemoryLocation Loc) :49Kind(LK_Memory), MemoryLoc(Loc) {}50// SymbolizedStackHolder must outlive Location object.51Location(const SymbolizedStackHolder &Stack) :52Kind(LK_Symbolized), SymbolizedLoc(Stack.get()) {}5354LocationKind getKind() const { return Kind; }5556bool isSourceLocation() const { return Kind == LK_Source; }57bool isMemoryLocation() const { return Kind == LK_Memory; }58bool isSymbolizedStack() const { return Kind == LK_Symbolized; }5960SourceLocation getSourceLocation() const {61CHECK(isSourceLocation());62return SourceLoc;63}64MemoryLocation getMemoryLocation() const {65CHECK(isMemoryLocation());66return MemoryLoc;67}68const SymbolizedStack *getSymbolizedStack() const {69CHECK(isSymbolizedStack());70return SymbolizedLoc;71}72};7374/// A diagnostic severity level.75enum DiagLevel {76DL_Error, ///< An error.77DL_Note ///< A note, attached to a prior diagnostic.78};7980/// \brief Annotation for a range of locations in a diagnostic.81class Range {82Location Start, End;83const char *Text;8485public:86Range() : Start(), End(), Text() {}87Range(MemoryLocation Start, MemoryLocation End, const char *Text)88: Start(Start), End(End), Text(Text) {}89Location getStart() const { return Start; }90Location getEnd() const { return End; }91const char *getText() const { return Text; }92};9394/// \brief A C++ type name. Really just a strong typedef for 'const char*'.95class TypeName {96const char *Name;97public:98TypeName(const char *Name) : Name(Name) {}99const char *getName() const { return Name; }100};101102enum class ErrorType {103#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) Name,104#include "ubsan_checks.inc"105#undef UBSAN_CHECK106};107108/// \brief Representation of an in-flight diagnostic.109///110/// Temporary \c Diag instances are created by the handler routines to111/// accumulate arguments for a diagnostic. The destructor emits the diagnostic112/// message.113class Diag {114/// The location at which the problem occurred.115Location Loc;116117/// The diagnostic level.118DiagLevel Level;119120/// The error type.121ErrorType ET;122123/// The message which will be emitted, with %0, %1, ... placeholders for124/// arguments.125const char *Message;126127public:128/// Kinds of arguments, corresponding to members of \c Arg's union.129enum ArgKind {130AK_String, ///< A string argument, displayed as-is.131AK_TypeName,///< A C++ type name, possibly demangled before display.132AK_UInt, ///< An unsigned integer argument.133AK_SInt, ///< A signed integer argument.134AK_Float, ///< A floating-point argument.135AK_Pointer ///< A pointer argument, displayed in hexadecimal.136};137138/// An individual diagnostic message argument.139struct Arg {140Arg() {}141Arg(const char *String) : Kind(AK_String), String(String) {}142Arg(TypeName TN) : Kind(AK_TypeName), String(TN.getName()) {}143Arg(UIntMax UInt) : Kind(AK_UInt), UInt(UInt) {}144Arg(SIntMax SInt) : Kind(AK_SInt), SInt(SInt) {}145Arg(FloatMax Float) : Kind(AK_Float), Float(Float) {}146Arg(const void *Pointer) : Kind(AK_Pointer), Pointer(Pointer) {}147148ArgKind Kind;149union {150const char *String;151UIntMax UInt;152SIntMax SInt;153FloatMax Float;154const void *Pointer;155};156};157158private:159static const unsigned MaxArgs = 8;160static const unsigned MaxRanges = 1;161162/// The arguments which have been added to this diagnostic so far.163Arg Args[MaxArgs];164unsigned NumArgs;165166/// The ranges which have been added to this diagnostic so far.167Range Ranges[MaxRanges];168unsigned NumRanges;169170Diag &AddArg(Arg A) {171CHECK(NumArgs != MaxArgs);172Args[NumArgs++] = A;173return *this;174}175176Diag &AddRange(Range A) {177CHECK(NumRanges != MaxRanges);178Ranges[NumRanges++] = A;179return *this;180}181182/// \c Diag objects are not copyable.183Diag(const Diag &); // NOT IMPLEMENTED184Diag &operator=(const Diag &);185186public:187Diag(Location Loc, DiagLevel Level, ErrorType ET, const char *Message)188: Loc(Loc), Level(Level), ET(ET), Message(Message), NumArgs(0),189NumRanges(0) {}190~Diag();191192Diag &operator<<(const char *Str) { return AddArg(Str); }193Diag &operator<<(TypeName TN) { return AddArg(TN); }194Diag &operator<<(unsigned long long V) { return AddArg(UIntMax(V)); }195Diag &operator<<(const void *V) { return AddArg(V); }196Diag &operator<<(const TypeDescriptor &V);197Diag &operator<<(const Value &V);198Diag &operator<<(const Range &R) { return AddRange(R); }199};200201struct ReportOptions {202// If FromUnrecoverableHandler is specified, UBSan runtime handler is not203// expected to return.204bool FromUnrecoverableHandler;205/// pc/bp are used to unwind the stack trace.206uptr pc;207uptr bp;208};209210bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET);211212#define GET_REPORT_OPTIONS(unrecoverable_handler) \213GET_CALLER_PC_BP; \214ReportOptions Opts = {unrecoverable_handler, pc, bp}215216/// \brief Instantiate this class before printing diagnostics in the error217/// report. This class ensures that reports from different threads and from218/// different sanitizers won't be mixed.219class ScopedReport {220struct Initializer {221Initializer();222};223Initializer initializer_;224ScopedErrorReportLock report_lock_;225226ReportOptions Opts;227Location SummaryLoc;228ErrorType Type;229230public:231ScopedReport(ReportOptions Opts, Location SummaryLoc, ErrorType Type);232~ScopedReport();233234static void CheckLocked() { ScopedErrorReportLock::CheckLocked(); }235};236237void InitializeSuppressions();238bool IsVptrCheckSuppressed(const char *TypeName);239// Sometimes UBSan runtime can know filename from handlers arguments, even if240// debug info is missing.241bool IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename);242243} // namespace __ubsan244245#endif // UBSAN_DIAG_H246247248