xref: /netbsd-src/external/gpl3/gcc.old/dist/libsanitizer/ubsan/ubsan_handlers.cc (revision 7863ba460b0a05b553c754e5dbc29247dddec322)
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 //===----------------------------------------------------------------------===//
11 
12 #include "ubsan_handlers.h"
13 #include "ubsan_diag.h"
14 
15 #include "sanitizer_common/sanitizer_common.h"
16 
17 using namespace __sanitizer;
18 using namespace __ubsan;
19 
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;
28 }
29 
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"};
35 }
36 
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;
43 
44   if (Data->Loc.isInvalid())
45     Loc = FallbackLoc;
46 
47   ScopedReport R(Opts, Loc);
48 
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");
63 }
64 
65 void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data,
66                                            ValueHandle Pointer) {
67   GET_REPORT_OPTIONS(false);
68   handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), Opts);
69 }
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();
75 }
76 
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;
85 
86   ScopedReport R(Opts, Loc);
87 
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;
92 }
93 
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();                                                          \
100   }
101 
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)
108 
109 static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,
110                                      ReportOptions Opts) {
111   SourceLocation Loc = Data->Loc.acquire();
112   if (ignoreReport(Loc, Opts))
113     return;
114 
115   ScopedReport R(Opts, Loc);
116 
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;
126 }
127 
128 void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
129                                              ValueHandle OldVal) {
130   GET_REPORT_OPTIONS(false);
131   handleNegateOverflowImpl(Data, OldVal, Opts);
132 }
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();
138 }
139 
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;
145 
146   ScopedReport R(Opts, Loc);
147 
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");
156 }
157 
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);
162 }
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();
169 }
170 
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;
177 
178   ScopedReport R(Opts, Loc);
179 
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;
194 }
195 
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);
201 }
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();
209 }
210 
211 static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
212                                   ReportOptions Opts) {
213   SourceLocation Loc = Data->Loc.acquire();
214   if (ignoreReport(Loc, Opts))
215     return;
216 
217   ScopedReport R(Opts, Loc);
218 
219   Value IndexVal(Data->IndexType, Index);
220   Diag(Loc, DL_Error, "index %0 out of bounds for type %1")
221     << IndexVal << Data->ArrayType;
222 }
223 
224 void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data,
225                                            ValueHandle Index) {
226   GET_REPORT_OPTIONS(false);
227   handleOutOfBoundsImpl(Data, Index, Opts);
228 }
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();
234 }
235 
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");
240 }
241 
242 void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
243   GET_REPORT_OPTIONS(true);
244   handleBuiltinUnreachableImpl(Data, Opts);
245   Die();
246 }
247 
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");
253 }
254 
255 void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
256   GET_REPORT_OPTIONS(true);
257   handleMissingReturnImpl(Data, Opts);
258   Die();
259 }
260 
261 static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
262                                       ReportOptions Opts) {
263   SourceLocation Loc = Data->Loc.acquire();
264   if (ignoreReport(Loc, Opts))
265     return;
266 
267   ScopedReport R(Opts, Loc);
268 
269   Diag(Loc, DL_Error, "variable length array bound evaluates to "
270                       "non-positive value %0")
271     << Value(Data->Type, Bound);
272 }
273 
274 void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
275                                                     ValueHandle Bound) {
276   GET_REPORT_OPTIONS(false);
277   handleVLABoundNotPositive(Data, Bound, Opts);
278 }
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();
284 }
285 
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);
291 
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;
295 }
296 
297 void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data,
298                                                  ValueHandle From) {
299   GET_REPORT_OPTIONS(false);
300   handleFloatCastOverflow(Data, From, Opts);
301 }
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();
308 }
309 
310 static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
311                                    ReportOptions Opts) {
312   SourceLocation Loc = Data->Loc.acquire();
313   if (ignoreReport(Loc, Opts))
314     return;
315 
316   ScopedReport R(Opts, Loc);
317 
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;
321 }
322 
323 void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
324                                                 ValueHandle Val) {
325   GET_REPORT_OPTIONS(false);
326   handleLoadInvalidValue(Data, Val, Opts);
327 }
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();
333 }
334 
335 static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
336                                        ValueHandle Function,
337                                        ReportOptions Opts) {
338   const char *FName = "(unknown)";
339 
340   Location Loc = getFunctionLocation(Function, &FName);
341 
342   ScopedReport R(Opts, Loc);
343 
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;
348 }
349 
350 void
351 __ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data,
352                                                ValueHandle Function) {
353   GET_REPORT_OPTIONS(false);
354   handleFunctionTypeMismatch(Data, Function, Opts);
355 }
356 
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();
362 }
363 
364 static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
365   SourceLocation Loc = Data->Loc.acquire();
366   if (ignoreReport(Loc, Opts))
367     return;
368 
369   ScopedReport R(Opts, Loc);
370 
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");
375 }
376 
377 void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) {
378   GET_REPORT_OPTIONS(false);
379   handleNonNullReturn(Data, Opts);
380 }
381 
382 void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
383   GET_REPORT_OPTIONS(true);
384   handleNonNullReturn(Data, Opts);
385   Die();
386 }
387 
388 static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
389   SourceLocation Loc = Data->Loc.acquire();
390   if (ignoreReport(Loc, Opts))
391     return;
392 
393   ScopedReport R(Opts, Loc);
394 
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");
399 }
400 
401 void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {
402   GET_REPORT_OPTIONS(false);
403   handleNonNullArg(Data, Opts);
404 }
405 
406 void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
407   GET_REPORT_OPTIONS(true);
408   handleNonNullArg(Data, Opts);
409   Die();
410 }
411