1 //===-- ubsan_handlers.cc -------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // Error logging entry points for the UBSan runtime.
10 //===----------------------------------------------------------------------===//
12 #include "ubsan_handlers.h"
13 #include "ubsan_diag.h"
15 #include "sanitizer_common/sanitizer_common.h"
17 using namespace __sanitizer
;
18 using namespace __ubsan
;
20 static bool ignoreReport(SourceLocation SLoc
, ReportOptions Opts
) {
21 // If source location is already acquired, we don't need to print an error
22 // report for the second time. However, if we're in an unrecoverable handler,
23 // it's possible that location was required by concurrently running thread.
24 // In this case, we should continue the execution to ensure that any of
25 // threads will grab the report mutex and print the report before
26 // crashing the program.
27 return SLoc
.isDisabled() && !Opts
.DieAfterReport
;
31 const char *TypeCheckKinds
[] = {
32 "load of", "store to", "reference binding to", "member access within",
33 "member call on", "constructor call on", "downcast of", "downcast of",
34 "upcast of", "cast to virtual base of"};
37 static void handleTypeMismatchImpl(TypeMismatchData
*Data
, ValueHandle Pointer
,
38 Location FallbackLoc
, ReportOptions Opts
) {
39 Location Loc
= Data
->Loc
.acquire();
40 // Use the SourceLocation from Data to track deduplication, even if 'invalid'
41 if (ignoreReport(Loc
.getSourceLocation(), Opts
))
44 if (Data
->Loc
.isInvalid())
47 ScopedReport
R(Opts
, Loc
);
50 Diag(Loc
, DL_Error
, "%0 null pointer of type %1")
51 << TypeCheckKinds
[Data
->TypeCheckKind
] << Data
->Type
;
52 else if (Data
->Alignment
&& (Pointer
& (Data
->Alignment
- 1)))
53 Diag(Loc
, DL_Error
, "%0 misaligned address %1 for type %3, "
54 "which requires %2 byte alignment")
55 << TypeCheckKinds
[Data
->TypeCheckKind
] << (void*)Pointer
56 << Data
->Alignment
<< Data
->Type
;
58 Diag(Loc
, DL_Error
, "%0 address %1 with insufficient space "
59 "for an object of type %2")
60 << TypeCheckKinds
[Data
->TypeCheckKind
] << (void*)Pointer
<< Data
->Type
;
62 Diag(Pointer
, DL_Note
, "pointer points here");
65 void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData
*Data
,
66 ValueHandle Pointer
) {
67 GET_REPORT_OPTIONS(false);
68 handleTypeMismatchImpl(Data
, Pointer
, getCallerLocation(), Opts
);
70 void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData
*Data
,
71 ValueHandle Pointer
) {
72 GET_REPORT_OPTIONS(true);
73 handleTypeMismatchImpl(Data
, Pointer
, getCallerLocation(), Opts
);
77 /// \brief Common diagnostic emission for various forms of integer overflow.
79 static void handleIntegerOverflowImpl(OverflowData
*Data
, ValueHandle LHS
,
80 const char *Operator
, T RHS
,
82 SourceLocation Loc
= Data
->Loc
.acquire();
83 if (ignoreReport(Loc
, Opts
))
86 ScopedReport
R(Opts
, Loc
);
88 Diag(Loc
, DL_Error
, "%0 integer overflow: "
89 "%1 %2 %3 cannot be represented in type %4")
90 << (Data
->Type
.isSignedIntegerTy() ? "signed" : "unsigned")
91 << Value(Data
->Type
, LHS
) << Operator
<< RHS
<< Data
->Type
;
94 #define UBSAN_OVERFLOW_HANDLER(handler_name, op, abort) \
95 void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \
97 GET_REPORT_OPTIONS(abort); \
98 handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \
102 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow
, "+", false)
103 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort
, "+", true)
104 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow
, "-", false)
105 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort
, "-", true)
106 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow
, "*", false)
107 UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort
, "*", true)
109 static void handleNegateOverflowImpl(OverflowData
*Data
, ValueHandle OldVal
,
110 ReportOptions Opts
) {
111 SourceLocation Loc
= Data
->Loc
.acquire();
112 if (ignoreReport(Loc
, Opts
))
115 ScopedReport
R(Opts
, Loc
);
117 if (Data
->Type
.isSignedIntegerTy())
119 "negation of %0 cannot be represented in type %1; "
120 "cast to an unsigned type to negate this value to itself")
121 << Value(Data
->Type
, OldVal
) << Data
->Type
;
124 "negation of %0 cannot be represented in type %1")
125 << Value(Data
->Type
, OldVal
) << Data
->Type
;
128 void __ubsan::__ubsan_handle_negate_overflow(OverflowData
*Data
,
129 ValueHandle OldVal
) {
130 GET_REPORT_OPTIONS(false);
131 handleNegateOverflowImpl(Data
, OldVal
, Opts
);
133 void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData
*Data
,
134 ValueHandle OldVal
) {
135 GET_REPORT_OPTIONS(true);
136 handleNegateOverflowImpl(Data
, OldVal
, Opts
);
140 static void handleDivremOverflowImpl(OverflowData
*Data
, ValueHandle LHS
,
141 ValueHandle RHS
, ReportOptions Opts
) {
142 SourceLocation Loc
= Data
->Loc
.acquire();
143 if (ignoreReport(Loc
, Opts
))
146 ScopedReport
R(Opts
, Loc
);
148 Value
LHSVal(Data
->Type
, LHS
);
149 Value
RHSVal(Data
->Type
, RHS
);
150 if (RHSVal
.isMinusOne())
152 "division of %0 by -1 cannot be represented in type %1")
153 << LHSVal
<< Data
->Type
;
155 Diag(Loc
, DL_Error
, "division by zero");
158 void __ubsan::__ubsan_handle_divrem_overflow(OverflowData
*Data
,
159 ValueHandle LHS
, ValueHandle RHS
) {
160 GET_REPORT_OPTIONS(false);
161 handleDivremOverflowImpl(Data
, LHS
, RHS
, Opts
);
163 void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData
*Data
,
166 GET_REPORT_OPTIONS(true);
167 handleDivremOverflowImpl(Data
, LHS
, RHS
, Opts
);
171 static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData
*Data
,
172 ValueHandle LHS
, ValueHandle RHS
,
173 ReportOptions Opts
) {
174 SourceLocation Loc
= Data
->Loc
.acquire();
175 if (ignoreReport(Loc
, Opts
))
178 ScopedReport
R(Opts
, Loc
);
180 Value
LHSVal(Data
->LHSType
, LHS
);
181 Value
RHSVal(Data
->RHSType
, RHS
);
182 if (RHSVal
.isNegative())
183 Diag(Loc
, DL_Error
, "shift exponent %0 is negative") << RHSVal
;
184 else if (RHSVal
.getPositiveIntValue() >= Data
->LHSType
.getIntegerBitWidth())
186 "shift exponent %0 is too large for %1-bit type %2")
187 << RHSVal
<< Data
->LHSType
.getIntegerBitWidth() << Data
->LHSType
;
188 else if (LHSVal
.isNegative())
189 Diag(Loc
, DL_Error
, "left shift of negative value %0") << LHSVal
;
192 "left shift of %0 by %1 places cannot be represented in type %2")
193 << LHSVal
<< RHSVal
<< Data
->LHSType
;
196 void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData
*Data
,
199 GET_REPORT_OPTIONS(false);
200 handleShiftOutOfBoundsImpl(Data
, LHS
, RHS
, Opts
);
202 void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
203 ShiftOutOfBoundsData
*Data
,
206 GET_REPORT_OPTIONS(true);
207 handleShiftOutOfBoundsImpl(Data
, LHS
, RHS
, Opts
);
211 static void handleOutOfBoundsImpl(OutOfBoundsData
*Data
, ValueHandle Index
,
212 ReportOptions Opts
) {
213 SourceLocation Loc
= Data
->Loc
.acquire();
214 if (ignoreReport(Loc
, Opts
))
217 ScopedReport
R(Opts
, Loc
);
219 Value
IndexVal(Data
->IndexType
, Index
);
220 Diag(Loc
, DL_Error
, "index %0 out of bounds for type %1")
221 << IndexVal
<< Data
->ArrayType
;
224 void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData
*Data
,
226 GET_REPORT_OPTIONS(false);
227 handleOutOfBoundsImpl(Data
, Index
, Opts
);
229 void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData
*Data
,
231 GET_REPORT_OPTIONS(true);
232 handleOutOfBoundsImpl(Data
, Index
, Opts
);
236 static void handleBuiltinUnreachableImpl(UnreachableData
*Data
,
237 ReportOptions Opts
) {
238 ScopedReport
R(Opts
, Data
->Loc
);
239 Diag(Data
->Loc
, DL_Error
, "execution reached a __builtin_unreachable() call");
242 void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData
*Data
) {
243 GET_REPORT_OPTIONS(true);
244 handleBuiltinUnreachableImpl(Data
, Opts
);
248 static void handleMissingReturnImpl(UnreachableData
*Data
, ReportOptions Opts
) {
249 ScopedReport
R(Opts
, Data
->Loc
);
250 Diag(Data
->Loc
, DL_Error
,
251 "execution reached the end of a value-returning function "
252 "without returning a value");
255 void __ubsan::__ubsan_handle_missing_return(UnreachableData
*Data
) {
256 GET_REPORT_OPTIONS(true);
257 handleMissingReturnImpl(Data
, Opts
);
261 static void handleVLABoundNotPositive(VLABoundData
*Data
, ValueHandle Bound
,
262 ReportOptions Opts
) {
263 SourceLocation Loc
= Data
->Loc
.acquire();
264 if (ignoreReport(Loc
, Opts
))
267 ScopedReport
R(Opts
, Loc
);
269 Diag(Loc
, DL_Error
, "variable length array bound evaluates to "
270 "non-positive value %0")
271 << Value(Data
->Type
, Bound
);
274 void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData
*Data
,
276 GET_REPORT_OPTIONS(false);
277 handleVLABoundNotPositive(Data
, Bound
, Opts
);
279 void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData
*Data
,
281 GET_REPORT_OPTIONS(true);
282 handleVLABoundNotPositive(Data
, Bound
, Opts
);
286 static void handleFloatCastOverflow(FloatCastOverflowData
*Data
,
287 ValueHandle From
, ReportOptions Opts
) {
288 // TODO: Add deduplication once a SourceLocation is generated for this check.
289 Location Loc
= getCallerLocation();
290 ScopedReport
R(Opts
, Loc
);
293 "value %0 is outside the range of representable values of type %2")
294 << Value(Data
->FromType
, From
) << Data
->FromType
<< Data
->ToType
;
297 void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData
*Data
,
299 GET_REPORT_OPTIONS(false);
300 handleFloatCastOverflow(Data
, From
, Opts
);
303 __ubsan::__ubsan_handle_float_cast_overflow_abort(FloatCastOverflowData
*Data
,
305 GET_REPORT_OPTIONS(true);
306 handleFloatCastOverflow(Data
, From
, Opts
);
310 static void handleLoadInvalidValue(InvalidValueData
*Data
, ValueHandle Val
,
311 ReportOptions Opts
) {
312 SourceLocation Loc
= Data
->Loc
.acquire();
313 if (ignoreReport(Loc
, Opts
))
316 ScopedReport
R(Opts
, Loc
);
319 "load of value %0, which is not a valid value for type %1")
320 << Value(Data
->Type
, Val
) << Data
->Type
;
323 void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData
*Data
,
325 GET_REPORT_OPTIONS(false);
326 handleLoadInvalidValue(Data
, Val
, Opts
);
328 void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData
*Data
,
330 GET_REPORT_OPTIONS(true);
331 handleLoadInvalidValue(Data
, Val
, Opts
);
335 static void handleFunctionTypeMismatch(FunctionTypeMismatchData
*Data
,
336 ValueHandle Function
,
337 ReportOptions Opts
) {
338 const char *FName
= "(unknown)";
340 Location Loc
= getFunctionLocation(Function
, &FName
);
342 ScopedReport
R(Opts
, Loc
);
344 Diag(Data
->Loc
, DL_Error
,
345 "call to function %0 through pointer to incorrect function type %1")
346 << FName
<< Data
->Type
;
347 Diag(Loc
, DL_Note
, "%0 defined here") << FName
;
351 __ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData
*Data
,
352 ValueHandle Function
) {
353 GET_REPORT_OPTIONS(false);
354 handleFunctionTypeMismatch(Data
, Function
, Opts
);
357 void __ubsan::__ubsan_handle_function_type_mismatch_abort(
358 FunctionTypeMismatchData
*Data
, ValueHandle Function
) {
359 GET_REPORT_OPTIONS(true);
360 handleFunctionTypeMismatch(Data
, Function
, Opts
);
364 static void handleNonNullReturn(NonNullReturnData
*Data
, ReportOptions Opts
) {
365 SourceLocation Loc
= Data
->Loc
.acquire();
366 if (ignoreReport(Loc
, Opts
))
369 ScopedReport
R(Opts
, Loc
);
371 Diag(Loc
, DL_Error
, "null pointer returned from function declared to never "
373 if (!Data
->AttrLoc
.isInvalid())
374 Diag(Data
->AttrLoc
, DL_Note
, "returns_nonnull attribute specified here");
377 void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData
*Data
) {
378 GET_REPORT_OPTIONS(false);
379 handleNonNullReturn(Data
, Opts
);
382 void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData
*Data
) {
383 GET_REPORT_OPTIONS(true);
384 handleNonNullReturn(Data
, Opts
);
388 static void handleNonNullArg(NonNullArgData
*Data
, ReportOptions Opts
) {
389 SourceLocation Loc
= Data
->Loc
.acquire();
390 if (ignoreReport(Loc
, Opts
))
393 ScopedReport
R(Opts
, Loc
);
395 Diag(Loc
, DL_Error
, "null pointer passed as argument %0, which is declared to "
396 "never be null") << Data
->ArgIndex
;
397 if (!Data
->AttrLoc
.isInvalid())
398 Diag(Data
->AttrLoc
, DL_Note
, "nonnull attribute specified here");
401 void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData
*Data
) {
402 GET_REPORT_OPTIONS(false);
403 handleNonNullArg(Data
, Opts
);
406 void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData
*Data
) {
407 GET_REPORT_OPTIONS(true);
408 handleNonNullArg(Data
, Opts
);