xref: /aosp_15_r20/external/scudo/standalone/report.cpp (revision 76559068c068bd27e82aff38fac3bfc865233bca)
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