]>
Commit | Line | Data |
---|---|---|
de5a5fa1 MP |
1 | //===-- ubsan_handlers.cc -------------------------------------------------===// |
2 | // | |
3 | // This file is distributed under the University of Illinois Open Source | |
4 | // License. See LICENSE.TXT for details. | |
5 | // | |
6 | //===----------------------------------------------------------------------===// | |
7 | // | |
8 | // Error logging entry points for the UBSan runtime. | |
9 | // | |
10 | //===----------------------------------------------------------------------===// | |
11 | ||
696d846a MO |
12 | #include "ubsan_platform.h" |
13 | #if CAN_SANITIZE_UB | |
de5a5fa1 MP |
14 | #include "ubsan_handlers.h" |
15 | #include "ubsan_diag.h" | |
16 | ||
17 | #include "sanitizer_common/sanitizer_common.h" | |
18 | ||
19 | using namespace __sanitizer; | |
20 | using namespace __ubsan; | |
21 | ||
10189819 MO |
22 | namespace __ubsan { |
23 | bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) { | |
24 | // We are not allowed to skip error report: if we are in unrecoverable | |
25 | // handler, we have to terminate the program right now, and therefore | |
26 | // have to print some diagnostic. | |
27 | // | |
28 | // Even if source location is disabled, it doesn't mean that we have | |
29 | // already report an error to the user: some concurrently running | |
30 | // thread could have acquired it, but not yet printed the report. | |
31 | if (Opts.FromUnrecoverableHandler) | |
32 | return false; | |
33 | return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename()); | |
866e32ad KS |
34 | } |
35 | ||
c5be964a | 36 | const char *TypeCheckKinds[] = { |
de5a5fa1 | 37 | "load of", "store to", "reference binding to", "member access within", |
c5be964a | 38 | "member call on", "constructor call on", "downcast of", "downcast of", |
5d3805fc | 39 | "upcast of", "cast to virtual base of", "_Nonnull binding to"}; |
de5a5fa1 MP |
40 | } |
41 | ||
42 | static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, | |
696d846a | 43 | ReportOptions Opts) { |
de5a5fa1 | 44 | Location Loc = Data->Loc.acquire(); |
10189819 | 45 | |
5d3805fc | 46 | uptr Alignment = (uptr)1 << Data->LogAlignment; |
10189819 MO |
47 | ErrorType ET; |
48 | if (!Pointer) | |
49 | ET = ErrorType::NullPointerUse; | |
5d3805fc | 50 | else if (Pointer & (Alignment - 1)) |
10189819 MO |
51 | ET = ErrorType::MisalignedPointerUse; |
52 | else | |
53 | ET = ErrorType::InsufficientObjectSize; | |
54 | ||
55 | // Use the SourceLocation from Data to track deduplication, even if it's | |
56 | // invalid. | |
57 | if (ignoreReport(Loc.getSourceLocation(), Opts, ET)) | |
de5a5fa1 | 58 | return; |
866e32ad | 59 | |
696d846a MO |
60 | SymbolizedStackHolder FallbackLoc; |
61 | if (Data->Loc.isInvalid()) { | |
62 | FallbackLoc.reset(getCallerLocation(Opts.pc)); | |
de5a5fa1 | 63 | Loc = FallbackLoc; |
696d846a | 64 | } |
de5a5fa1 | 65 | |
10189819 | 66 | ScopedReport R(Opts, Loc, ET); |
866e32ad | 67 | |
10189819 MO |
68 | switch (ET) { |
69 | case ErrorType::NullPointerUse: | |
de5a5fa1 | 70 | Diag(Loc, DL_Error, "%0 null pointer of type %1") |
10189819 MO |
71 | << TypeCheckKinds[Data->TypeCheckKind] << Data->Type; |
72 | break; | |
73 | case ErrorType::MisalignedPointerUse: | |
de5a5fa1 MP |
74 | Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, " |
75 | "which requires %2 byte alignment") | |
5d3805fc JJ |
76 | << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Alignment |
77 | << Data->Type; | |
10189819 MO |
78 | break; |
79 | case ErrorType::InsufficientObjectSize: | |
de5a5fa1 MP |
80 | Diag(Loc, DL_Error, "%0 address %1 with insufficient space " |
81 | "for an object of type %2") | |
10189819 MO |
82 | << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Data->Type; |
83 | break; | |
84 | default: | |
85 | UNREACHABLE("unexpected error type!"); | |
696d846a | 86 | } |
10189819 | 87 | |
de5a5fa1 MP |
88 | if (Pointer) |
89 | Diag(Pointer, DL_Note, "pointer points here"); | |
90 | } | |
866e32ad | 91 | |
5d3805fc JJ |
92 | void __ubsan::__ubsan_handle_type_mismatch_v1(TypeMismatchData *Data, |
93 | ValueHandle Pointer) { | |
866e32ad | 94 | GET_REPORT_OPTIONS(false); |
696d846a | 95 | handleTypeMismatchImpl(Data, Pointer, Opts); |
de5a5fa1 | 96 | } |
5d3805fc JJ |
97 | void __ubsan::__ubsan_handle_type_mismatch_v1_abort(TypeMismatchData *Data, |
98 | ValueHandle Pointer) { | |
866e32ad | 99 | GET_REPORT_OPTIONS(true); |
696d846a | 100 | handleTypeMismatchImpl(Data, Pointer, Opts); |
de5a5fa1 MP |
101 | Die(); |
102 | } | |
103 | ||
104 | /// \brief Common diagnostic emission for various forms of integer overflow. | |
866e32ad KS |
105 | template <typename T> |
106 | static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS, | |
107 | const char *Operator, T RHS, | |
108 | ReportOptions Opts) { | |
de5a5fa1 | 109 | SourceLocation Loc = Data->Loc.acquire(); |
10189819 MO |
110 | bool IsSigned = Data->Type.isSignedIntegerTy(); |
111 | ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow | |
112 | : ErrorType::UnsignedIntegerOverflow; | |
113 | ||
114 | if (ignoreReport(Loc, Opts, ET)) | |
de5a5fa1 MP |
115 | return; |
116 | ||
10189819 | 117 | ScopedReport R(Opts, Loc, ET); |
866e32ad | 118 | |
de5a5fa1 MP |
119 | Diag(Loc, DL_Error, "%0 integer overflow: " |
120 | "%1 %2 %3 cannot be represented in type %4") | |
696d846a | 121 | << (IsSigned ? "signed" : "unsigned") |
de5a5fa1 MP |
122 | << Value(Data->Type, LHS) << Operator << RHS << Data->Type; |
123 | } | |
124 | ||
10189819 | 125 | #define UBSAN_OVERFLOW_HANDLER(handler_name, op, unrecoverable) \ |
866e32ad KS |
126 | void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \ |
127 | ValueHandle RHS) { \ | |
10189819 | 128 | GET_REPORT_OPTIONS(unrecoverable); \ |
866e32ad | 129 | handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \ |
10189819 MO |
130 | if (unrecoverable) \ |
131 | Die(); \ | |
866e32ad | 132 | } |
de5a5fa1 | 133 | |
866e32ad KS |
134 | UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false) |
135 | UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true) | |
136 | UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false) | |
137 | UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true) | |
138 | UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false) | |
139 | UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true) | |
de5a5fa1 | 140 | |
866e32ad KS |
141 | static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal, |
142 | ReportOptions Opts) { | |
de5a5fa1 | 143 | SourceLocation Loc = Data->Loc.acquire(); |
10189819 MO |
144 | bool IsSigned = Data->Type.isSignedIntegerTy(); |
145 | ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow | |
146 | : ErrorType::UnsignedIntegerOverflow; | |
147 | ||
148 | if (ignoreReport(Loc, Opts, ET)) | |
de5a5fa1 MP |
149 | return; |
150 | ||
10189819 | 151 | ScopedReport R(Opts, Loc, ET); |
866e32ad | 152 | |
696d846a | 153 | if (IsSigned) |
de5a5fa1 MP |
154 | Diag(Loc, DL_Error, |
155 | "negation of %0 cannot be represented in type %1; " | |
156 | "cast to an unsigned type to negate this value to itself") | |
696d846a | 157 | << Value(Data->Type, OldVal) << Data->Type; |
de5a5fa1 | 158 | else |
696d846a MO |
159 | Diag(Loc, DL_Error, "negation of %0 cannot be represented in type %1") |
160 | << Value(Data->Type, OldVal) << Data->Type; | |
de5a5fa1 | 161 | } |
866e32ad KS |
162 | |
163 | void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data, | |
164 | ValueHandle OldVal) { | |
165 | GET_REPORT_OPTIONS(false); | |
166 | handleNegateOverflowImpl(Data, OldVal, Opts); | |
167 | } | |
de5a5fa1 MP |
168 | void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data, |
169 | ValueHandle OldVal) { | |
866e32ad KS |
170 | GET_REPORT_OPTIONS(true); |
171 | handleNegateOverflowImpl(Data, OldVal, Opts); | |
de5a5fa1 MP |
172 | Die(); |
173 | } | |
174 | ||
866e32ad KS |
175 | static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS, |
176 | ValueHandle RHS, ReportOptions Opts) { | |
de5a5fa1 | 177 | SourceLocation Loc = Data->Loc.acquire(); |
10189819 MO |
178 | Value LHSVal(Data->Type, LHS); |
179 | Value RHSVal(Data->Type, RHS); | |
180 | ||
181 | ErrorType ET; | |
182 | if (RHSVal.isMinusOne()) | |
183 | ET = ErrorType::SignedIntegerOverflow; | |
184 | else if (Data->Type.isIntegerTy()) | |
185 | ET = ErrorType::IntegerDivideByZero; | |
186 | else | |
187 | ET = ErrorType::FloatDivideByZero; | |
188 | ||
189 | if (ignoreReport(Loc, Opts, ET)) | |
de5a5fa1 MP |
190 | return; |
191 | ||
10189819 | 192 | ScopedReport R(Opts, Loc, ET); |
866e32ad | 193 | |
10189819 MO |
194 | switch (ET) { |
195 | case ErrorType::SignedIntegerOverflow: | |
196 | Diag(Loc, DL_Error, "division of %0 by -1 cannot be represented in type %1") | |
197 | << LHSVal << Data->Type; | |
198 | break; | |
199 | default: | |
de5a5fa1 | 200 | Diag(Loc, DL_Error, "division by zero"); |
10189819 | 201 | break; |
696d846a | 202 | } |
de5a5fa1 | 203 | } |
866e32ad KS |
204 | |
205 | void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data, | |
206 | ValueHandle LHS, ValueHandle RHS) { | |
207 | GET_REPORT_OPTIONS(false); | |
208 | handleDivremOverflowImpl(Data, LHS, RHS, Opts); | |
209 | } | |
de5a5fa1 MP |
210 | void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data, |
211 | ValueHandle LHS, | |
212 | ValueHandle RHS) { | |
866e32ad KS |
213 | GET_REPORT_OPTIONS(true); |
214 | handleDivremOverflowImpl(Data, LHS, RHS, Opts); | |
de5a5fa1 MP |
215 | Die(); |
216 | } | |
217 | ||
866e32ad KS |
218 | static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data, |
219 | ValueHandle LHS, ValueHandle RHS, | |
220 | ReportOptions Opts) { | |
de5a5fa1 | 221 | SourceLocation Loc = Data->Loc.acquire(); |
10189819 MO |
222 | Value LHSVal(Data->LHSType, LHS); |
223 | Value RHSVal(Data->RHSType, RHS); | |
224 | ||
225 | ErrorType ET; | |
226 | if (RHSVal.isNegative() || | |
227 | RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth()) | |
228 | ET = ErrorType::InvalidShiftExponent; | |
229 | else | |
230 | ET = ErrorType::InvalidShiftBase; | |
231 | ||
232 | if (ignoreReport(Loc, Opts, ET)) | |
de5a5fa1 MP |
233 | return; |
234 | ||
10189819 | 235 | ScopedReport R(Opts, Loc, ET); |
866e32ad | 236 | |
10189819 MO |
237 | if (ET == ErrorType::InvalidShiftExponent) { |
238 | if (RHSVal.isNegative()) | |
239 | Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal; | |
240 | else | |
241 | Diag(Loc, DL_Error, "shift exponent %0 is too large for %1-bit type %2") | |
242 | << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType; | |
696d846a | 243 | } else { |
10189819 MO |
244 | if (LHSVal.isNegative()) |
245 | Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal; | |
246 | else | |
247 | Diag(Loc, DL_Error, | |
248 | "left shift of %0 by %1 places cannot be represented in type %2") | |
249 | << LHSVal << RHSVal << Data->LHSType; | |
696d846a | 250 | } |
de5a5fa1 | 251 | } |
866e32ad KS |
252 | |
253 | void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data, | |
254 | ValueHandle LHS, | |
255 | ValueHandle RHS) { | |
256 | GET_REPORT_OPTIONS(false); | |
257 | handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); | |
258 | } | |
de5a5fa1 MP |
259 | void __ubsan::__ubsan_handle_shift_out_of_bounds_abort( |
260 | ShiftOutOfBoundsData *Data, | |
261 | ValueHandle LHS, | |
262 | ValueHandle RHS) { | |
866e32ad KS |
263 | GET_REPORT_OPTIONS(true); |
264 | handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); | |
de5a5fa1 MP |
265 | Die(); |
266 | } | |
267 | ||
866e32ad KS |
268 | static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index, |
269 | ReportOptions Opts) { | |
de5a5fa1 | 270 | SourceLocation Loc = Data->Loc.acquire(); |
10189819 MO |
271 | ErrorType ET = ErrorType::OutOfBoundsIndex; |
272 | ||
273 | if (ignoreReport(Loc, Opts, ET)) | |
de5a5fa1 MP |
274 | return; |
275 | ||
10189819 | 276 | ScopedReport R(Opts, Loc, ET); |
866e32ad | 277 | |
de5a5fa1 MP |
278 | Value IndexVal(Data->IndexType, Index); |
279 | Diag(Loc, DL_Error, "index %0 out of bounds for type %1") | |
280 | << IndexVal << Data->ArrayType; | |
281 | } | |
866e32ad KS |
282 | |
283 | void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data, | |
284 | ValueHandle Index) { | |
285 | GET_REPORT_OPTIONS(false); | |
286 | handleOutOfBoundsImpl(Data, Index, Opts); | |
287 | } | |
de5a5fa1 MP |
288 | void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data, |
289 | ValueHandle Index) { | |
866e32ad KS |
290 | GET_REPORT_OPTIONS(true); |
291 | handleOutOfBoundsImpl(Data, Index, Opts); | |
de5a5fa1 MP |
292 | Die(); |
293 | } | |
294 | ||
866e32ad KS |
295 | static void handleBuiltinUnreachableImpl(UnreachableData *Data, |
296 | ReportOptions Opts) { | |
696d846a | 297 | ScopedReport R(Opts, Data->Loc, ErrorType::UnreachableCall); |
de5a5fa1 | 298 | Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call"); |
866e32ad KS |
299 | } |
300 | ||
301 | void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) { | |
302 | GET_REPORT_OPTIONS(true); | |
303 | handleBuiltinUnreachableImpl(Data, Opts); | |
de5a5fa1 MP |
304 | Die(); |
305 | } | |
306 | ||
866e32ad | 307 | static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) { |
696d846a | 308 | ScopedReport R(Opts, Data->Loc, ErrorType::MissingReturn); |
de5a5fa1 MP |
309 | Diag(Data->Loc, DL_Error, |
310 | "execution reached the end of a value-returning function " | |
311 | "without returning a value"); | |
866e32ad KS |
312 | } |
313 | ||
314 | void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) { | |
315 | GET_REPORT_OPTIONS(true); | |
316 | handleMissingReturnImpl(Data, Opts); | |
de5a5fa1 MP |
317 | Die(); |
318 | } | |
319 | ||
866e32ad KS |
320 | static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound, |
321 | ReportOptions Opts) { | |
de5a5fa1 | 322 | SourceLocation Loc = Data->Loc.acquire(); |
10189819 MO |
323 | ErrorType ET = ErrorType::NonPositiveVLAIndex; |
324 | ||
325 | if (ignoreReport(Loc, Opts, ET)) | |
de5a5fa1 MP |
326 | return; |
327 | ||
10189819 | 328 | ScopedReport R(Opts, Loc, ET); |
866e32ad | 329 | |
de5a5fa1 MP |
330 | Diag(Loc, DL_Error, "variable length array bound evaluates to " |
331 | "non-positive value %0") | |
332 | << Value(Data->Type, Bound); | |
333 | } | |
866e32ad KS |
334 | |
335 | void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data, | |
336 | ValueHandle Bound) { | |
337 | GET_REPORT_OPTIONS(false); | |
338 | handleVLABoundNotPositive(Data, Bound, Opts); | |
339 | } | |
de5a5fa1 | 340 | void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data, |
866e32ad KS |
341 | ValueHandle Bound) { |
342 | GET_REPORT_OPTIONS(true); | |
343 | handleVLABoundNotPositive(Data, Bound, Opts); | |
de5a5fa1 MP |
344 | Die(); |
345 | } | |
346 | ||
696d846a MO |
347 | static bool looksLikeFloatCastOverflowDataV1(void *Data) { |
348 | // First field is either a pointer to filename or a pointer to a | |
349 | // TypeDescriptor. | |
350 | u8 *FilenameOrTypeDescriptor; | |
351 | internal_memcpy(&FilenameOrTypeDescriptor, Data, | |
352 | sizeof(FilenameOrTypeDescriptor)); | |
353 | ||
354 | // Heuristic: For float_cast_overflow, the TypeKind will be either TK_Integer | |
355 | // (0x0), TK_Float (0x1) or TK_Unknown (0xff). If both types are known, | |
356 | // adding both bytes will be 0 or 1 (for BE or LE). If it were a filename, | |
357 | // adding two printable characters will not yield such a value. Otherwise, | |
358 | // if one of them is 0xff, this is most likely TK_Unknown type descriptor. | |
359 | u16 MaybeFromTypeKind = | |
360 | FilenameOrTypeDescriptor[0] + FilenameOrTypeDescriptor[1]; | |
361 | return MaybeFromTypeKind < 2 || FilenameOrTypeDescriptor[0] == 0xff || | |
362 | FilenameOrTypeDescriptor[1] == 0xff; | |
363 | } | |
364 | ||
365 | static void handleFloatCastOverflow(void *DataPtr, ValueHandle From, | |
366 | ReportOptions Opts) { | |
367 | SymbolizedStackHolder CallerLoc; | |
368 | Location Loc; | |
369 | const TypeDescriptor *FromType, *ToType; | |
10189819 | 370 | ErrorType ET = ErrorType::FloatCastOverflow; |
696d846a MO |
371 | |
372 | if (looksLikeFloatCastOverflowDataV1(DataPtr)) { | |
373 | auto Data = reinterpret_cast<FloatCastOverflowData *>(DataPtr); | |
374 | CallerLoc.reset(getCallerLocation(Opts.pc)); | |
375 | Loc = CallerLoc; | |
376 | FromType = &Data->FromType; | |
377 | ToType = &Data->ToType; | |
378 | } else { | |
379 | auto Data = reinterpret_cast<FloatCastOverflowDataV2 *>(DataPtr); | |
380 | SourceLocation SLoc = Data->Loc.acquire(); | |
10189819 | 381 | if (ignoreReport(SLoc, Opts, ET)) |
696d846a MO |
382 | return; |
383 | Loc = SLoc; | |
384 | FromType = &Data->FromType; | |
385 | ToType = &Data->ToType; | |
386 | } | |
387 | ||
10189819 | 388 | ScopedReport R(Opts, Loc, ET); |
866e32ad KS |
389 | |
390 | Diag(Loc, DL_Error, | |
5d3805fc | 391 | "%0 is outside the range of representable values of type %2") |
696d846a | 392 | << Value(*FromType, From) << *FromType << *ToType; |
de5a5fa1 | 393 | } |
866e32ad | 394 | |
696d846a | 395 | void __ubsan::__ubsan_handle_float_cast_overflow(void *Data, ValueHandle From) { |
866e32ad KS |
396 | GET_REPORT_OPTIONS(false); |
397 | handleFloatCastOverflow(Data, From, Opts); | |
398 | } | |
696d846a MO |
399 | void __ubsan::__ubsan_handle_float_cast_overflow_abort(void *Data, |
400 | ValueHandle From) { | |
866e32ad KS |
401 | GET_REPORT_OPTIONS(true); |
402 | handleFloatCastOverflow(Data, From, Opts); | |
de5a5fa1 MP |
403 | Die(); |
404 | } | |
405 | ||
866e32ad KS |
406 | static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val, |
407 | ReportOptions Opts) { | |
df77f0e4 | 408 | SourceLocation Loc = Data->Loc.acquire(); |
696d846a MO |
409 | // This check could be more precise if we used different handlers for |
410 | // -fsanitize=bool and -fsanitize=enum. | |
5d3805fc JJ |
411 | bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")) || |
412 | (0 == internal_strncmp(Data->Type.getTypeName(), "'BOOL'", 6)); | |
10189819 MO |
413 | ErrorType ET = |
414 | IsBool ? ErrorType::InvalidBoolLoad : ErrorType::InvalidEnumLoad; | |
415 | ||
416 | if (ignoreReport(Loc, Opts, ET)) | |
417 | return; | |
418 | ||
419 | ScopedReport R(Opts, Loc, ET); | |
866e32ad | 420 | |
df77f0e4 | 421 | Diag(Loc, DL_Error, |
de5a5fa1 MP |
422 | "load of value %0, which is not a valid value for type %1") |
423 | << Value(Data->Type, Val) << Data->Type; | |
424 | } | |
866e32ad KS |
425 | |
426 | void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data, | |
427 | ValueHandle Val) { | |
428 | GET_REPORT_OPTIONS(false); | |
429 | handleLoadInvalidValue(Data, Val, Opts); | |
430 | } | |
de5a5fa1 MP |
431 | void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data, |
432 | ValueHandle Val) { | |
866e32ad KS |
433 | GET_REPORT_OPTIONS(true); |
434 | handleLoadInvalidValue(Data, Val, Opts); | |
df77f0e4 KS |
435 | Die(); |
436 | } | |
437 | ||
5d3805fc JJ |
438 | static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) { |
439 | SourceLocation Loc = Data->Loc.acquire(); | |
440 | ErrorType ET = ErrorType::InvalidBuiltin; | |
441 | ||
442 | if (ignoreReport(Loc, Opts, ET)) | |
443 | return; | |
444 | ||
445 | ScopedReport R(Opts, Loc, ET); | |
446 | ||
447 | Diag(Loc, DL_Error, | |
448 | "passing zero to %0, which is not a valid argument") | |
449 | << ((Data->Kind == BCK_CTZPassedZero) ? "ctz()" : "clz()"); | |
450 | } | |
451 | ||
452 | void __ubsan::__ubsan_handle_invalid_builtin(InvalidBuiltinData *Data) { | |
453 | GET_REPORT_OPTIONS(true); | |
454 | handleInvalidBuiltin(Data, Opts); | |
455 | } | |
456 | void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) { | |
457 | GET_REPORT_OPTIONS(true); | |
458 | handleInvalidBuiltin(Data, Opts); | |
459 | Die(); | |
460 | } | |
461 | ||
866e32ad KS |
462 | static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data, |
463 | ValueHandle Function, | |
464 | ReportOptions Opts) { | |
696d846a | 465 | SourceLocation CallLoc = Data->Loc.acquire(); |
10189819 MO |
466 | ErrorType ET = ErrorType::FunctionTypeMismatch; |
467 | ||
468 | if (ignoreReport(CallLoc, Opts, ET)) | |
696d846a | 469 | return; |
df77f0e4 | 470 | |
10189819 | 471 | ScopedReport R(Opts, CallLoc, ET); |
df77f0e4 | 472 | |
696d846a MO |
473 | SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); |
474 | const char *FName = FLoc.get()->info.function; | |
475 | if (!FName) | |
476 | FName = "(unknown)"; | |
866e32ad | 477 | |
696d846a | 478 | Diag(CallLoc, DL_Error, |
df77f0e4 | 479 | "call to function %0 through pointer to incorrect function type %1") |
696d846a MO |
480 | << FName << Data->Type; |
481 | Diag(FLoc, DL_Note, "%0 defined here") << FName; | |
df77f0e4 KS |
482 | } |
483 | ||
866e32ad KS |
484 | void |
485 | __ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data, | |
486 | ValueHandle Function) { | |
487 | GET_REPORT_OPTIONS(false); | |
488 | handleFunctionTypeMismatch(Data, Function, Opts); | |
489 | } | |
490 | ||
df77f0e4 | 491 | void __ubsan::__ubsan_handle_function_type_mismatch_abort( |
866e32ad KS |
492 | FunctionTypeMismatchData *Data, ValueHandle Function) { |
493 | GET_REPORT_OPTIONS(true); | |
494 | handleFunctionTypeMismatch(Data, Function, Opts); | |
de5a5fa1 MP |
495 | Die(); |
496 | } | |
126edc3f | 497 | |
5d3805fc JJ |
498 | static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr, |
499 | ReportOptions Opts, bool IsAttr) { | |
500 | if (!LocPtr) | |
501 | UNREACHABLE("source location pointer is null!"); | |
502 | ||
503 | SourceLocation Loc = LocPtr->acquire(); | |
10189819 MO |
504 | ErrorType ET = ErrorType::InvalidNullReturn; |
505 | ||
506 | if (ignoreReport(Loc, Opts, ET)) | |
126edc3f JJ |
507 | return; |
508 | ||
10189819 | 509 | ScopedReport R(Opts, Loc, ET); |
866e32ad | 510 | |
126edc3f JJ |
511 | Diag(Loc, DL_Error, "null pointer returned from function declared to never " |
512 | "return null"); | |
513 | if (!Data->AttrLoc.isInvalid()) | |
5d3805fc JJ |
514 | Diag(Data->AttrLoc, DL_Note, "%0 specified here") |
515 | << (IsAttr ? "returns_nonnull attribute" | |
516 | : "_Nonnull return type annotation"); | |
517 | } | |
518 | ||
519 | void __ubsan::__ubsan_handle_nonnull_return_v1(NonNullReturnData *Data, | |
520 | SourceLocation *LocPtr) { | |
521 | GET_REPORT_OPTIONS(false); | |
522 | handleNonNullReturn(Data, LocPtr, Opts, true); | |
126edc3f JJ |
523 | } |
524 | ||
5d3805fc JJ |
525 | void __ubsan::__ubsan_handle_nonnull_return_v1_abort(NonNullReturnData *Data, |
526 | SourceLocation *LocPtr) { | |
527 | GET_REPORT_OPTIONS(true); | |
528 | handleNonNullReturn(Data, LocPtr, Opts, true); | |
529 | Die(); | |
530 | } | |
531 | ||
532 | void __ubsan::__ubsan_handle_nullability_return_v1(NonNullReturnData *Data, | |
533 | SourceLocation *LocPtr) { | |
866e32ad | 534 | GET_REPORT_OPTIONS(false); |
5d3805fc | 535 | handleNonNullReturn(Data, LocPtr, Opts, false); |
126edc3f JJ |
536 | } |
537 | ||
5d3805fc JJ |
538 | void __ubsan::__ubsan_handle_nullability_return_v1_abort( |
539 | NonNullReturnData *Data, SourceLocation *LocPtr) { | |
866e32ad | 540 | GET_REPORT_OPTIONS(true); |
5d3805fc | 541 | handleNonNullReturn(Data, LocPtr, Opts, false); |
126edc3f JJ |
542 | Die(); |
543 | } | |
544 | ||
5d3805fc JJ |
545 | static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts, |
546 | bool IsAttr) { | |
126edc3f | 547 | SourceLocation Loc = Data->Loc.acquire(); |
10189819 MO |
548 | ErrorType ET = ErrorType::InvalidNullArgument; |
549 | ||
550 | if (ignoreReport(Loc, Opts, ET)) | |
126edc3f JJ |
551 | return; |
552 | ||
10189819 | 553 | ScopedReport R(Opts, Loc, ET); |
866e32ad | 554 | |
5d3805fc JJ |
555 | Diag(Loc, DL_Error, |
556 | "null pointer passed as argument %0, which is declared to " | |
557 | "never be null") | |
558 | << Data->ArgIndex; | |
126edc3f | 559 | if (!Data->AttrLoc.isInvalid()) |
5d3805fc JJ |
560 | Diag(Data->AttrLoc, DL_Note, "%0 specified here") |
561 | << (IsAttr ? "nonnull attribute" : "_Nonnull type annotation"); | |
126edc3f JJ |
562 | } |
563 | ||
564 | void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) { | |
866e32ad | 565 | GET_REPORT_OPTIONS(false); |
5d3805fc | 566 | handleNonNullArg(Data, Opts, true); |
126edc3f JJ |
567 | } |
568 | ||
569 | void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) { | |
866e32ad | 570 | GET_REPORT_OPTIONS(true); |
5d3805fc JJ |
571 | handleNonNullArg(Data, Opts, true); |
572 | Die(); | |
573 | } | |
574 | ||
575 | void __ubsan::__ubsan_handle_nullability_arg(NonNullArgData *Data) { | |
576 | GET_REPORT_OPTIONS(false); | |
577 | handleNonNullArg(Data, Opts, false); | |
578 | } | |
579 | ||
580 | void __ubsan::__ubsan_handle_nullability_arg_abort(NonNullArgData *Data) { | |
581 | GET_REPORT_OPTIONS(true); | |
582 | handleNonNullArg(Data, Opts, false); | |
126edc3f JJ |
583 | Die(); |
584 | } | |
696d846a | 585 | |
c9b39a49 JJ |
586 | static void handlePointerOverflowImpl(PointerOverflowData *Data, |
587 | ValueHandle Base, | |
588 | ValueHandle Result, | |
589 | ReportOptions Opts) { | |
590 | SourceLocation Loc = Data->Loc.acquire(); | |
591 | ErrorType ET = ErrorType::PointerOverflow; | |
592 | ||
593 | if (ignoreReport(Loc, Opts, ET)) | |
594 | return; | |
595 | ||
596 | ScopedReport R(Opts, Loc, ET); | |
597 | ||
5d3805fc JJ |
598 | if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) { |
599 | if (Base > Result) | |
600 | Diag(Loc, DL_Error, "addition of unsigned offset to %0 overflowed to %1") | |
601 | << (void *)Base << (void *)Result; | |
602 | else | |
603 | Diag(Loc, DL_Error, | |
604 | "subtraction of unsigned offset from %0 overflowed to %1") | |
605 | << (void *)Base << (void *)Result; | |
606 | } else { | |
607 | Diag(Loc, DL_Error, | |
608 | "pointer index expression with base %0 overflowed to %1") | |
609 | << (void *)Base << (void *)Result; | |
610 | } | |
c9b39a49 JJ |
611 | } |
612 | ||
613 | void __ubsan::__ubsan_handle_pointer_overflow(PointerOverflowData *Data, | |
614 | ValueHandle Base, | |
615 | ValueHandle Result) { | |
616 | GET_REPORT_OPTIONS(false); | |
617 | handlePointerOverflowImpl(Data, Base, Result, Opts); | |
618 | } | |
619 | ||
620 | void __ubsan::__ubsan_handle_pointer_overflow_abort(PointerOverflowData *Data, | |
621 | ValueHandle Base, | |
622 | ValueHandle Result) { | |
623 | GET_REPORT_OPTIONS(true); | |
624 | handlePointerOverflowImpl(Data, Base, Result, Opts); | |
625 | Die(); | |
626 | } | |
627 | ||
10189819 | 628 | static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function, |
696d846a | 629 | ReportOptions Opts) { |
10189819 MO |
630 | if (Data->CheckKind != CFITCK_ICall) |
631 | Die(); | |
632 | ||
696d846a | 633 | SourceLocation Loc = Data->Loc.acquire(); |
10189819 MO |
634 | ErrorType ET = ErrorType::CFIBadType; |
635 | ||
636 | if (ignoreReport(Loc, Opts, ET)) | |
696d846a MO |
637 | return; |
638 | ||
10189819 | 639 | ScopedReport R(Opts, Loc, ET); |
696d846a MO |
640 | |
641 | Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during " | |
642 | "indirect function call") | |
643 | << Data->Type; | |
644 | ||
645 | SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); | |
646 | const char *FName = FLoc.get()->info.function; | |
647 | if (!FName) | |
648 | FName = "(unknown)"; | |
649 | Diag(FLoc, DL_Note, "%0 defined here") << FName; | |
650 | } | |
651 | ||
10189819 | 652 | namespace __ubsan { |
5d3805fc | 653 | |
10189819 | 654 | #ifdef UBSAN_CAN_USE_CXXABI |
5d3805fc JJ |
655 | |
656 | #ifdef _WIN32 | |
657 | ||
658 | extern "C" void __ubsan_handle_cfi_bad_type_default(CFICheckFailData *Data, | |
659 | ValueHandle Vtable, | |
660 | bool ValidVtable, | |
661 | ReportOptions Opts) { | |
10189819 MO |
662 | Die(); |
663 | } | |
10189819 | 664 | |
5d3805fc JJ |
665 | WIN_WEAK_ALIAS(__ubsan_handle_cfi_bad_type, __ubsan_handle_cfi_bad_type_default) |
666 | #else | |
667 | SANITIZER_WEAK_ATTRIBUTE | |
668 | #endif | |
669 | void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, | |
670 | bool ValidVtable, ReportOptions Opts); | |
511c8687 | 671 | |
5d3805fc JJ |
672 | #else |
673 | void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, | |
674 | bool ValidVtable, ReportOptions Opts) { | |
511c8687 MO |
675 | Die(); |
676 | } | |
5d3805fc JJ |
677 | #endif |
678 | ||
679 | } // namespace __ubsan | |
511c8687 | 680 | |
10189819 MO |
681 | void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data, |
682 | ValueHandle Value, | |
683 | uptr ValidVtable) { | |
696d846a | 684 | GET_REPORT_OPTIONS(false); |
10189819 MO |
685 | if (Data->CheckKind == CFITCK_ICall) |
686 | handleCFIBadIcall(Data, Value, Opts); | |
687 | else | |
5d3805fc | 688 | __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts); |
696d846a MO |
689 | } |
690 | ||
10189819 MO |
691 | void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data, |
692 | ValueHandle Value, | |
693 | uptr ValidVtable) { | |
696d846a | 694 | GET_REPORT_OPTIONS(true); |
10189819 MO |
695 | if (Data->CheckKind == CFITCK_ICall) |
696 | handleCFIBadIcall(Data, Value, Opts); | |
697 | else | |
5d3805fc | 698 | __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts); |
696d846a MO |
699 | Die(); |
700 | } | |
701 | ||
702 | #endif // CAN_SANITIZE_UB |