1*76559068SAndroid Build Coastguard Worker //===-- report.cpp ----------------------------------------------*- C++ -*-===//
2*76559068SAndroid Build Coastguard Worker //
3*76559068SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*76559068SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information.
5*76559068SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*76559068SAndroid Build Coastguard Worker //
7*76559068SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
8*76559068SAndroid Build Coastguard Worker
9*76559068SAndroid Build Coastguard Worker #include "report.h"
10*76559068SAndroid Build Coastguard Worker
11*76559068SAndroid Build Coastguard Worker #include "atomic_helpers.h"
12*76559068SAndroid Build Coastguard Worker #include "string_utils.h"
13*76559068SAndroid Build Coastguard Worker
14*76559068SAndroid Build Coastguard Worker #include <stdarg.h>
15*76559068SAndroid Build Coastguard Worker
16*76559068SAndroid Build Coastguard Worker namespace scudo {
17*76559068SAndroid Build Coastguard Worker
18*76559068SAndroid Build Coastguard Worker class ScopedErrorReport {
19*76559068SAndroid Build Coastguard Worker public:
ScopedErrorReport()20*76559068SAndroid Build Coastguard Worker ScopedErrorReport() : Message() { Message.append("Scudo ERROR: "); }
append(const char * Format,...)21*76559068SAndroid Build Coastguard Worker void append(const char *Format, ...) {
22*76559068SAndroid Build Coastguard Worker va_list Args;
23*76559068SAndroid Build Coastguard Worker va_start(Args, Format);
24*76559068SAndroid Build Coastguard Worker Message.vappend(Format, Args);
25*76559068SAndroid Build Coastguard Worker va_end(Args);
26*76559068SAndroid Build Coastguard Worker }
~ScopedErrorReport()27*76559068SAndroid Build Coastguard Worker NORETURN ~ScopedErrorReport() { reportRawError(Message.data()); }
28*76559068SAndroid Build Coastguard Worker
29*76559068SAndroid Build Coastguard Worker private:
30*76559068SAndroid Build Coastguard Worker ScopedString Message;
31*76559068SAndroid Build Coastguard Worker };
32*76559068SAndroid Build Coastguard Worker
trap()33*76559068SAndroid Build Coastguard Worker inline void NORETURN trap() { __builtin_trap(); }
34*76559068SAndroid Build Coastguard Worker
35*76559068SAndroid Build Coastguard Worker // This could potentially be called recursively if a CHECK fails in the reports.
reportCheckFailed(const char * File,int Line,const char * Condition,u64 Value1,u64 Value2)36*76559068SAndroid Build Coastguard Worker void NORETURN reportCheckFailed(const char *File, int Line,
37*76559068SAndroid Build Coastguard Worker const char *Condition, u64 Value1, u64 Value2) {
38*76559068SAndroid Build Coastguard Worker static atomic_u32 NumberOfCalls;
39*76559068SAndroid Build Coastguard Worker if (atomic_fetch_add(&NumberOfCalls, 1, memory_order_relaxed) > 2) {
40*76559068SAndroid Build Coastguard Worker // TODO(kostyak): maybe sleep here?
41*76559068SAndroid Build Coastguard Worker trap();
42*76559068SAndroid Build Coastguard Worker }
43*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
44*76559068SAndroid Build Coastguard Worker Report.append("CHECK failed @ %s:%d %s ((u64)op1=%llu, (u64)op2=%llu)\n",
45*76559068SAndroid Build Coastguard Worker File, Line, Condition, Value1, Value2);
46*76559068SAndroid Build Coastguard Worker }
47*76559068SAndroid Build Coastguard Worker
48*76559068SAndroid Build Coastguard Worker // Generic string fatal error message.
reportError(const char * Message)49*76559068SAndroid Build Coastguard Worker void NORETURN reportError(const char *Message) {
50*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
51*76559068SAndroid Build Coastguard Worker Report.append("%s\n", Message);
52*76559068SAndroid Build Coastguard Worker }
53*76559068SAndroid Build Coastguard Worker
54*76559068SAndroid Build Coastguard Worker // Generic fatal error message without ScopedString.
reportRawError(const char * Message)55*76559068SAndroid Build Coastguard Worker void NORETURN reportRawError(const char *Message) {
56*76559068SAndroid Build Coastguard Worker outputRaw(Message);
57*76559068SAndroid Build Coastguard Worker setAbortMessage(Message);
58*76559068SAndroid Build Coastguard Worker die();
59*76559068SAndroid Build Coastguard Worker }
60*76559068SAndroid Build Coastguard Worker
reportInvalidFlag(const char * FlagType,const char * Value)61*76559068SAndroid Build Coastguard Worker void NORETURN reportInvalidFlag(const char *FlagType, const char *Value) {
62*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
63*76559068SAndroid Build Coastguard Worker Report.append("invalid value for %s option: '%s'\n", FlagType, Value);
64*76559068SAndroid Build Coastguard Worker }
65*76559068SAndroid Build Coastguard Worker
66*76559068SAndroid Build Coastguard Worker // The checksum of a chunk header is invalid. This could be caused by an
67*76559068SAndroid Build Coastguard Worker // {over,under}write of the header, a pointer that is not an actual chunk.
reportHeaderCorruption(void * Ptr)68*76559068SAndroid Build Coastguard Worker void NORETURN reportHeaderCorruption(void *Ptr) {
69*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
70*76559068SAndroid Build Coastguard Worker Report.append("corrupted chunk header at address %p\n", Ptr);
71*76559068SAndroid Build Coastguard Worker }
72*76559068SAndroid Build Coastguard Worker
73*76559068SAndroid Build Coastguard Worker // The allocator was compiled with parameters that conflict with field size
74*76559068SAndroid Build Coastguard Worker // requirements.
reportSanityCheckError(const char * Field)75*76559068SAndroid Build Coastguard Worker void NORETURN reportSanityCheckError(const char *Field) {
76*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
77*76559068SAndroid Build Coastguard Worker Report.append("maximum possible %s doesn't fit in header\n", Field);
78*76559068SAndroid Build Coastguard Worker }
79*76559068SAndroid Build Coastguard Worker
80*76559068SAndroid Build Coastguard Worker // We enforce a maximum alignment, to keep fields smaller and generally prevent
81*76559068SAndroid Build Coastguard Worker // integer overflows, or unexpected corner cases.
reportAlignmentTooBig(uptr Alignment,uptr MaxAlignment)82*76559068SAndroid Build Coastguard Worker void NORETURN reportAlignmentTooBig(uptr Alignment, uptr MaxAlignment) {
83*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
84*76559068SAndroid Build Coastguard Worker Report.append("invalid allocation alignment: %zu exceeds maximum supported "
85*76559068SAndroid Build Coastguard Worker "alignment of %zu\n",
86*76559068SAndroid Build Coastguard Worker Alignment, MaxAlignment);
87*76559068SAndroid Build Coastguard Worker }
88*76559068SAndroid Build Coastguard Worker
89*76559068SAndroid Build Coastguard Worker // See above, we also enforce a maximum size.
reportAllocationSizeTooBig(uptr UserSize,uptr TotalSize,uptr MaxSize)90*76559068SAndroid Build Coastguard Worker void NORETURN reportAllocationSizeTooBig(uptr UserSize, uptr TotalSize,
91*76559068SAndroid Build Coastguard Worker uptr MaxSize) {
92*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
93*76559068SAndroid Build Coastguard Worker Report.append("requested allocation size %zu (%zu after adjustments) exceeds "
94*76559068SAndroid Build Coastguard Worker "maximum supported size of %zu\n",
95*76559068SAndroid Build Coastguard Worker UserSize, TotalSize, MaxSize);
96*76559068SAndroid Build Coastguard Worker }
97*76559068SAndroid Build Coastguard Worker
reportOutOfBatchClass()98*76559068SAndroid Build Coastguard Worker void NORETURN reportOutOfBatchClass() {
99*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
100*76559068SAndroid Build Coastguard Worker Report.append("BatchClass region is used up, can't hold any free block\n");
101*76559068SAndroid Build Coastguard Worker }
102*76559068SAndroid Build Coastguard Worker
reportOutOfMemory(uptr RequestedSize)103*76559068SAndroid Build Coastguard Worker void NORETURN reportOutOfMemory(uptr RequestedSize) {
104*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
105*76559068SAndroid Build Coastguard Worker Report.append("out of memory trying to allocate %zu bytes\n", RequestedSize);
106*76559068SAndroid Build Coastguard Worker }
107*76559068SAndroid Build Coastguard Worker
stringifyAction(AllocatorAction Action)108*76559068SAndroid Build Coastguard Worker static const char *stringifyAction(AllocatorAction Action) {
109*76559068SAndroid Build Coastguard Worker switch (Action) {
110*76559068SAndroid Build Coastguard Worker case AllocatorAction::Recycling:
111*76559068SAndroid Build Coastguard Worker return "recycling";
112*76559068SAndroid Build Coastguard Worker case AllocatorAction::Deallocating:
113*76559068SAndroid Build Coastguard Worker return "deallocating";
114*76559068SAndroid Build Coastguard Worker case AllocatorAction::Reallocating:
115*76559068SAndroid Build Coastguard Worker return "reallocating";
116*76559068SAndroid Build Coastguard Worker case AllocatorAction::Sizing:
117*76559068SAndroid Build Coastguard Worker return "sizing";
118*76559068SAndroid Build Coastguard Worker }
119*76559068SAndroid Build Coastguard Worker return "<invalid action>";
120*76559068SAndroid Build Coastguard Worker }
121*76559068SAndroid Build Coastguard Worker
122*76559068SAndroid Build Coastguard Worker // The chunk is not in a state congruent with the operation we want to perform.
123*76559068SAndroid Build Coastguard Worker // This is usually the case with a double-free, a realloc of a freed pointer.
reportInvalidChunkState(AllocatorAction Action,void * Ptr)124*76559068SAndroid Build Coastguard Worker void NORETURN reportInvalidChunkState(AllocatorAction Action, void *Ptr) {
125*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
126*76559068SAndroid Build Coastguard Worker Report.append("invalid chunk state when %s address %p\n",
127*76559068SAndroid Build Coastguard Worker stringifyAction(Action), Ptr);
128*76559068SAndroid Build Coastguard Worker }
129*76559068SAndroid Build Coastguard Worker
reportMisalignedPointer(AllocatorAction Action,void * Ptr)130*76559068SAndroid Build Coastguard Worker void NORETURN reportMisalignedPointer(AllocatorAction Action, void *Ptr) {
131*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
132*76559068SAndroid Build Coastguard Worker Report.append("misaligned pointer when %s address %p\n",
133*76559068SAndroid Build Coastguard Worker stringifyAction(Action), Ptr);
134*76559068SAndroid Build Coastguard Worker }
135*76559068SAndroid Build Coastguard Worker
136*76559068SAndroid Build Coastguard Worker // The deallocation function used is at odds with the one used to allocate the
137*76559068SAndroid Build Coastguard Worker // chunk (eg: new[]/delete or malloc/delete, and so on).
reportDeallocTypeMismatch(AllocatorAction Action,void * Ptr,u8 TypeA,u8 TypeB)138*76559068SAndroid Build Coastguard Worker void NORETURN reportDeallocTypeMismatch(AllocatorAction Action, void *Ptr,
139*76559068SAndroid Build Coastguard Worker u8 TypeA, u8 TypeB) {
140*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
141*76559068SAndroid Build Coastguard Worker Report.append("allocation type mismatch when %s address %p (%d vs %d)\n",
142*76559068SAndroid Build Coastguard Worker stringifyAction(Action), Ptr, TypeA, TypeB);
143*76559068SAndroid Build Coastguard Worker }
144*76559068SAndroid Build Coastguard Worker
145*76559068SAndroid Build Coastguard Worker // The size specified to the delete operator does not match the one that was
146*76559068SAndroid Build Coastguard Worker // passed to new when allocating the chunk.
reportDeleteSizeMismatch(void * Ptr,uptr Size,uptr ExpectedSize)147*76559068SAndroid Build Coastguard Worker void NORETURN reportDeleteSizeMismatch(void *Ptr, uptr Size,
148*76559068SAndroid Build Coastguard Worker uptr ExpectedSize) {
149*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
150*76559068SAndroid Build Coastguard Worker Report.append(
151*76559068SAndroid Build Coastguard Worker "invalid sized delete when deallocating address %p (%zu vs %zu)\n", Ptr,
152*76559068SAndroid Build Coastguard Worker Size, ExpectedSize);
153*76559068SAndroid Build Coastguard Worker }
154*76559068SAndroid Build Coastguard Worker
reportAlignmentNotPowerOfTwo(uptr Alignment)155*76559068SAndroid Build Coastguard Worker void NORETURN reportAlignmentNotPowerOfTwo(uptr Alignment) {
156*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
157*76559068SAndroid Build Coastguard Worker Report.append(
158*76559068SAndroid Build Coastguard Worker "invalid allocation alignment: %zu, alignment must be a power of two\n",
159*76559068SAndroid Build Coastguard Worker Alignment);
160*76559068SAndroid Build Coastguard Worker }
161*76559068SAndroid Build Coastguard Worker
reportCallocOverflow(uptr Count,uptr Size)162*76559068SAndroid Build Coastguard Worker void NORETURN reportCallocOverflow(uptr Count, uptr Size) {
163*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
164*76559068SAndroid Build Coastguard Worker Report.append("calloc parameters overflow: count * size (%zu * %zu) cannot "
165*76559068SAndroid Build Coastguard Worker "be represented with type size_t\n",
166*76559068SAndroid Build Coastguard Worker Count, Size);
167*76559068SAndroid Build Coastguard Worker }
168*76559068SAndroid Build Coastguard Worker
reportInvalidPosixMemalignAlignment(uptr Alignment)169*76559068SAndroid Build Coastguard Worker void NORETURN reportInvalidPosixMemalignAlignment(uptr Alignment) {
170*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
171*76559068SAndroid Build Coastguard Worker Report.append(
172*76559068SAndroid Build Coastguard Worker "invalid alignment requested in posix_memalign: %zu, alignment must be a "
173*76559068SAndroid Build Coastguard Worker "power of two and a multiple of sizeof(void *) == %zu\n",
174*76559068SAndroid Build Coastguard Worker Alignment, sizeof(void *));
175*76559068SAndroid Build Coastguard Worker }
176*76559068SAndroid Build Coastguard Worker
reportPvallocOverflow(uptr Size)177*76559068SAndroid Build Coastguard Worker void NORETURN reportPvallocOverflow(uptr Size) {
178*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
179*76559068SAndroid Build Coastguard Worker Report.append("pvalloc parameters overflow: size %zu rounded up to system "
180*76559068SAndroid Build Coastguard Worker "page size %zu cannot be represented in type size_t\n",
181*76559068SAndroid Build Coastguard Worker Size, getPageSizeCached());
182*76559068SAndroid Build Coastguard Worker }
183*76559068SAndroid Build Coastguard Worker
reportInvalidAlignedAllocAlignment(uptr Alignment,uptr Size)184*76559068SAndroid Build Coastguard Worker void NORETURN reportInvalidAlignedAllocAlignment(uptr Alignment, uptr Size) {
185*76559068SAndroid Build Coastguard Worker ScopedErrorReport Report;
186*76559068SAndroid Build Coastguard Worker Report.append("invalid alignment requested in aligned_alloc: %zu, alignment "
187*76559068SAndroid Build Coastguard Worker "must be a power of two and the requested size %zu must be a "
188*76559068SAndroid Build Coastguard Worker "multiple of alignment\n",
189*76559068SAndroid Build Coastguard Worker Alignment, Size);
190*76559068SAndroid Build Coastguard Worker }
191*76559068SAndroid Build Coastguard Worker
192*76559068SAndroid Build Coastguard Worker } // namespace scudo
193