]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //===-- ubsan_handlers.cc -------------------------------------------------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // Error logging entry points for the UBSan runtime. | |
11 | // | |
12 | //===----------------------------------------------------------------------===// | |
13 | ||
92a42be0 SL |
14 | #include "ubsan_platform.h" |
15 | #if CAN_SANITIZE_UB | |
1a4d82fc JJ |
16 | #include "ubsan_handlers.h" |
17 | #include "ubsan_diag.h" | |
18 | ||
19 | #include "sanitizer_common/sanitizer_common.h" | |
20 | ||
21 | using namespace __sanitizer; | |
22 | using namespace __ubsan; | |
23 | ||
3157f602 XL |
24 | namespace __ubsan { |
25 | bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) { | |
26 | // We are not allowed to skip error report: if we are in unrecoverable | |
27 | // handler, we have to terminate the program right now, and therefore | |
28 | // have to print some diagnostic. | |
29 | // | |
30 | // Even if source location is disabled, it doesn't mean that we have | |
31 | // already report an error to the user: some concurrently running | |
32 | // thread could have acquired it, but not yet printed the report. | |
33 | if (Opts.FromUnrecoverableHandler) | |
34 | return false; | |
35 | return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename()); | |
92a42be0 SL |
36 | } |
37 | ||
92a42be0 | 38 | const char *TypeCheckKinds[] = { |
1a4d82fc | 39 | "load of", "store to", "reference binding to", "member access within", |
92a42be0 SL |
40 | "member call on", "constructor call on", "downcast of", "downcast of", |
41 | "upcast of", "cast to virtual base of"}; | |
1a4d82fc JJ |
42 | } |
43 | ||
44 | static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, | |
92a42be0 | 45 | ReportOptions Opts) { |
1a4d82fc | 46 | Location Loc = Data->Loc.acquire(); |
3157f602 XL |
47 | |
48 | ErrorType ET; | |
49 | if (!Pointer) | |
50 | ET = ErrorType::NullPointerUse; | |
51 | else if (Data->Alignment && (Pointer & (Data->Alignment - 1))) | |
52 | ET = ErrorType::MisalignedPointerUse; | |
53 | else | |
54 | ET = ErrorType::InsufficientObjectSize; | |
55 | ||
56 | // Use the SourceLocation from Data to track deduplication, even if it's | |
57 | // invalid. | |
58 | if (ignoreReport(Loc.getSourceLocation(), Opts, ET)) | |
1a4d82fc | 59 | return; |
92a42be0 SL |
60 | |
61 | SymbolizedStackHolder FallbackLoc; | |
62 | if (Data->Loc.isInvalid()) { | |
63 | FallbackLoc.reset(getCallerLocation(Opts.pc)); | |
1a4d82fc | 64 | Loc = FallbackLoc; |
92a42be0 | 65 | } |
1a4d82fc | 66 | |
3157f602 | 67 | ScopedReport R(Opts, Loc, ET); |
92a42be0 | 68 | |
3157f602 XL |
69 | switch (ET) { |
70 | case ErrorType::NullPointerUse: | |
1a4d82fc | 71 | Diag(Loc, DL_Error, "%0 null pointer of type %1") |
3157f602 XL |
72 | << TypeCheckKinds[Data->TypeCheckKind] << Data->Type; |
73 | break; | |
74 | case ErrorType::MisalignedPointerUse: | |
1a4d82fc JJ |
75 | Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, " |
76 | "which requires %2 byte alignment") | |
3157f602 XL |
77 | << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer |
78 | << Data->Alignment << Data->Type; | |
79 | break; | |
80 | case ErrorType::InsufficientObjectSize: | |
1a4d82fc JJ |
81 | Diag(Loc, DL_Error, "%0 address %1 with insufficient space " |
82 | "for an object of type %2") | |
3157f602 XL |
83 | << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Data->Type; |
84 | break; | |
85 | default: | |
86 | UNREACHABLE("unexpected error type!"); | |
92a42be0 | 87 | } |
3157f602 | 88 | |
1a4d82fc JJ |
89 | if (Pointer) |
90 | Diag(Pointer, DL_Note, "pointer points here"); | |
91 | } | |
92a42be0 | 92 | |
1a4d82fc JJ |
93 | void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data, |
94 | ValueHandle Pointer) { | |
92a42be0 SL |
95 | GET_REPORT_OPTIONS(false); |
96 | handleTypeMismatchImpl(Data, Pointer, Opts); | |
1a4d82fc JJ |
97 | } |
98 | void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data, | |
99 | ValueHandle Pointer) { | |
92a42be0 SL |
100 | GET_REPORT_OPTIONS(true); |
101 | handleTypeMismatchImpl(Data, Pointer, Opts); | |
1a4d82fc JJ |
102 | Die(); |
103 | } | |
104 | ||
105 | /// \brief Common diagnostic emission for various forms of integer overflow. | |
92a42be0 SL |
106 | template <typename T> |
107 | static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS, | |
108 | const char *Operator, T RHS, | |
109 | ReportOptions Opts) { | |
1a4d82fc | 110 | SourceLocation Loc = Data->Loc.acquire(); |
3157f602 XL |
111 | bool IsSigned = Data->Type.isSignedIntegerTy(); |
112 | ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow | |
113 | : ErrorType::UnsignedIntegerOverflow; | |
114 | ||
115 | if (ignoreReport(Loc, Opts, ET)) | |
1a4d82fc JJ |
116 | return; |
117 | ||
3157f602 | 118 | ScopedReport R(Opts, Loc, ET); |
92a42be0 | 119 | |
1a4d82fc JJ |
120 | Diag(Loc, DL_Error, "%0 integer overflow: " |
121 | "%1 %2 %3 cannot be represented in type %4") | |
92a42be0 | 122 | << (IsSigned ? "signed" : "unsigned") |
1a4d82fc JJ |
123 | << Value(Data->Type, LHS) << Operator << RHS << Data->Type; |
124 | } | |
125 | ||
3157f602 | 126 | #define UBSAN_OVERFLOW_HANDLER(handler_name, op, unrecoverable) \ |
92a42be0 SL |
127 | void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \ |
128 | ValueHandle RHS) { \ | |
3157f602 | 129 | GET_REPORT_OPTIONS(unrecoverable); \ |
92a42be0 | 130 | handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \ |
3157f602 XL |
131 | if (unrecoverable) \ |
132 | Die(); \ | |
92a42be0 SL |
133 | } |
134 | ||
135 | UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false) | |
136 | UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true) | |
137 | UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false) | |
138 | UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true) | |
139 | UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false) | |
140 | UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true) | |
141 | ||
142 | static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal, | |
143 | ReportOptions Opts) { | |
1a4d82fc | 144 | SourceLocation Loc = Data->Loc.acquire(); |
3157f602 XL |
145 | bool IsSigned = Data->Type.isSignedIntegerTy(); |
146 | ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow | |
147 | : ErrorType::UnsignedIntegerOverflow; | |
148 | ||
149 | if (ignoreReport(Loc, Opts, ET)) | |
1a4d82fc JJ |
150 | return; |
151 | ||
3157f602 | 152 | ScopedReport R(Opts, Loc, ET); |
92a42be0 SL |
153 | |
154 | if (IsSigned) | |
1a4d82fc JJ |
155 | Diag(Loc, DL_Error, |
156 | "negation of %0 cannot be represented in type %1; " | |
157 | "cast to an unsigned type to negate this value to itself") | |
92a42be0 | 158 | << Value(Data->Type, OldVal) << Data->Type; |
1a4d82fc | 159 | else |
92a42be0 SL |
160 | Diag(Loc, DL_Error, "negation of %0 cannot be represented in type %1") |
161 | << Value(Data->Type, OldVal) << Data->Type; | |
162 | } | |
163 | ||
164 | void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data, | |
165 | ValueHandle OldVal) { | |
166 | GET_REPORT_OPTIONS(false); | |
167 | handleNegateOverflowImpl(Data, OldVal, Opts); | |
1a4d82fc JJ |
168 | } |
169 | void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data, | |
170 | ValueHandle OldVal) { | |
92a42be0 SL |
171 | GET_REPORT_OPTIONS(true); |
172 | handleNegateOverflowImpl(Data, OldVal, Opts); | |
1a4d82fc JJ |
173 | Die(); |
174 | } | |
175 | ||
92a42be0 SL |
176 | static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS, |
177 | ValueHandle RHS, ReportOptions Opts) { | |
1a4d82fc | 178 | SourceLocation Loc = Data->Loc.acquire(); |
3157f602 XL |
179 | Value LHSVal(Data->Type, LHS); |
180 | Value RHSVal(Data->Type, RHS); | |
181 | ||
182 | ErrorType ET; | |
183 | if (RHSVal.isMinusOne()) | |
184 | ET = ErrorType::SignedIntegerOverflow; | |
185 | else if (Data->Type.isIntegerTy()) | |
186 | ET = ErrorType::IntegerDivideByZero; | |
187 | else | |
188 | ET = ErrorType::FloatDivideByZero; | |
189 | ||
190 | if (ignoreReport(Loc, Opts, ET)) | |
1a4d82fc JJ |
191 | return; |
192 | ||
3157f602 | 193 | ScopedReport R(Opts, Loc, ET); |
92a42be0 | 194 | |
3157f602 XL |
195 | switch (ET) { |
196 | case ErrorType::SignedIntegerOverflow: | |
197 | Diag(Loc, DL_Error, "division of %0 by -1 cannot be represented in type %1") | |
198 | << LHSVal << Data->Type; | |
199 | break; | |
200 | default: | |
1a4d82fc | 201 | Diag(Loc, DL_Error, "division by zero"); |
3157f602 | 202 | break; |
92a42be0 SL |
203 | } |
204 | } | |
205 | ||
206 | void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data, | |
207 | ValueHandle LHS, ValueHandle RHS) { | |
208 | GET_REPORT_OPTIONS(false); | |
209 | handleDivremOverflowImpl(Data, LHS, RHS, Opts); | |
1a4d82fc JJ |
210 | } |
211 | void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data, | |
212 | ValueHandle LHS, | |
213 | ValueHandle RHS) { | |
92a42be0 SL |
214 | GET_REPORT_OPTIONS(true); |
215 | handleDivremOverflowImpl(Data, LHS, RHS, Opts); | |
1a4d82fc JJ |
216 | Die(); |
217 | } | |
218 | ||
92a42be0 SL |
219 | static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data, |
220 | ValueHandle LHS, ValueHandle RHS, | |
221 | ReportOptions Opts) { | |
1a4d82fc | 222 | SourceLocation Loc = Data->Loc.acquire(); |
3157f602 XL |
223 | Value LHSVal(Data->LHSType, LHS); |
224 | Value RHSVal(Data->RHSType, RHS); | |
225 | ||
226 | ErrorType ET; | |
227 | if (RHSVal.isNegative() || | |
228 | RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth()) | |
229 | ET = ErrorType::InvalidShiftExponent; | |
230 | else | |
231 | ET = ErrorType::InvalidShiftBase; | |
232 | ||
233 | if (ignoreReport(Loc, Opts, ET)) | |
1a4d82fc JJ |
234 | return; |
235 | ||
3157f602 | 236 | ScopedReport R(Opts, Loc, ET); |
92a42be0 | 237 | |
3157f602 XL |
238 | if (ET == ErrorType::InvalidShiftExponent) { |
239 | if (RHSVal.isNegative()) | |
240 | Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal; | |
241 | else | |
242 | Diag(Loc, DL_Error, "shift exponent %0 is too large for %1-bit type %2") | |
243 | << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType; | |
92a42be0 | 244 | } else { |
3157f602 XL |
245 | if (LHSVal.isNegative()) |
246 | Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal; | |
247 | else | |
248 | Diag(Loc, DL_Error, | |
249 | "left shift of %0 by %1 places cannot be represented in type %2") | |
250 | << LHSVal << RHSVal << Data->LHSType; | |
92a42be0 SL |
251 | } |
252 | } | |
253 | ||
254 | void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data, | |
255 | ValueHandle LHS, | |
256 | ValueHandle RHS) { | |
257 | GET_REPORT_OPTIONS(false); | |
258 | handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); | |
1a4d82fc JJ |
259 | } |
260 | void __ubsan::__ubsan_handle_shift_out_of_bounds_abort( | |
261 | ShiftOutOfBoundsData *Data, | |
262 | ValueHandle LHS, | |
263 | ValueHandle RHS) { | |
92a42be0 SL |
264 | GET_REPORT_OPTIONS(true); |
265 | handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); | |
1a4d82fc JJ |
266 | Die(); |
267 | } | |
268 | ||
92a42be0 SL |
269 | static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index, |
270 | ReportOptions Opts) { | |
1a4d82fc | 271 | SourceLocation Loc = Data->Loc.acquire(); |
3157f602 XL |
272 | ErrorType ET = ErrorType::OutOfBoundsIndex; |
273 | ||
274 | if (ignoreReport(Loc, Opts, ET)) | |
1a4d82fc JJ |
275 | return; |
276 | ||
3157f602 | 277 | ScopedReport R(Opts, Loc, ET); |
92a42be0 | 278 | |
1a4d82fc JJ |
279 | Value IndexVal(Data->IndexType, Index); |
280 | Diag(Loc, DL_Error, "index %0 out of bounds for type %1") | |
281 | << IndexVal << Data->ArrayType; | |
282 | } | |
92a42be0 SL |
283 | |
284 | void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data, | |
285 | ValueHandle Index) { | |
286 | GET_REPORT_OPTIONS(false); | |
287 | handleOutOfBoundsImpl(Data, Index, Opts); | |
288 | } | |
1a4d82fc JJ |
289 | void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data, |
290 | ValueHandle Index) { | |
92a42be0 SL |
291 | GET_REPORT_OPTIONS(true); |
292 | handleOutOfBoundsImpl(Data, Index, Opts); | |
1a4d82fc JJ |
293 | Die(); |
294 | } | |
295 | ||
92a42be0 SL |
296 | static void handleBuiltinUnreachableImpl(UnreachableData *Data, |
297 | ReportOptions Opts) { | |
298 | ScopedReport R(Opts, Data->Loc, ErrorType::UnreachableCall); | |
1a4d82fc | 299 | Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call"); |
92a42be0 SL |
300 | } |
301 | ||
302 | void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) { | |
303 | GET_REPORT_OPTIONS(true); | |
304 | handleBuiltinUnreachableImpl(Data, Opts); | |
1a4d82fc JJ |
305 | Die(); |
306 | } | |
307 | ||
92a42be0 SL |
308 | static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) { |
309 | ScopedReport R(Opts, Data->Loc, ErrorType::MissingReturn); | |
1a4d82fc JJ |
310 | Diag(Data->Loc, DL_Error, |
311 | "execution reached the end of a value-returning function " | |
312 | "without returning a value"); | |
92a42be0 SL |
313 | } |
314 | ||
315 | void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) { | |
316 | GET_REPORT_OPTIONS(true); | |
317 | handleMissingReturnImpl(Data, Opts); | |
1a4d82fc JJ |
318 | Die(); |
319 | } | |
320 | ||
92a42be0 SL |
321 | static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound, |
322 | ReportOptions Opts) { | |
1a4d82fc | 323 | SourceLocation Loc = Data->Loc.acquire(); |
3157f602 XL |
324 | ErrorType ET = ErrorType::NonPositiveVLAIndex; |
325 | ||
326 | if (ignoreReport(Loc, Opts, ET)) | |
1a4d82fc JJ |
327 | return; |
328 | ||
3157f602 | 329 | ScopedReport R(Opts, Loc, ET); |
92a42be0 | 330 | |
1a4d82fc JJ |
331 | Diag(Loc, DL_Error, "variable length array bound evaluates to " |
332 | "non-positive value %0") | |
333 | << Value(Data->Type, Bound); | |
334 | } | |
92a42be0 SL |
335 | |
336 | void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data, | |
337 | ValueHandle Bound) { | |
338 | GET_REPORT_OPTIONS(false); | |
339 | handleVLABoundNotPositive(Data, Bound, Opts); | |
340 | } | |
1a4d82fc | 341 | void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data, |
92a42be0 SL |
342 | ValueHandle Bound) { |
343 | GET_REPORT_OPTIONS(true); | |
344 | handleVLABoundNotPositive(Data, Bound, Opts); | |
1a4d82fc JJ |
345 | Die(); |
346 | } | |
347 | ||
92a42be0 SL |
348 | static bool looksLikeFloatCastOverflowDataV1(void *Data) { |
349 | // First field is either a pointer to filename or a pointer to a | |
350 | // TypeDescriptor. | |
351 | u8 *FilenameOrTypeDescriptor; | |
352 | internal_memcpy(&FilenameOrTypeDescriptor, Data, | |
353 | sizeof(FilenameOrTypeDescriptor)); | |
354 | ||
355 | // Heuristic: For float_cast_overflow, the TypeKind will be either TK_Integer | |
356 | // (0x0), TK_Float (0x1) or TK_Unknown (0xff). If both types are known, | |
357 | // adding both bytes will be 0 or 1 (for BE or LE). If it were a filename, | |
358 | // adding two printable characters will not yield such a value. Otherwise, | |
359 | // if one of them is 0xff, this is most likely TK_Unknown type descriptor. | |
360 | u16 MaybeFromTypeKind = | |
361 | FilenameOrTypeDescriptor[0] + FilenameOrTypeDescriptor[1]; | |
362 | return MaybeFromTypeKind < 2 || FilenameOrTypeDescriptor[0] == 0xff || | |
363 | FilenameOrTypeDescriptor[1] == 0xff; | |
364 | } | |
365 | ||
366 | static void handleFloatCastOverflow(void *DataPtr, ValueHandle From, | |
367 | ReportOptions Opts) { | |
368 | SymbolizedStackHolder CallerLoc; | |
369 | Location Loc; | |
370 | const TypeDescriptor *FromType, *ToType; | |
3157f602 | 371 | ErrorType ET = ErrorType::FloatCastOverflow; |
92a42be0 SL |
372 | |
373 | if (looksLikeFloatCastOverflowDataV1(DataPtr)) { | |
374 | auto Data = reinterpret_cast<FloatCastOverflowData *>(DataPtr); | |
375 | CallerLoc.reset(getCallerLocation(Opts.pc)); | |
376 | Loc = CallerLoc; | |
377 | FromType = &Data->FromType; | |
378 | ToType = &Data->ToType; | |
379 | } else { | |
380 | auto Data = reinterpret_cast<FloatCastOverflowDataV2 *>(DataPtr); | |
381 | SourceLocation SLoc = Data->Loc.acquire(); | |
3157f602 | 382 | if (ignoreReport(SLoc, Opts, ET)) |
92a42be0 SL |
383 | return; |
384 | Loc = SLoc; | |
385 | FromType = &Data->FromType; | |
386 | ToType = &Data->ToType; | |
387 | } | |
388 | ||
3157f602 | 389 | ScopedReport R(Opts, Loc, ET); |
1a4d82fc | 390 | |
92a42be0 | 391 | Diag(Loc, DL_Error, |
1a4d82fc | 392 | "value %0 is outside the range of representable values of type %2") |
92a42be0 | 393 | << Value(*FromType, From) << *FromType << *ToType; |
1a4d82fc | 394 | } |
92a42be0 SL |
395 | |
396 | void __ubsan::__ubsan_handle_float_cast_overflow(void *Data, ValueHandle From) { | |
397 | GET_REPORT_OPTIONS(false); | |
398 | handleFloatCastOverflow(Data, From, Opts); | |
399 | } | |
400 | void __ubsan::__ubsan_handle_float_cast_overflow_abort(void *Data, | |
401 | ValueHandle From) { | |
402 | GET_REPORT_OPTIONS(true); | |
403 | handleFloatCastOverflow(Data, From, Opts); | |
1a4d82fc JJ |
404 | Die(); |
405 | } | |
406 | ||
92a42be0 SL |
407 | static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val, |
408 | ReportOptions Opts) { | |
1a4d82fc | 409 | SourceLocation Loc = Data->Loc.acquire(); |
92a42be0 SL |
410 | // This check could be more precise if we used different handlers for |
411 | // -fsanitize=bool and -fsanitize=enum. | |
412 | bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")); | |
3157f602 XL |
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); | |
92a42be0 | 420 | |
1a4d82fc JJ |
421 | Diag(Loc, DL_Error, |
422 | "load of value %0, which is not a valid value for type %1") | |
423 | << Value(Data->Type, Val) << Data->Type; | |
424 | } | |
92a42be0 SL |
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 | } | |
1a4d82fc JJ |
431 | void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data, |
432 | ValueHandle Val) { | |
92a42be0 SL |
433 | GET_REPORT_OPTIONS(true); |
434 | handleLoadInvalidValue(Data, Val, Opts); | |
1a4d82fc JJ |
435 | Die(); |
436 | } | |
437 | ||
92a42be0 SL |
438 | static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data, |
439 | ValueHandle Function, | |
440 | ReportOptions Opts) { | |
441 | SourceLocation CallLoc = Data->Loc.acquire(); | |
3157f602 XL |
442 | ErrorType ET = ErrorType::FunctionTypeMismatch; |
443 | ||
444 | if (ignoreReport(CallLoc, Opts, ET)) | |
92a42be0 | 445 | return; |
1a4d82fc | 446 | |
3157f602 | 447 | ScopedReport R(Opts, CallLoc, ET); |
1a4d82fc | 448 | |
92a42be0 SL |
449 | SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); |
450 | const char *FName = FLoc.get()->info.function; | |
451 | if (!FName) | |
452 | FName = "(unknown)"; | |
453 | ||
454 | Diag(CallLoc, DL_Error, | |
1a4d82fc | 455 | "call to function %0 through pointer to incorrect function type %1") |
92a42be0 SL |
456 | << FName << Data->Type; |
457 | Diag(FLoc, DL_Note, "%0 defined here") << FName; | |
458 | } | |
459 | ||
460 | void | |
461 | __ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data, | |
462 | ValueHandle Function) { | |
463 | GET_REPORT_OPTIONS(false); | |
464 | handleFunctionTypeMismatch(Data, Function, Opts); | |
1a4d82fc JJ |
465 | } |
466 | ||
467 | void __ubsan::__ubsan_handle_function_type_mismatch_abort( | |
92a42be0 SL |
468 | FunctionTypeMismatchData *Data, ValueHandle Function) { |
469 | GET_REPORT_OPTIONS(true); | |
470 | handleFunctionTypeMismatch(Data, Function, Opts); | |
471 | Die(); | |
472 | } | |
473 | ||
474 | static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) { | |
475 | SourceLocation Loc = Data->Loc.acquire(); | |
3157f602 XL |
476 | ErrorType ET = ErrorType::InvalidNullReturn; |
477 | ||
478 | if (ignoreReport(Loc, Opts, ET)) | |
92a42be0 SL |
479 | return; |
480 | ||
3157f602 | 481 | ScopedReport R(Opts, Loc, ET); |
92a42be0 SL |
482 | |
483 | Diag(Loc, DL_Error, "null pointer returned from function declared to never " | |
484 | "return null"); | |
485 | if (!Data->AttrLoc.isInvalid()) | |
486 | Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here"); | |
487 | } | |
488 | ||
489 | void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) { | |
490 | GET_REPORT_OPTIONS(false); | |
491 | handleNonNullReturn(Data, Opts); | |
492 | } | |
493 | ||
494 | void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) { | |
495 | GET_REPORT_OPTIONS(true); | |
496 | handleNonNullReturn(Data, Opts); | |
497 | Die(); | |
498 | } | |
499 | ||
500 | static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) { | |
501 | SourceLocation Loc = Data->Loc.acquire(); | |
3157f602 XL |
502 | ErrorType ET = ErrorType::InvalidNullArgument; |
503 | ||
504 | if (ignoreReport(Loc, Opts, ET)) | |
92a42be0 SL |
505 | return; |
506 | ||
3157f602 | 507 | ScopedReport R(Opts, Loc, ET); |
92a42be0 SL |
508 | |
509 | Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to " | |
510 | "never be null") << Data->ArgIndex; | |
511 | if (!Data->AttrLoc.isInvalid()) | |
512 | Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here"); | |
513 | } | |
514 | ||
515 | void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) { | |
516 | GET_REPORT_OPTIONS(false); | |
517 | handleNonNullArg(Data, Opts); | |
518 | } | |
519 | ||
520 | void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) { | |
521 | GET_REPORT_OPTIONS(true); | |
522 | handleNonNullArg(Data, Opts); | |
523 | Die(); | |
524 | } | |
525 | ||
526 | static void handleCFIBadIcall(CFIBadIcallData *Data, ValueHandle Function, | |
527 | ReportOptions Opts) { | |
528 | SourceLocation Loc = Data->Loc.acquire(); | |
3157f602 XL |
529 | ErrorType ET = ErrorType::CFIBadType; |
530 | ||
531 | if (ignoreReport(Loc, Opts, ET)) | |
92a42be0 SL |
532 | return; |
533 | ||
3157f602 | 534 | ScopedReport R(Opts, Loc, ET); |
92a42be0 SL |
535 | |
536 | Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during " | |
537 | "indirect function call") | |
538 | << Data->Type; | |
539 | ||
540 | SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); | |
541 | const char *FName = FLoc.get()->info.function; | |
542 | if (!FName) | |
543 | FName = "(unknown)"; | |
544 | Diag(FLoc, DL_Note, "%0 defined here") << FName; | |
545 | } | |
546 | ||
547 | void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *Data, | |
548 | ValueHandle Function) { | |
549 | GET_REPORT_OPTIONS(false); | |
550 | handleCFIBadIcall(Data, Function, Opts); | |
551 | } | |
552 | ||
553 | void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *Data, | |
554 | ValueHandle Function) { | |
555 | GET_REPORT_OPTIONS(true); | |
556 | handleCFIBadIcall(Data, Function, Opts); | |
1a4d82fc JJ |
557 | Die(); |
558 | } | |
92a42be0 SL |
559 | |
560 | #endif // CAN_SANITIZE_UB |