1 //===-- ubsan_handlers.cc -------------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Error logging entry points for the UBSan runtime.
12 //===----------------------------------------------------------------------===//
14 #include "ubsan_handlers.h"
15 #include "ubsan_diag.h"
17 #include "sanitizer_common/sanitizer_common.h"
19 using namespace __sanitizer;
20 using namespace __ubsan;
22 static bool ignoreReport(SourceLocation SLoc, ReportOptions Opts) {
23 // If source location is already acquired, we don't need to print an error
24 // report for the second time. However, if we're in an unrecoverable handler,
25 // it's possible that location was required by concurrently running thread.
26 // In this case, we should continue the execution to ensure that any of
27 // threads will grab the report mutex and print the report before
28 // crashing the program.
29 return SLoc.isDisabled() && !Opts.DieAfterReport;
33 const char *TypeCheckKinds[] = {
34 "load of", "store to", "reference binding to", "member access within",
35 "member call on", "constructor call on", "downcast of", "downcast of",
36 "upcast of", "cast to virtual base of"};
39 static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
41 Location Loc = Data->Loc.acquire();
42 // Use the SourceLocation from Data to track deduplication, even if 'invalid'
43 if (ignoreReport(Loc.getSourceLocation(), Opts))
46 SymbolizedStackHolder FallbackLoc;
47 if (Data->Loc.isInvalid()) {
48 FallbackLoc.reset(getCallerLocation(Opts.pc));
52 ScopedReport R(Opts, Loc);
55 Diag(Loc, DL_Error, "%0 null pointer of type %1")
56 << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
57 else if (Data->Alignment && (Pointer & (Data->Alignment - 1)))
58 Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, "
59 "which requires %2 byte alignment")
60 << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer
61 << Data->Alignment << Data->Type;
63 Diag(Loc, DL_Error, "%0 address %1 with insufficient space "
64 "for an object of type %2")
65 << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
67 Diag(Pointer, DL_Note, "pointer points here");
70 void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data,
71 ValueHandle Pointer) {
72 GET_REPORT_OPTIONS(false);
73 handleTypeMismatchImpl(Data, Pointer, Opts);
75 void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data,
76 ValueHandle Pointer) {
77 GET_REPORT_OPTIONS(true);
78 handleTypeMismatchImpl(Data, Pointer, Opts);
82 /// \brief Common diagnostic emission for various forms of integer overflow.
84 static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,
85 const char *Operator, T RHS,
87 SourceLocation Loc = Data->Loc.acquire();
88 if (ignoreReport(Loc, Opts))
91 ScopedReport R(Opts, Loc);
93 Diag(Loc, DL_Error, "%0 integer overflow: "
94 "%1 %2 %3 cannot be represented in type %4")
95 << (Data->Type.isSignedIntegerTy() ? "signed" : "unsigned")
96 << Value(Data->Type, LHS) << Operator << RHS << Data->Type;
99 #define UBSAN_OVERFLOW_HANDLER(handler_name, op, abort) \
100 void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \
102 GET_REPORT_OPTIONS(abort); \
103 handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \
107 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false)
108 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true)
109 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false)
110 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true)
111 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false)
112 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true)
114 static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,
115 ReportOptions Opts) {
116 SourceLocation Loc = Data->Loc.acquire();
117 if (ignoreReport(Loc, Opts))
120 ScopedReport R(Opts, Loc);
122 if (Data->Type.isSignedIntegerTy())
124 "negation of %0 cannot be represented in type %1; "
125 "cast to an unsigned type to negate this value to itself")
126 << Value(Data->Type, OldVal) << Data->Type;
129 "negation of %0 cannot be represented in type %1")
130 << Value(Data->Type, OldVal) << Data->Type;
133 void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
134 ValueHandle OldVal) {
135 GET_REPORT_OPTIONS(false);
136 handleNegateOverflowImpl(Data, OldVal, Opts);
138 void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,
139 ValueHandle OldVal) {
140 GET_REPORT_OPTIONS(true);
141 handleNegateOverflowImpl(Data, OldVal, Opts);
145 static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,
146 ValueHandle RHS, ReportOptions Opts) {
147 SourceLocation Loc = Data->Loc.acquire();
148 if (ignoreReport(Loc, Opts))
151 ScopedReport R(Opts, Loc);
153 Value LHSVal(Data->Type, LHS);
154 Value RHSVal(Data->Type, RHS);
155 if (RHSVal.isMinusOne())
157 "division of %0 by -1 cannot be represented in type %1")
158 << LHSVal << Data->Type;
160 Diag(Loc, DL_Error, "division by zero");
163 void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
164 ValueHandle LHS, ValueHandle RHS) {
165 GET_REPORT_OPTIONS(false);
166 handleDivremOverflowImpl(Data, LHS, RHS, Opts);
168 void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data,
171 GET_REPORT_OPTIONS(true);
172 handleDivremOverflowImpl(Data, LHS, RHS, Opts);
176 static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,
177 ValueHandle LHS, ValueHandle RHS,
178 ReportOptions Opts) {
179 SourceLocation Loc = Data->Loc.acquire();
180 if (ignoreReport(Loc, Opts))
183 ScopedReport R(Opts, Loc);
185 Value LHSVal(Data->LHSType, LHS);
186 Value RHSVal(Data->RHSType, RHS);
187 if (RHSVal.isNegative())
188 Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal;
189 else if (RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth())
191 "shift exponent %0 is too large for %1-bit type %2")
192 << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;
193 else if (LHSVal.isNegative())
194 Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal;
197 "left shift of %0 by %1 places cannot be represented in type %2")
198 << LHSVal << RHSVal << Data->LHSType;
201 void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
204 GET_REPORT_OPTIONS(false);
205 handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
207 void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
208 ShiftOutOfBoundsData *Data,
211 GET_REPORT_OPTIONS(true);
212 handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
216 static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
217 ReportOptions Opts) {
218 SourceLocation Loc = Data->Loc.acquire();
219 if (ignoreReport(Loc, Opts))
222 ScopedReport R(Opts, Loc);
224 Value IndexVal(Data->IndexType, Index);
225 Diag(Loc, DL_Error, "index %0 out of bounds for type %1")
226 << IndexVal << Data->ArrayType;
229 void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data,
231 GET_REPORT_OPTIONS(false);
232 handleOutOfBoundsImpl(Data, Index, Opts);
234 void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,
236 GET_REPORT_OPTIONS(true);
237 handleOutOfBoundsImpl(Data, Index, Opts);
241 static void handleBuiltinUnreachableImpl(UnreachableData *Data,
242 ReportOptions Opts) {
243 ScopedReport R(Opts, Data->Loc);
244 Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call");
247 void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
248 GET_REPORT_OPTIONS(true);
249 handleBuiltinUnreachableImpl(Data, Opts);
253 static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) {
254 ScopedReport R(Opts, Data->Loc);
255 Diag(Data->Loc, DL_Error,
256 "execution reached the end of a value-returning function "
257 "without returning a value");
260 void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
261 GET_REPORT_OPTIONS(true);
262 handleMissingReturnImpl(Data, Opts);
266 static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
267 ReportOptions Opts) {
268 SourceLocation Loc = Data->Loc.acquire();
269 if (ignoreReport(Loc, Opts))
272 ScopedReport R(Opts, Loc);
274 Diag(Loc, DL_Error, "variable length array bound evaluates to "
275 "non-positive value %0")
276 << Value(Data->Type, Bound);
279 void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
281 GET_REPORT_OPTIONS(false);
282 handleVLABoundNotPositive(Data, Bound, Opts);
284 void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data,
286 GET_REPORT_OPTIONS(true);
287 handleVLABoundNotPositive(Data, Bound, Opts);
291 static void handleFloatCastOverflow(FloatCastOverflowData *Data,
292 ValueHandle From, ReportOptions Opts) {
293 // TODO: Add deduplication once a SourceLocation is generated for this check.
294 SymbolizedStackHolder CallerLoc(getCallerLocation(Opts.pc));
295 Location Loc = CallerLoc;
296 ScopedReport R(Opts, Loc);
299 "value %0 is outside the range of representable values of type %2")
300 << Value(Data->FromType, From) << Data->FromType << Data->ToType;
303 void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data,
305 GET_REPORT_OPTIONS(false);
306 handleFloatCastOverflow(Data, From, Opts);
309 __ubsan::__ubsan_handle_float_cast_overflow_abort(FloatCastOverflowData *Data,
311 GET_REPORT_OPTIONS(true);
312 handleFloatCastOverflow(Data, From, Opts);
316 static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
317 ReportOptions Opts) {
318 SourceLocation Loc = Data->Loc.acquire();
319 if (ignoreReport(Loc, Opts))
322 ScopedReport R(Opts, Loc);
325 "load of value %0, which is not a valid value for type %1")
326 << Value(Data->Type, Val) << Data->Type;
329 void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
331 GET_REPORT_OPTIONS(false);
332 handleLoadInvalidValue(Data, Val, Opts);
334 void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,
336 GET_REPORT_OPTIONS(true);
337 handleLoadInvalidValue(Data, Val, Opts);
341 static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
342 ValueHandle Function,
343 ReportOptions Opts) {
344 SourceLocation CallLoc = Data->Loc.acquire();
345 if (ignoreReport(CallLoc, Opts))
348 ScopedReport R(Opts, CallLoc);
350 SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
351 const char *FName = FLoc.get()->info.function;
355 Diag(CallLoc, DL_Error,
356 "call to function %0 through pointer to incorrect function type %1")
357 << FName << Data->Type;
358 Diag(FLoc, DL_Note, "%0 defined here") << FName;
362 __ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data,
363 ValueHandle Function) {
364 GET_REPORT_OPTIONS(false);
365 handleFunctionTypeMismatch(Data, Function, Opts);
368 void __ubsan::__ubsan_handle_function_type_mismatch_abort(
369 FunctionTypeMismatchData *Data, ValueHandle Function) {
370 GET_REPORT_OPTIONS(true);
371 handleFunctionTypeMismatch(Data, Function, Opts);
375 static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
376 SourceLocation Loc = Data->Loc.acquire();
377 if (ignoreReport(Loc, Opts))
380 ScopedReport R(Opts, Loc);
382 Diag(Loc, DL_Error, "null pointer returned from function declared to never "
384 if (!Data->AttrLoc.isInvalid())
385 Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here");
388 void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) {
389 GET_REPORT_OPTIONS(false);
390 handleNonNullReturn(Data, Opts);
393 void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
394 GET_REPORT_OPTIONS(true);
395 handleNonNullReturn(Data, Opts);
399 static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
400 SourceLocation Loc = Data->Loc.acquire();
401 if (ignoreReport(Loc, Opts))
404 ScopedReport R(Opts, Loc);
406 Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to "
407 "never be null") << Data->ArgIndex;
408 if (!Data->AttrLoc.isInvalid())
409 Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here");
412 void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {
413 GET_REPORT_OPTIONS(false);
414 handleNonNullArg(Data, Opts);
417 void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
418 GET_REPORT_OPTIONS(true);
419 handleNonNullArg(Data, Opts);