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