2015-03-05 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / libsanitizer / ubsan / ubsan_handlers.cc
blob770d3c28a4a9138d53ff300f8d45bcf0a8dd05c2
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 //===----------------------------------------------------------------------===//
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;
30 namespace __ubsan {
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))
42 return;
44 if (Data->Loc.isInvalid())
45 Loc = FallbackLoc;
47 ScopedReport R(Opts, Loc);
49 if (!Pointer)
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;
57 else
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;
61 if (Pointer)
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);
74 Die();
77 /// \brief Common diagnostic emission for various forms of integer overflow.
78 template <typename T>
79 static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,
80 const char *Operator, T RHS,
81 ReportOptions Opts) {
82 SourceLocation Loc = Data->Loc.acquire();
83 if (ignoreReport(Loc, Opts))
84 return;
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, \
96 ValueHandle RHS) { \
97 GET_REPORT_OPTIONS(abort); \
98 handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \
99 if (abort) Die(); \
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))
113 return;
115 ScopedReport R(Opts, Loc);
117 if (Data->Type.isSignedIntegerTy())
118 Diag(Loc, DL_Error,
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;
122 else
123 Diag(Loc, DL_Error,
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);
137 Die();
140 static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,
141 ValueHandle RHS, ReportOptions Opts) {
142 SourceLocation Loc = Data->Loc.acquire();
143 if (ignoreReport(Loc, Opts))
144 return;
146 ScopedReport R(Opts, Loc);
148 Value LHSVal(Data->Type, LHS);
149 Value RHSVal(Data->Type, RHS);
150 if (RHSVal.isMinusOne())
151 Diag(Loc, DL_Error,
152 "division of %0 by -1 cannot be represented in type %1")
153 << LHSVal << Data->Type;
154 else
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,
164 ValueHandle LHS,
165 ValueHandle RHS) {
166 GET_REPORT_OPTIONS(true);
167 handleDivremOverflowImpl(Data, LHS, RHS, Opts);
168 Die();
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))
176 return;
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())
185 Diag(Loc, DL_Error,
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;
190 else
191 Diag(Loc, DL_Error,
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,
197 ValueHandle LHS,
198 ValueHandle RHS) {
199 GET_REPORT_OPTIONS(false);
200 handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
202 void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
203 ShiftOutOfBoundsData *Data,
204 ValueHandle LHS,
205 ValueHandle RHS) {
206 GET_REPORT_OPTIONS(true);
207 handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
208 Die();
211 static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
212 ReportOptions Opts) {
213 SourceLocation Loc = Data->Loc.acquire();
214 if (ignoreReport(Loc, Opts))
215 return;
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,
225 ValueHandle Index) {
226 GET_REPORT_OPTIONS(false);
227 handleOutOfBoundsImpl(Data, Index, Opts);
229 void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,
230 ValueHandle Index) {
231 GET_REPORT_OPTIONS(true);
232 handleOutOfBoundsImpl(Data, Index, Opts);
233 Die();
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);
245 Die();
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);
258 Die();
261 static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
262 ReportOptions Opts) {
263 SourceLocation Loc = Data->Loc.acquire();
264 if (ignoreReport(Loc, Opts))
265 return;
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,
275 ValueHandle Bound) {
276 GET_REPORT_OPTIONS(false);
277 handleVLABoundNotPositive(Data, Bound, Opts);
279 void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data,
280 ValueHandle Bound) {
281 GET_REPORT_OPTIONS(true);
282 handleVLABoundNotPositive(Data, Bound, Opts);
283 Die();
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);
292 Diag(Loc, DL_Error,
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,
298 ValueHandle From) {
299 GET_REPORT_OPTIONS(false);
300 handleFloatCastOverflow(Data, From, Opts);
302 void
303 __ubsan::__ubsan_handle_float_cast_overflow_abort(FloatCastOverflowData *Data,
304 ValueHandle From) {
305 GET_REPORT_OPTIONS(true);
306 handleFloatCastOverflow(Data, From, Opts);
307 Die();
310 static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
311 ReportOptions Opts) {
312 SourceLocation Loc = Data->Loc.acquire();
313 if (ignoreReport(Loc, Opts))
314 return;
316 ScopedReport R(Opts, Loc);
318 Diag(Loc, DL_Error,
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,
324 ValueHandle Val) {
325 GET_REPORT_OPTIONS(false);
326 handleLoadInvalidValue(Data, Val, Opts);
328 void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,
329 ValueHandle Val) {
330 GET_REPORT_OPTIONS(true);
331 handleLoadInvalidValue(Data, Val, Opts);
332 Die();
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;
350 void
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);
361 Die();
364 static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
365 SourceLocation Loc = Data->Loc.acquire();
366 if (ignoreReport(Loc, Opts))
367 return;
369 ScopedReport R(Opts, Loc);
371 Diag(Loc, DL_Error, "null pointer returned from function declared to never "
372 "return null");
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);
385 Die();
388 static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
389 SourceLocation Loc = Data->Loc.acquire();
390 if (ignoreReport(Loc, Opts))
391 return;
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);
409 Die();