2015-12-05 01:30:29 +08:00
|
|
|
==========================
|
|
|
|
UndefinedBehaviorSanitizer
|
|
|
|
==========================
|
|
|
|
|
|
|
|
.. contents::
|
|
|
|
:local:
|
|
|
|
|
|
|
|
Introduction
|
|
|
|
============
|
|
|
|
|
|
|
|
UndefinedBehaviorSanitizer (UBSan) is a fast undefined behavior detector.
|
|
|
|
UBSan modifies the program at compile-time to catch various kinds of undefined
|
|
|
|
behavior during program execution, for example:
|
|
|
|
|
|
|
|
* Using misaligned or null pointer
|
|
|
|
* Signed integer overflow
|
|
|
|
* Conversion to, from, or between floating-point types which would
|
|
|
|
overflow the destination
|
|
|
|
|
|
|
|
See the full list of available :ref:`checks <ubsan-checks>` below.
|
|
|
|
|
|
|
|
UBSan has an optional run-time library which provides better error reporting.
|
|
|
|
The checks have small runtime cost and no impact on address space layout or ABI.
|
|
|
|
|
|
|
|
How to build
|
|
|
|
============
|
|
|
|
|
2018-11-05 01:02:00 +08:00
|
|
|
Build LLVM/Clang with `CMake <https://llvm.org/docs/CMake.html>`_.
|
2015-12-05 01:30:29 +08:00
|
|
|
|
|
|
|
Usage
|
|
|
|
=====
|
|
|
|
|
|
|
|
Use ``clang++`` to compile and link your program with ``-fsanitize=undefined``
|
|
|
|
flag. Make sure to use ``clang++`` (not ``ld``) as a linker, so that your
|
|
|
|
executable is linked with proper UBSan runtime libraries. You can use ``clang``
|
|
|
|
instead of ``clang++`` if you're compiling/linking C code.
|
|
|
|
|
|
|
|
.. code-block:: console
|
|
|
|
|
|
|
|
% cat test.cc
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
int k = 0x7fffffff;
|
|
|
|
k += argc;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
% clang++ -fsanitize=undefined test.cc
|
|
|
|
% ./a.out
|
|
|
|
test.cc:3:5: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
|
|
|
|
|
|
|
|
You can enable only a subset of :ref:`checks <ubsan-checks>` offered by UBSan,
|
|
|
|
and define the desired behavior for each kind of check:
|
|
|
|
|
2017-03-21 05:40:58 +08:00
|
|
|
* ``-fsanitize=...``: print a verbose error report and continue execution (default);
|
|
|
|
* ``-fno-sanitize-recover=...``: print a verbose error report and exit the program;
|
|
|
|
* ``-fsanitize-trap=...``: execute a trap instruction (doesn't require UBSan run-time support).
|
2015-12-05 01:30:29 +08:00
|
|
|
|
|
|
|
For example if you compile/link your program as:
|
|
|
|
|
|
|
|
.. code-block:: console
|
|
|
|
|
|
|
|
% clang++ -fsanitize=signed-integer-overflow,null,alignment -fno-sanitize-recover=null -fsanitize-trap=alignment
|
|
|
|
|
|
|
|
the program will continue execution after signed integer overflows, exit after
|
|
|
|
the first invalid use of a null pointer, and trap after the first use of misaligned
|
|
|
|
pointer.
|
|
|
|
|
|
|
|
.. _ubsan-checks:
|
|
|
|
|
2016-09-21 02:37:25 +08:00
|
|
|
Available checks
|
|
|
|
================
|
2015-12-05 01:30:29 +08:00
|
|
|
|
|
|
|
Available checks are:
|
|
|
|
|
|
|
|
- ``-fsanitize=alignment``: Use of a misaligned pointer or creation
|
[clang][UBSan] Sanitization for alignment assumptions.
Summary:
UB isn't nice. It's cool and powerful, but not nice.
Having a way to detect it is nice though.
[[ https://wg21.link/p1007r3 | P1007R3: std::assume_aligned ]] / http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1007r2.pdf says:
```
We propose to add this functionality via a library function instead of a core language attribute.
...
If the pointer passed in is not aligned to at least N bytes, calling assume_aligned results in undefined behaviour.
```
This differential teaches clang to sanitize all the various variants of this assume-aligned attribute.
Requires D54588 for LLVM IRBuilder changes.
The compiler-rt part is D54590.
This is a second commit, the original one was r351105,
which was mass-reverted in r351159 because 2 compiler-rt tests were failing.
Reviewers: ABataev, craig.topper, vsk, rsmith, rnk, #sanitizers, erichkeane, filcab, rjmccall
Reviewed By: rjmccall
Subscribers: chandlerc, ldionne, EricWF, mclow.lists, cfe-commits, bkramer
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D54589
llvm-svn: 351177
2019-01-15 17:44:25 +08:00
|
|
|
of a misaligned reference. Also sanitizes assume_aligned-like attributes.
|
2015-12-05 01:30:29 +08:00
|
|
|
- ``-fsanitize=bool``: Load of a ``bool`` value which is neither
|
|
|
|
``true`` nor ``false``.
|
2017-07-29 08:19:51 +08:00
|
|
|
- ``-fsanitize=builtin``: Passing invalid values to compiler builtins.
|
2015-12-05 01:30:29 +08:00
|
|
|
- ``-fsanitize=bounds``: Out of bounds array indexing, in cases
|
|
|
|
where the array bound can be statically determined.
|
|
|
|
- ``-fsanitize=enum``: Load of a value of an enumerated type which
|
|
|
|
is not in the range of representable values for that enumerated
|
|
|
|
type.
|
|
|
|
- ``-fsanitize=float-cast-overflow``: Conversion to, from, or
|
|
|
|
between floating-point types which would overflow the
|
Treat the range of representable values of floating-point types as [-inf, +inf] not as [-max, +max].
Summary:
Prior to r329065, we used [-max, max] as the range of representable
values because LLVM's `fptrunc` did not guarantee defined behavior when
truncating from a larger floating-point type to a smaller one. Now that
has been fixed, we can make clang follow normal IEEE 754 semantics in this
regard and take the larger range [-inf, +inf] as the range of representable
values.
In practice, this affects two parts of the frontend:
* the constant evaluator no longer treats floating-point evaluations
that result in +-inf as being undefined (because they no longer leave
the range of representable values of the type)
* UBSan no longer treats conversions to floating-point type that are
outside the [-max, +max] range as being undefined
In passing, also remove the float-divide-by-zero sanitizer from
-fsanitize=undefined, on the basis that while it's undefined per C++
rules (and we disallow it in constant expressions for that reason), it
is defined by Clang / LLVM / IEEE 754.
Reviewers: rnk, BillyONeal
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D63793
llvm-svn: 365272
2019-07-07 05:05:52 +08:00
|
|
|
destination. Because the range of representable values for all
|
|
|
|
floating-point types supported by Clang is [-inf, +inf], the only
|
|
|
|
cases detected are conversions from floating point to integer types.
|
2015-12-05 01:30:29 +08:00
|
|
|
- ``-fsanitize=float-divide-by-zero``: Floating point division by
|
Treat the range of representable values of floating-point types as [-inf, +inf] not as [-max, +max].
Summary:
Prior to r329065, we used [-max, max] as the range of representable
values because LLVM's `fptrunc` did not guarantee defined behavior when
truncating from a larger floating-point type to a smaller one. Now that
has been fixed, we can make clang follow normal IEEE 754 semantics in this
regard and take the larger range [-inf, +inf] as the range of representable
values.
In practice, this affects two parts of the frontend:
* the constant evaluator no longer treats floating-point evaluations
that result in +-inf as being undefined (because they no longer leave
the range of representable values of the type)
* UBSan no longer treats conversions to floating-point type that are
outside the [-max, +max] range as being undefined
In passing, also remove the float-divide-by-zero sanitizer from
-fsanitize=undefined, on the basis that while it's undefined per C++
rules (and we disallow it in constant expressions for that reason), it
is defined by Clang / LLVM / IEEE 754.
Reviewers: rnk, BillyONeal
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D63793
llvm-svn: 365272
2019-07-07 05:05:52 +08:00
|
|
|
zero. This is undefined per the C and C++ standards, but is defined
|
|
|
|
by Clang (and by ISO/IEC/IEEE 60559 / IEEE 754) as producing either an
|
|
|
|
infinity or NaN value, so is not included in ``-fsanitize=undefined``.
|
2015-12-05 01:30:29 +08:00
|
|
|
- ``-fsanitize=function``: Indirect call of a function through a
|
2017-09-13 08:04:36 +08:00
|
|
|
function pointer of the wrong type (Darwin/Linux, C++ and x86/x86_64
|
|
|
|
only).
|
2018-10-11 17:09:50 +08:00
|
|
|
- ``-fsanitize=implicit-unsigned-integer-truncation``,
|
|
|
|
``-fsanitize=implicit-signed-integer-truncation``: Implicit conversion from
|
[clang][ubsan] Implicit Conversion Sanitizer - integer truncation - clang part
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
unsigned char store = 0;
bool consume(unsigned int val);
void test(unsigned long val) {
if (consume(val)) {
// the 'val' is `unsigned long`, but `consume()` takes `unsigned int`.
// If their bit widths are different on this platform, the implicit
// truncation happens. And if that `unsigned long` had a value bigger
// than UINT_MAX, then you may or may not have a bug.
// Similarly, integer addition happens on `int`s, so `store` will
// be promoted to an `int`, the sum calculated (0+768=768),
// and the result demoted to `unsigned char`, and stored to `store`.
// In this case, the `store` will still be 0. Again, not always intended.
store = store + 768; // before addition, 'store' was promoted to int.
}
// But yes, sometimes this is intentional.
// You can either make the conversion explicit
(void)consume((unsigned int)val);
// or mask the value so no bits will be *implicitly* lost.
(void)consume((~((unsigned int)0)) & val);
}
```
Yes, there is a `-Wconversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, there are cases where it does **not** warn.
So a Sanitizer is needed. I don't have any motivational numbers, but i know
i had this kind of problem 10-20 times, and it was never easy to track down.
The logic to detect whether an truncation has happened is pretty simple
if you think about it - https://godbolt.org/g/NEzXbb - basically, just
extend (using the new, not original!, signedness) the 'truncated' value
back to it's original width, and equality-compare it with the original value.
The most non-trivial thing here is the logic to detect whether this
`ImplicitCastExpr` AST node is **actually** an implicit conversion, //or//
part of an explicit cast. Because the explicit casts are modeled as an outer
`ExplicitCastExpr` with some `ImplicitCastExpr`'s as **direct** children.
https://godbolt.org/g/eE1GkJ
Nowadays, we can just use the new `part_of_explicit_cast` flag, which is set
on all the implicitly-added `ImplicitCastExpr`'s of an `ExplicitCastExpr`.
So if that flag is **not** set, then it is an actual implicit conversion.
As you may have noted, this isn't just named `-fsanitize=implicit-integer-truncation`.
There are potentially some more implicit conversions to be warned about.
Namely, implicit conversions that result in sign change; implicit conversion
between different floating point types, or between fp and an integer,
when again, that conversion is lossy.
One thing i know isn't handled is bitfields.
This is a clang part.
The compiler-rt part is D48959.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Partially fixes [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Fixes https://github.com/google/sanitizers/issues/940. (other than sign-changing implicit conversions)
Reviewers: rjmccall, rsmith, samsonov, pcc, vsk, eugenis, efriedma, kcc, erichkeane
Reviewed By: rsmith, vsk, erichkeane
Subscribers: erichkeane, klimek, #sanitizers, aaron.ballman, RKSimon, dtzWill, filcab, danielaustin, ygribov, dvyukov, milianw, mclow.lists, cfe-commits, regehr
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D48958
llvm-svn: 338288
2018-07-31 02:58:30 +08:00
|
|
|
integer of larger bit width to smaller bit width, if that results in data
|
|
|
|
loss. That is, if the demoted value, after casting back to the original
|
|
|
|
width, is not equal to the original value before the downcast.
|
2018-10-11 17:09:50 +08:00
|
|
|
The ``-fsanitize=implicit-unsigned-integer-truncation`` handles conversions
|
|
|
|
between two ``unsigned`` types, while
|
|
|
|
``-fsanitize=implicit-signed-integer-truncation`` handles the rest of the
|
|
|
|
conversions - when either one, or both of the types are signed.
|
|
|
|
Issues caught by these sanitizers are not undefined behavior,
|
[clang][ubsan] Implicit Conversion Sanitizer - integer truncation - clang part
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
unsigned char store = 0;
bool consume(unsigned int val);
void test(unsigned long val) {
if (consume(val)) {
// the 'val' is `unsigned long`, but `consume()` takes `unsigned int`.
// If their bit widths are different on this platform, the implicit
// truncation happens. And if that `unsigned long` had a value bigger
// than UINT_MAX, then you may or may not have a bug.
// Similarly, integer addition happens on `int`s, so `store` will
// be promoted to an `int`, the sum calculated (0+768=768),
// and the result demoted to `unsigned char`, and stored to `store`.
// In this case, the `store` will still be 0. Again, not always intended.
store = store + 768; // before addition, 'store' was promoted to int.
}
// But yes, sometimes this is intentional.
// You can either make the conversion explicit
(void)consume((unsigned int)val);
// or mask the value so no bits will be *implicitly* lost.
(void)consume((~((unsigned int)0)) & val);
}
```
Yes, there is a `-Wconversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, there are cases where it does **not** warn.
So a Sanitizer is needed. I don't have any motivational numbers, but i know
i had this kind of problem 10-20 times, and it was never easy to track down.
The logic to detect whether an truncation has happened is pretty simple
if you think about it - https://godbolt.org/g/NEzXbb - basically, just
extend (using the new, not original!, signedness) the 'truncated' value
back to it's original width, and equality-compare it with the original value.
The most non-trivial thing here is the logic to detect whether this
`ImplicitCastExpr` AST node is **actually** an implicit conversion, //or//
part of an explicit cast. Because the explicit casts are modeled as an outer
`ExplicitCastExpr` with some `ImplicitCastExpr`'s as **direct** children.
https://godbolt.org/g/eE1GkJ
Nowadays, we can just use the new `part_of_explicit_cast` flag, which is set
on all the implicitly-added `ImplicitCastExpr`'s of an `ExplicitCastExpr`.
So if that flag is **not** set, then it is an actual implicit conversion.
As you may have noted, this isn't just named `-fsanitize=implicit-integer-truncation`.
There are potentially some more implicit conversions to be warned about.
Namely, implicit conversions that result in sign change; implicit conversion
between different floating point types, or between fp and an integer,
when again, that conversion is lossy.
One thing i know isn't handled is bitfields.
This is a clang part.
The compiler-rt part is D48959.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Partially fixes [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Fixes https://github.com/google/sanitizers/issues/940. (other than sign-changing implicit conversions)
Reviewers: rjmccall, rsmith, samsonov, pcc, vsk, eugenis, efriedma, kcc, erichkeane
Reviewed By: rsmith, vsk, erichkeane
Subscribers: erichkeane, klimek, #sanitizers, aaron.ballman, RKSimon, dtzWill, filcab, danielaustin, ygribov, dvyukov, milianw, mclow.lists, cfe-commits, regehr
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D48958
llvm-svn: 338288
2018-07-31 02:58:30 +08:00
|
|
|
but are often unintentional.
|
[clang][ubsan] Implicit Conversion Sanitizer - integer sign change - clang part
This is the second half of Implicit Integer Conversion Sanitizer.
It completes the first half, and finally makes the sanitizer
fully functional! Only the bitfield handling is missing.
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
void consume(unsigned int val);
void test(int val) {
consume(val);
// The 'val' is `signed int`, but `consume()` takes `unsigned int`.
// If val is negative, then consume() will be operating on a large
// unsigned value, and you may or may not have a bug.
// But yes, sometimes this is intentional.
// Making the conversion explicit silences the sanitizer.
consume((unsigned int)val);
}
```
Yes, there is a `-Wsign-conversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, likely there are cases where it does **not** warn.
The actual detection is pretty easy. We just need to check each of the values
whether it is negative, and equality-compare the results of those comparisons.
The unsigned value is obviously non-negative. Zero is non-negative too.
https://godbolt.org/g/w93oj2
We do not have to emit the check *always*, there are obvious situations
where we can avoid emitting it, since it would **always** get optimized-out.
But i do think the tautological IR (`icmp ult %x, 0`, which is always false)
should be emitted, and the middle-end should cleanup it.
This sanitizer is in the `-fsanitize=implicit-conversion` group,
and is a logical continuation of D48958 `-fsanitize=implicit-integer-truncation`.
As for the ordering, i'we opted to emit the check **after**
`-fsanitize=implicit-integer-truncation`. At least on these simple 16 test cases,
this results in 1 of the 12 emitted checks being optimized away,
as compared to 0 checks being optimized away if the order is reversed.
This is a clang part.
The compiler-rt part is D50251.
Finishes fixing [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Finishes partially fixing [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Finishes fixing https://github.com/google/sanitizers/issues/940.
Only the bitfield handling is missing.
Reviewers: vsk, rsmith, rjmccall, #sanitizers, erichkeane
Reviewed By: rsmith
Subscribers: chandlerc, filcab, cfe-commits, regehr
Tags: #sanitizers, #clang
Differential Revision: https://reviews.llvm.org/D50250
llvm-svn: 345660
2018-10-31 05:58:56 +08:00
|
|
|
- ``-fsanitize=implicit-integer-sign-change``: Implicit conversion between
|
|
|
|
integer types, if that changes the sign of the value. That is, if the the
|
|
|
|
original value was negative and the new value is positive (or zero),
|
|
|
|
or the original value was positive, and the new value is negative.
|
|
|
|
Issues caught by this sanitizer are not undefined behavior,
|
|
|
|
but are often unintentional.
|
2015-12-05 01:30:29 +08:00
|
|
|
- ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
|
|
|
|
- ``-fsanitize=nonnull-attribute``: Passing null pointer as a function
|
|
|
|
parameter which is declared to never be null.
|
|
|
|
- ``-fsanitize=null``: Use of a null pointer or creation of a null
|
|
|
|
reference.
|
2017-03-14 09:56:34 +08:00
|
|
|
- ``-fsanitize=nullability-arg``: Passing null as a function parameter
|
|
|
|
which is annotated with ``_Nonnull``.
|
|
|
|
- ``-fsanitize=nullability-assign``: Assigning null to an lvalue which
|
|
|
|
is annotated with ``_Nonnull``.
|
|
|
|
- ``-fsanitize=nullability-return``: Returning null from a function with
|
|
|
|
a return type annotated with ``_Nonnull``.
|
2016-04-26 03:21:45 +08:00
|
|
|
- ``-fsanitize=object-size``: An attempt to potentially use bytes which
|
2016-04-26 08:31:29 +08:00
|
|
|
the optimizer can determine are not part of the object being accessed.
|
|
|
|
This will also detect some types of undefined behavior that may not
|
|
|
|
directly access memory, but are provably incorrect given the size of
|
|
|
|
the objects involved, such as invalid downcasts and calling methods on
|
|
|
|
invalid pointers. These checks are made in terms of
|
|
|
|
``__builtin_object_size``, and consequently may be able to detect more
|
|
|
|
problems at higher optimization levels.
|
2017-06-02 03:22:18 +08:00
|
|
|
- ``-fsanitize=pointer-overflow``: Performing pointer arithmetic which
|
|
|
|
overflows.
|
2015-12-05 01:30:29 +08:00
|
|
|
- ``-fsanitize=return``: In C++, reaching the end of a
|
|
|
|
value-returning function without returning a value.
|
|
|
|
- ``-fsanitize=returns-nonnull-attribute``: Returning null pointer
|
|
|
|
from a function which is declared to never return null.
|
|
|
|
- ``-fsanitize=shift``: Shift operators where the amount shifted is
|
|
|
|
greater or equal to the promoted bit-width of the left hand side
|
|
|
|
or less than zero, or where the left hand side is negative. For a
|
|
|
|
signed left shift, also checks for signed overflow in C, and for
|
|
|
|
unsigned overflow in C++. You can use ``-fsanitize=shift-base`` or
|
|
|
|
``-fsanitize=shift-exponent`` to check only left-hand side or
|
|
|
|
right-hand side of shift operation, respectively.
|
[clang][ubsan] Implicit Conversion Sanitizer - integer truncation - clang part
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
unsigned char store = 0;
bool consume(unsigned int val);
void test(unsigned long val) {
if (consume(val)) {
// the 'val' is `unsigned long`, but `consume()` takes `unsigned int`.
// If their bit widths are different on this platform, the implicit
// truncation happens. And if that `unsigned long` had a value bigger
// than UINT_MAX, then you may or may not have a bug.
// Similarly, integer addition happens on `int`s, so `store` will
// be promoted to an `int`, the sum calculated (0+768=768),
// and the result demoted to `unsigned char`, and stored to `store`.
// In this case, the `store` will still be 0. Again, not always intended.
store = store + 768; // before addition, 'store' was promoted to int.
}
// But yes, sometimes this is intentional.
// You can either make the conversion explicit
(void)consume((unsigned int)val);
// or mask the value so no bits will be *implicitly* lost.
(void)consume((~((unsigned int)0)) & val);
}
```
Yes, there is a `-Wconversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, there are cases where it does **not** warn.
So a Sanitizer is needed. I don't have any motivational numbers, but i know
i had this kind of problem 10-20 times, and it was never easy to track down.
The logic to detect whether an truncation has happened is pretty simple
if you think about it - https://godbolt.org/g/NEzXbb - basically, just
extend (using the new, not original!, signedness) the 'truncated' value
back to it's original width, and equality-compare it with the original value.
The most non-trivial thing here is the logic to detect whether this
`ImplicitCastExpr` AST node is **actually** an implicit conversion, //or//
part of an explicit cast. Because the explicit casts are modeled as an outer
`ExplicitCastExpr` with some `ImplicitCastExpr`'s as **direct** children.
https://godbolt.org/g/eE1GkJ
Nowadays, we can just use the new `part_of_explicit_cast` flag, which is set
on all the implicitly-added `ImplicitCastExpr`'s of an `ExplicitCastExpr`.
So if that flag is **not** set, then it is an actual implicit conversion.
As you may have noted, this isn't just named `-fsanitize=implicit-integer-truncation`.
There are potentially some more implicit conversions to be warned about.
Namely, implicit conversions that result in sign change; implicit conversion
between different floating point types, or between fp and an integer,
when again, that conversion is lossy.
One thing i know isn't handled is bitfields.
This is a clang part.
The compiler-rt part is D48959.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Partially fixes [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Fixes https://github.com/google/sanitizers/issues/940. (other than sign-changing implicit conversions)
Reviewers: rjmccall, rsmith, samsonov, pcc, vsk, eugenis, efriedma, kcc, erichkeane
Reviewed By: rsmith, vsk, erichkeane
Subscribers: erichkeane, klimek, #sanitizers, aaron.ballman, RKSimon, dtzWill, filcab, danielaustin, ygribov, dvyukov, milianw, mclow.lists, cfe-commits, regehr
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D48958
llvm-svn: 338288
2018-07-31 02:58:30 +08:00
|
|
|
- ``-fsanitize=signed-integer-overflow``: Signed integer overflow, where the
|
|
|
|
result of a signed integer computation cannot be represented in its type.
|
|
|
|
This includes all the checks covered by ``-ftrapv``, as well as checks for
|
|
|
|
signed division overflow (``INT_MIN/-1``), but not checks for
|
2018-07-31 05:11:32 +08:00
|
|
|
lossy implicit conversions performed before the computation
|
[clang][ubsan] Implicit Conversion Sanitizer - integer truncation - clang part
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
unsigned char store = 0;
bool consume(unsigned int val);
void test(unsigned long val) {
if (consume(val)) {
// the 'val' is `unsigned long`, but `consume()` takes `unsigned int`.
// If their bit widths are different on this platform, the implicit
// truncation happens. And if that `unsigned long` had a value bigger
// than UINT_MAX, then you may or may not have a bug.
// Similarly, integer addition happens on `int`s, so `store` will
// be promoted to an `int`, the sum calculated (0+768=768),
// and the result demoted to `unsigned char`, and stored to `store`.
// In this case, the `store` will still be 0. Again, not always intended.
store = store + 768; // before addition, 'store' was promoted to int.
}
// But yes, sometimes this is intentional.
// You can either make the conversion explicit
(void)consume((unsigned int)val);
// or mask the value so no bits will be *implicitly* lost.
(void)consume((~((unsigned int)0)) & val);
}
```
Yes, there is a `-Wconversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, there are cases where it does **not** warn.
So a Sanitizer is needed. I don't have any motivational numbers, but i know
i had this kind of problem 10-20 times, and it was never easy to track down.
The logic to detect whether an truncation has happened is pretty simple
if you think about it - https://godbolt.org/g/NEzXbb - basically, just
extend (using the new, not original!, signedness) the 'truncated' value
back to it's original width, and equality-compare it with the original value.
The most non-trivial thing here is the logic to detect whether this
`ImplicitCastExpr` AST node is **actually** an implicit conversion, //or//
part of an explicit cast. Because the explicit casts are modeled as an outer
`ExplicitCastExpr` with some `ImplicitCastExpr`'s as **direct** children.
https://godbolt.org/g/eE1GkJ
Nowadays, we can just use the new `part_of_explicit_cast` flag, which is set
on all the implicitly-added `ImplicitCastExpr`'s of an `ExplicitCastExpr`.
So if that flag is **not** set, then it is an actual implicit conversion.
As you may have noted, this isn't just named `-fsanitize=implicit-integer-truncation`.
There are potentially some more implicit conversions to be warned about.
Namely, implicit conversions that result in sign change; implicit conversion
between different floating point types, or between fp and an integer,
when again, that conversion is lossy.
One thing i know isn't handled is bitfields.
This is a clang part.
The compiler-rt part is D48959.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Partially fixes [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Fixes https://github.com/google/sanitizers/issues/940. (other than sign-changing implicit conversions)
Reviewers: rjmccall, rsmith, samsonov, pcc, vsk, eugenis, efriedma, kcc, erichkeane
Reviewed By: rsmith, vsk, erichkeane
Subscribers: erichkeane, klimek, #sanitizers, aaron.ballman, RKSimon, dtzWill, filcab, danielaustin, ygribov, dvyukov, milianw, mclow.lists, cfe-commits, regehr
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D48958
llvm-svn: 338288
2018-07-31 02:58:30 +08:00
|
|
|
(see ``-fsanitize=implicit-conversion``). Both of these two issues are
|
|
|
|
handled by ``-fsanitize=implicit-conversion`` group of checks.
|
2017-12-21 08:10:25 +08:00
|
|
|
- ``-fsanitize=unreachable``: If control flow reaches an unreachable
|
|
|
|
program point.
|
[clang][ubsan] Implicit Conversion Sanitizer - integer truncation - clang part
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
unsigned char store = 0;
bool consume(unsigned int val);
void test(unsigned long val) {
if (consume(val)) {
// the 'val' is `unsigned long`, but `consume()` takes `unsigned int`.
// If their bit widths are different on this platform, the implicit
// truncation happens. And if that `unsigned long` had a value bigger
// than UINT_MAX, then you may or may not have a bug.
// Similarly, integer addition happens on `int`s, so `store` will
// be promoted to an `int`, the sum calculated (0+768=768),
// and the result demoted to `unsigned char`, and stored to `store`.
// In this case, the `store` will still be 0. Again, not always intended.
store = store + 768; // before addition, 'store' was promoted to int.
}
// But yes, sometimes this is intentional.
// You can either make the conversion explicit
(void)consume((unsigned int)val);
// or mask the value so no bits will be *implicitly* lost.
(void)consume((~((unsigned int)0)) & val);
}
```
Yes, there is a `-Wconversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, there are cases where it does **not** warn.
So a Sanitizer is needed. I don't have any motivational numbers, but i know
i had this kind of problem 10-20 times, and it was never easy to track down.
The logic to detect whether an truncation has happened is pretty simple
if you think about it - https://godbolt.org/g/NEzXbb - basically, just
extend (using the new, not original!, signedness) the 'truncated' value
back to it's original width, and equality-compare it with the original value.
The most non-trivial thing here is the logic to detect whether this
`ImplicitCastExpr` AST node is **actually** an implicit conversion, //or//
part of an explicit cast. Because the explicit casts are modeled as an outer
`ExplicitCastExpr` with some `ImplicitCastExpr`'s as **direct** children.
https://godbolt.org/g/eE1GkJ
Nowadays, we can just use the new `part_of_explicit_cast` flag, which is set
on all the implicitly-added `ImplicitCastExpr`'s of an `ExplicitCastExpr`.
So if that flag is **not** set, then it is an actual implicit conversion.
As you may have noted, this isn't just named `-fsanitize=implicit-integer-truncation`.
There are potentially some more implicit conversions to be warned about.
Namely, implicit conversions that result in sign change; implicit conversion
between different floating point types, or between fp and an integer,
when again, that conversion is lossy.
One thing i know isn't handled is bitfields.
This is a clang part.
The compiler-rt part is D48959.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Partially fixes [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Fixes https://github.com/google/sanitizers/issues/940. (other than sign-changing implicit conversions)
Reviewers: rjmccall, rsmith, samsonov, pcc, vsk, eugenis, efriedma, kcc, erichkeane
Reviewed By: rsmith, vsk, erichkeane
Subscribers: erichkeane, klimek, #sanitizers, aaron.ballman, RKSimon, dtzWill, filcab, danielaustin, ygribov, dvyukov, milianw, mclow.lists, cfe-commits, regehr
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D48958
llvm-svn: 338288
2018-07-31 02:58:30 +08:00
|
|
|
- ``-fsanitize=unsigned-integer-overflow``: Unsigned integer overflow, where
|
|
|
|
the result of an unsigned integer computation cannot be represented in its
|
|
|
|
type. Unlike signed integer overflow, this is not undefined behavior, but
|
|
|
|
it is often unintentional. This sanitizer does not check for lossy implicit
|
2018-07-31 05:11:32 +08:00
|
|
|
conversions performed before such a computation
|
[clang][ubsan] Implicit Conversion Sanitizer - integer truncation - clang part
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
unsigned char store = 0;
bool consume(unsigned int val);
void test(unsigned long val) {
if (consume(val)) {
// the 'val' is `unsigned long`, but `consume()` takes `unsigned int`.
// If their bit widths are different on this platform, the implicit
// truncation happens. And if that `unsigned long` had a value bigger
// than UINT_MAX, then you may or may not have a bug.
// Similarly, integer addition happens on `int`s, so `store` will
// be promoted to an `int`, the sum calculated (0+768=768),
// and the result demoted to `unsigned char`, and stored to `store`.
// In this case, the `store` will still be 0. Again, not always intended.
store = store + 768; // before addition, 'store' was promoted to int.
}
// But yes, sometimes this is intentional.
// You can either make the conversion explicit
(void)consume((unsigned int)val);
// or mask the value so no bits will be *implicitly* lost.
(void)consume((~((unsigned int)0)) & val);
}
```
Yes, there is a `-Wconversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, there are cases where it does **not** warn.
So a Sanitizer is needed. I don't have any motivational numbers, but i know
i had this kind of problem 10-20 times, and it was never easy to track down.
The logic to detect whether an truncation has happened is pretty simple
if you think about it - https://godbolt.org/g/NEzXbb - basically, just
extend (using the new, not original!, signedness) the 'truncated' value
back to it's original width, and equality-compare it with the original value.
The most non-trivial thing here is the logic to detect whether this
`ImplicitCastExpr` AST node is **actually** an implicit conversion, //or//
part of an explicit cast. Because the explicit casts are modeled as an outer
`ExplicitCastExpr` with some `ImplicitCastExpr`'s as **direct** children.
https://godbolt.org/g/eE1GkJ
Nowadays, we can just use the new `part_of_explicit_cast` flag, which is set
on all the implicitly-added `ImplicitCastExpr`'s of an `ExplicitCastExpr`.
So if that flag is **not** set, then it is an actual implicit conversion.
As you may have noted, this isn't just named `-fsanitize=implicit-integer-truncation`.
There are potentially some more implicit conversions to be warned about.
Namely, implicit conversions that result in sign change; implicit conversion
between different floating point types, or between fp and an integer,
when again, that conversion is lossy.
One thing i know isn't handled is bitfields.
This is a clang part.
The compiler-rt part is D48959.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Partially fixes [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Fixes https://github.com/google/sanitizers/issues/940. (other than sign-changing implicit conversions)
Reviewers: rjmccall, rsmith, samsonov, pcc, vsk, eugenis, efriedma, kcc, erichkeane
Reviewed By: rsmith, vsk, erichkeane
Subscribers: erichkeane, klimek, #sanitizers, aaron.ballman, RKSimon, dtzWill, filcab, danielaustin, ygribov, dvyukov, milianw, mclow.lists, cfe-commits, regehr
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D48958
llvm-svn: 338288
2018-07-31 02:58:30 +08:00
|
|
|
(see ``-fsanitize=implicit-conversion``).
|
2015-12-05 01:30:29 +08:00
|
|
|
- ``-fsanitize=vla-bound``: A variable-length array whose bound
|
|
|
|
does not evaluate to a positive value.
|
2017-07-26 03:34:23 +08:00
|
|
|
- ``-fsanitize=vptr``: Use of an object whose vptr indicates that it is of
|
2017-08-03 02:24:12 +08:00
|
|
|
the wrong dynamic type, or that its lifetime has not begun or has ended.
|
|
|
|
Incompatible with ``-fno-rtti``. Link must be performed by ``clang++``, not
|
|
|
|
``clang``, to make sure C++-specific parts of the runtime library and C++
|
|
|
|
standard libraries are present.
|
2015-12-05 01:30:29 +08:00
|
|
|
|
|
|
|
You can also use the following check groups:
|
|
|
|
- ``-fsanitize=undefined``: All of the checks listed above other than
|
Treat the range of representable values of floating-point types as [-inf, +inf] not as [-max, +max].
Summary:
Prior to r329065, we used [-max, max] as the range of representable
values because LLVM's `fptrunc` did not guarantee defined behavior when
truncating from a larger floating-point type to a smaller one. Now that
has been fixed, we can make clang follow normal IEEE 754 semantics in this
regard and take the larger range [-inf, +inf] as the range of representable
values.
In practice, this affects two parts of the frontend:
* the constant evaluator no longer treats floating-point evaluations
that result in +-inf as being undefined (because they no longer leave
the range of representable values of the type)
* UBSan no longer treats conversions to floating-point type that are
outside the [-max, +max] range as being undefined
In passing, also remove the float-divide-by-zero sanitizer from
-fsanitize=undefined, on the basis that while it's undefined per C++
rules (and we disallow it in constant expressions for that reason), it
is defined by Clang / LLVM / IEEE 754.
Reviewers: rnk, BillyONeal
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D63793
llvm-svn: 365272
2019-07-07 05:05:52 +08:00
|
|
|
``float-divide-by-zero``, ``unsigned-integer-overflow``,
|
|
|
|
``implicit-conversion``, and the ``nullability-*`` group of checks.
|
2015-12-05 01:30:29 +08:00
|
|
|
- ``-fsanitize=undefined-trap``: Deprecated alias of
|
|
|
|
``-fsanitize=undefined``.
|
[clang][ubsan] Implicit Conversion Sanitizer - integer sign change - clang part
This is the second half of Implicit Integer Conversion Sanitizer.
It completes the first half, and finally makes the sanitizer
fully functional! Only the bitfield handling is missing.
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
void consume(unsigned int val);
void test(int val) {
consume(val);
// The 'val' is `signed int`, but `consume()` takes `unsigned int`.
// If val is negative, then consume() will be operating on a large
// unsigned value, and you may or may not have a bug.
// But yes, sometimes this is intentional.
// Making the conversion explicit silences the sanitizer.
consume((unsigned int)val);
}
```
Yes, there is a `-Wsign-conversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, likely there are cases where it does **not** warn.
The actual detection is pretty easy. We just need to check each of the values
whether it is negative, and equality-compare the results of those comparisons.
The unsigned value is obviously non-negative. Zero is non-negative too.
https://godbolt.org/g/w93oj2
We do not have to emit the check *always*, there are obvious situations
where we can avoid emitting it, since it would **always** get optimized-out.
But i do think the tautological IR (`icmp ult %x, 0`, which is always false)
should be emitted, and the middle-end should cleanup it.
This sanitizer is in the `-fsanitize=implicit-conversion` group,
and is a logical continuation of D48958 `-fsanitize=implicit-integer-truncation`.
As for the ordering, i'we opted to emit the check **after**
`-fsanitize=implicit-integer-truncation`. At least on these simple 16 test cases,
this results in 1 of the 12 emitted checks being optimized away,
as compared to 0 checks being optimized away if the order is reversed.
This is a clang part.
The compiler-rt part is D50251.
Finishes fixing [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Finishes partially fixing [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Finishes fixing https://github.com/google/sanitizers/issues/940.
Only the bitfield handling is missing.
Reviewers: vsk, rsmith, rjmccall, #sanitizers, erichkeane
Reviewed By: rsmith
Subscribers: chandlerc, filcab, cfe-commits, regehr
Tags: #sanitizers, #clang
Differential Revision: https://reviews.llvm.org/D50250
llvm-svn: 345660
2018-10-31 05:58:56 +08:00
|
|
|
- ``-fsanitize=implicit-integer-truncation``: Catches lossy integral
|
|
|
|
conversions. Enables ``implicit-signed-integer-truncation`` and
|
|
|
|
``implicit-unsigned-integer-truncation``.
|
|
|
|
- ``-fsanitize=implicit-integer-arithmetic-value-change``: Catches implicit
|
|
|
|
conversions that change the arithmetic value of the integer. Enables
|
|
|
|
``implicit-signed-integer-truncation`` and ``implicit-integer-sign-change``.
|
|
|
|
- ``-fsanitize=implicit-conversion``: Checks for suspicious
|
Treat the range of representable values of floating-point types as [-inf, +inf] not as [-max, +max].
Summary:
Prior to r329065, we used [-max, max] as the range of representable
values because LLVM's `fptrunc` did not guarantee defined behavior when
truncating from a larger floating-point type to a smaller one. Now that
has been fixed, we can make clang follow normal IEEE 754 semantics in this
regard and take the larger range [-inf, +inf] as the range of representable
values.
In practice, this affects two parts of the frontend:
* the constant evaluator no longer treats floating-point evaluations
that result in +-inf as being undefined (because they no longer leave
the range of representable values of the type)
* UBSan no longer treats conversions to floating-point type that are
outside the [-max, +max] range as being undefined
In passing, also remove the float-divide-by-zero sanitizer from
-fsanitize=undefined, on the basis that while it's undefined per C++
rules (and we disallow it in constant expressions for that reason), it
is defined by Clang / LLVM / IEEE 754.
Reviewers: rnk, BillyONeal
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D63793
llvm-svn: 365272
2019-07-07 05:05:52 +08:00
|
|
|
behavior of implicit conversions. Enables
|
[clang][ubsan] Implicit Conversion Sanitizer - integer sign change - clang part
This is the second half of Implicit Integer Conversion Sanitizer.
It completes the first half, and finally makes the sanitizer
fully functional! Only the bitfield handling is missing.
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
void consume(unsigned int val);
void test(int val) {
consume(val);
// The 'val' is `signed int`, but `consume()` takes `unsigned int`.
// If val is negative, then consume() will be operating on a large
// unsigned value, and you may or may not have a bug.
// But yes, sometimes this is intentional.
// Making the conversion explicit silences the sanitizer.
consume((unsigned int)val);
}
```
Yes, there is a `-Wsign-conversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, likely there are cases where it does **not** warn.
The actual detection is pretty easy. We just need to check each of the values
whether it is negative, and equality-compare the results of those comparisons.
The unsigned value is obviously non-negative. Zero is non-negative too.
https://godbolt.org/g/w93oj2
We do not have to emit the check *always*, there are obvious situations
where we can avoid emitting it, since it would **always** get optimized-out.
But i do think the tautological IR (`icmp ult %x, 0`, which is always false)
should be emitted, and the middle-end should cleanup it.
This sanitizer is in the `-fsanitize=implicit-conversion` group,
and is a logical continuation of D48958 `-fsanitize=implicit-integer-truncation`.
As for the ordering, i'we opted to emit the check **after**
`-fsanitize=implicit-integer-truncation`. At least on these simple 16 test cases,
this results in 1 of the 12 emitted checks being optimized away,
as compared to 0 checks being optimized away if the order is reversed.
This is a clang part.
The compiler-rt part is D50251.
Finishes fixing [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Finishes partially fixing [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Finishes fixing https://github.com/google/sanitizers/issues/940.
Only the bitfield handling is missing.
Reviewers: vsk, rsmith, rjmccall, #sanitizers, erichkeane
Reviewed By: rsmith
Subscribers: chandlerc, filcab, cfe-commits, regehr
Tags: #sanitizers, #clang
Differential Revision: https://reviews.llvm.org/D50250
llvm-svn: 345660
2018-10-31 05:58:56 +08:00
|
|
|
``implicit-unsigned-integer-truncation``,
|
Treat the range of representable values of floating-point types as [-inf, +inf] not as [-max, +max].
Summary:
Prior to r329065, we used [-max, max] as the range of representable
values because LLVM's `fptrunc` did not guarantee defined behavior when
truncating from a larger floating-point type to a smaller one. Now that
has been fixed, we can make clang follow normal IEEE 754 semantics in this
regard and take the larger range [-inf, +inf] as the range of representable
values.
In practice, this affects two parts of the frontend:
* the constant evaluator no longer treats floating-point evaluations
that result in +-inf as being undefined (because they no longer leave
the range of representable values of the type)
* UBSan no longer treats conversions to floating-point type that are
outside the [-max, +max] range as being undefined
In passing, also remove the float-divide-by-zero sanitizer from
-fsanitize=undefined, on the basis that while it's undefined per C++
rules (and we disallow it in constant expressions for that reason), it
is defined by Clang / LLVM / IEEE 754.
Reviewers: rnk, BillyONeal
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D63793
llvm-svn: 365272
2019-07-07 05:05:52 +08:00
|
|
|
``implicit-signed-integer-truncation``, and
|
[clang][ubsan] Implicit Conversion Sanitizer - integer sign change - clang part
This is the second half of Implicit Integer Conversion Sanitizer.
It completes the first half, and finally makes the sanitizer
fully functional! Only the bitfield handling is missing.
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
void consume(unsigned int val);
void test(int val) {
consume(val);
// The 'val' is `signed int`, but `consume()` takes `unsigned int`.
// If val is negative, then consume() will be operating on a large
// unsigned value, and you may or may not have a bug.
// But yes, sometimes this is intentional.
// Making the conversion explicit silences the sanitizer.
consume((unsigned int)val);
}
```
Yes, there is a `-Wsign-conversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, likely there are cases where it does **not** warn.
The actual detection is pretty easy. We just need to check each of the values
whether it is negative, and equality-compare the results of those comparisons.
The unsigned value is obviously non-negative. Zero is non-negative too.
https://godbolt.org/g/w93oj2
We do not have to emit the check *always*, there are obvious situations
where we can avoid emitting it, since it would **always** get optimized-out.
But i do think the tautological IR (`icmp ult %x, 0`, which is always false)
should be emitted, and the middle-end should cleanup it.
This sanitizer is in the `-fsanitize=implicit-conversion` group,
and is a logical continuation of D48958 `-fsanitize=implicit-integer-truncation`.
As for the ordering, i'we opted to emit the check **after**
`-fsanitize=implicit-integer-truncation`. At least on these simple 16 test cases,
this results in 1 of the 12 emitted checks being optimized away,
as compared to 0 checks being optimized away if the order is reversed.
This is a clang part.
The compiler-rt part is D50251.
Finishes fixing [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Finishes partially fixing [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Finishes fixing https://github.com/google/sanitizers/issues/940.
Only the bitfield handling is missing.
Reviewers: vsk, rsmith, rjmccall, #sanitizers, erichkeane
Reviewed By: rsmith
Subscribers: chandlerc, filcab, cfe-commits, regehr
Tags: #sanitizers, #clang
Differential Revision: https://reviews.llvm.org/D50250
llvm-svn: 345660
2018-10-31 05:58:56 +08:00
|
|
|
``implicit-integer-sign-change``.
|
2015-12-05 01:30:29 +08:00
|
|
|
- ``-fsanitize=integer``: Checks for undefined or suspicious integer
|
|
|
|
behavior (e.g. unsigned integer overflow).
|
[clang][ubsan] Implicit Conversion Sanitizer - integer truncation - clang part
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
unsigned char store = 0;
bool consume(unsigned int val);
void test(unsigned long val) {
if (consume(val)) {
// the 'val' is `unsigned long`, but `consume()` takes `unsigned int`.
// If their bit widths are different on this platform, the implicit
// truncation happens. And if that `unsigned long` had a value bigger
// than UINT_MAX, then you may or may not have a bug.
// Similarly, integer addition happens on `int`s, so `store` will
// be promoted to an `int`, the sum calculated (0+768=768),
// and the result demoted to `unsigned char`, and stored to `store`.
// In this case, the `store` will still be 0. Again, not always intended.
store = store + 768; // before addition, 'store' was promoted to int.
}
// But yes, sometimes this is intentional.
// You can either make the conversion explicit
(void)consume((unsigned int)val);
// or mask the value so no bits will be *implicitly* lost.
(void)consume((~((unsigned int)0)) & val);
}
```
Yes, there is a `-Wconversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, there are cases where it does **not** warn.
So a Sanitizer is needed. I don't have any motivational numbers, but i know
i had this kind of problem 10-20 times, and it was never easy to track down.
The logic to detect whether an truncation has happened is pretty simple
if you think about it - https://godbolt.org/g/NEzXbb - basically, just
extend (using the new, not original!, signedness) the 'truncated' value
back to it's original width, and equality-compare it with the original value.
The most non-trivial thing here is the logic to detect whether this
`ImplicitCastExpr` AST node is **actually** an implicit conversion, //or//
part of an explicit cast. Because the explicit casts are modeled as an outer
`ExplicitCastExpr` with some `ImplicitCastExpr`'s as **direct** children.
https://godbolt.org/g/eE1GkJ
Nowadays, we can just use the new `part_of_explicit_cast` flag, which is set
on all the implicitly-added `ImplicitCastExpr`'s of an `ExplicitCastExpr`.
So if that flag is **not** set, then it is an actual implicit conversion.
As you may have noted, this isn't just named `-fsanitize=implicit-integer-truncation`.
There are potentially some more implicit conversions to be warned about.
Namely, implicit conversions that result in sign change; implicit conversion
between different floating point types, or between fp and an integer,
when again, that conversion is lossy.
One thing i know isn't handled is bitfields.
This is a clang part.
The compiler-rt part is D48959.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Partially fixes [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Fixes https://github.com/google/sanitizers/issues/940. (other than sign-changing implicit conversions)
Reviewers: rjmccall, rsmith, samsonov, pcc, vsk, eugenis, efriedma, kcc, erichkeane
Reviewed By: rsmith, vsk, erichkeane
Subscribers: erichkeane, klimek, #sanitizers, aaron.ballman, RKSimon, dtzWill, filcab, danielaustin, ygribov, dvyukov, milianw, mclow.lists, cfe-commits, regehr
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D48958
llvm-svn: 338288
2018-07-31 02:58:30 +08:00
|
|
|
Enables ``signed-integer-overflow``, ``unsigned-integer-overflow``,
|
[clang][ubsan] Implicit Conversion Sanitizer - integer sign change - clang part
This is the second half of Implicit Integer Conversion Sanitizer.
It completes the first half, and finally makes the sanitizer
fully functional! Only the bitfield handling is missing.
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
void consume(unsigned int val);
void test(int val) {
consume(val);
// The 'val' is `signed int`, but `consume()` takes `unsigned int`.
// If val is negative, then consume() will be operating on a large
// unsigned value, and you may or may not have a bug.
// But yes, sometimes this is intentional.
// Making the conversion explicit silences the sanitizer.
consume((unsigned int)val);
}
```
Yes, there is a `-Wsign-conversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, likely there are cases where it does **not** warn.
The actual detection is pretty easy. We just need to check each of the values
whether it is negative, and equality-compare the results of those comparisons.
The unsigned value is obviously non-negative. Zero is non-negative too.
https://godbolt.org/g/w93oj2
We do not have to emit the check *always*, there are obvious situations
where we can avoid emitting it, since it would **always** get optimized-out.
But i do think the tautological IR (`icmp ult %x, 0`, which is always false)
should be emitted, and the middle-end should cleanup it.
This sanitizer is in the `-fsanitize=implicit-conversion` group,
and is a logical continuation of D48958 `-fsanitize=implicit-integer-truncation`.
As for the ordering, i'we opted to emit the check **after**
`-fsanitize=implicit-integer-truncation`. At least on these simple 16 test cases,
this results in 1 of the 12 emitted checks being optimized away,
as compared to 0 checks being optimized away if the order is reversed.
This is a clang part.
The compiler-rt part is D50251.
Finishes fixing [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Finishes partially fixing [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Finishes fixing https://github.com/google/sanitizers/issues/940.
Only the bitfield handling is missing.
Reviewers: vsk, rsmith, rjmccall, #sanitizers, erichkeane
Reviewed By: rsmith
Subscribers: chandlerc, filcab, cfe-commits, regehr
Tags: #sanitizers, #clang
Differential Revision: https://reviews.llvm.org/D50250
llvm-svn: 345660
2018-10-31 05:58:56 +08:00
|
|
|
``shift``, ``integer-divide-by-zero``,
|
|
|
|
``implicit-unsigned-integer-truncation``,
|
Treat the range of representable values of floating-point types as [-inf, +inf] not as [-max, +max].
Summary:
Prior to r329065, we used [-max, max] as the range of representable
values because LLVM's `fptrunc` did not guarantee defined behavior when
truncating from a larger floating-point type to a smaller one. Now that
has been fixed, we can make clang follow normal IEEE 754 semantics in this
regard and take the larger range [-inf, +inf] as the range of representable
values.
In practice, this affects two parts of the frontend:
* the constant evaluator no longer treats floating-point evaluations
that result in +-inf as being undefined (because they no longer leave
the range of representable values of the type)
* UBSan no longer treats conversions to floating-point type that are
outside the [-max, +max] range as being undefined
In passing, also remove the float-divide-by-zero sanitizer from
-fsanitize=undefined, on the basis that while it's undefined per C++
rules (and we disallow it in constant expressions for that reason), it
is defined by Clang / LLVM / IEEE 754.
Reviewers: rnk, BillyONeal
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D63793
llvm-svn: 365272
2019-07-07 05:05:52 +08:00
|
|
|
``implicit-signed-integer-truncation``, and
|
[clang][ubsan] Implicit Conversion Sanitizer - integer sign change - clang part
This is the second half of Implicit Integer Conversion Sanitizer.
It completes the first half, and finally makes the sanitizer
fully functional! Only the bitfield handling is missing.
Summary:
C and C++ are interesting languages. They are statically typed, but weakly.
The implicit conversions are allowed. This is nice, allows to write code
while balancing between getting drowned in everything being convertible,
and nothing being convertible. As usual, this comes with a price:
```
void consume(unsigned int val);
void test(int val) {
consume(val);
// The 'val' is `signed int`, but `consume()` takes `unsigned int`.
// If val is negative, then consume() will be operating on a large
// unsigned value, and you may or may not have a bug.
// But yes, sometimes this is intentional.
// Making the conversion explicit silences the sanitizer.
consume((unsigned int)val);
}
```
Yes, there is a `-Wsign-conversion`` diagnostic group, but first, it is kinda
noisy, since it warns on everything (unlike sanitizers, warning on an
actual issues), and second, likely there are cases where it does **not** warn.
The actual detection is pretty easy. We just need to check each of the values
whether it is negative, and equality-compare the results of those comparisons.
The unsigned value is obviously non-negative. Zero is non-negative too.
https://godbolt.org/g/w93oj2
We do not have to emit the check *always*, there are obvious situations
where we can avoid emitting it, since it would **always** get optimized-out.
But i do think the tautological IR (`icmp ult %x, 0`, which is always false)
should be emitted, and the middle-end should cleanup it.
This sanitizer is in the `-fsanitize=implicit-conversion` group,
and is a logical continuation of D48958 `-fsanitize=implicit-integer-truncation`.
As for the ordering, i'we opted to emit the check **after**
`-fsanitize=implicit-integer-truncation`. At least on these simple 16 test cases,
this results in 1 of the 12 emitted checks being optimized away,
as compared to 0 checks being optimized away if the order is reversed.
This is a clang part.
The compiler-rt part is D50251.
Finishes fixing [[ https://bugs.llvm.org/show_bug.cgi?id=21530 | PR21530 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=37552 | PR37552 ]], [[ https://bugs.llvm.org/show_bug.cgi?id=35409 | PR35409 ]].
Finishes partially fixing [[ https://bugs.llvm.org/show_bug.cgi?id=9821 | PR9821 ]].
Finishes fixing https://github.com/google/sanitizers/issues/940.
Only the bitfield handling is missing.
Reviewers: vsk, rsmith, rjmccall, #sanitizers, erichkeane
Reviewed By: rsmith
Subscribers: chandlerc, filcab, cfe-commits, regehr
Tags: #sanitizers, #clang
Differential Revision: https://reviews.llvm.org/D50250
llvm-svn: 345660
2018-10-31 05:58:56 +08:00
|
|
|
``implicit-integer-sign-change``.
|
2017-03-14 09:56:34 +08:00
|
|
|
- ``-fsanitize=nullability``: Enables ``nullability-arg``,
|
|
|
|
``nullability-assign``, and ``nullability-return``. While violating
|
|
|
|
nullability does not have undefined behavior, it is often unintentional,
|
|
|
|
so UBSan offers to catch it.
|
2015-12-05 01:30:29 +08:00
|
|
|
|
2017-06-17 02:38:43 +08:00
|
|
|
Volatile
|
|
|
|
--------
|
|
|
|
|
|
|
|
The ``null``, ``alignment``, ``object-size``, and ``vptr`` checks do not apply
|
|
|
|
to pointers to types with the ``volatile`` qualifier.
|
|
|
|
|
2017-09-12 05:37:05 +08:00
|
|
|
Minimal Runtime
|
|
|
|
===============
|
|
|
|
|
|
|
|
There is a minimal UBSan runtime available suitable for use in production
|
|
|
|
environments. This runtime has a small attack surface. It only provides very
|
2019-07-16 14:23:27 +08:00
|
|
|
basic issue logging and deduplication, and does not support
|
|
|
|
``-fsanitize=function`` and ``-fsanitize=vptr`` checking.
|
2017-09-12 05:37:05 +08:00
|
|
|
|
|
|
|
To use the minimal runtime, add ``-fsanitize-minimal-runtime`` to the clang
|
|
|
|
command line options. For example, if you're used to compiling with
|
|
|
|
``-fsanitize=undefined``, you could enable the minimal runtime with
|
|
|
|
``-fsanitize=undefined -fsanitize-minimal-runtime``.
|
|
|
|
|
2015-12-05 01:30:29 +08:00
|
|
|
Stack traces and report symbolization
|
|
|
|
=====================================
|
|
|
|
If you want UBSan to print symbolized stack trace for each error report, you
|
|
|
|
will need to:
|
|
|
|
|
|
|
|
#. Compile with ``-g`` and ``-fno-omit-frame-pointer`` to get proper debug
|
|
|
|
information in your binary.
|
|
|
|
#. Run your program with environment variable
|
|
|
|
``UBSAN_OPTIONS=print_stacktrace=1``.
|
|
|
|
#. Make sure ``llvm-symbolizer`` binary is in ``PATH``.
|
|
|
|
|
2018-06-28 02:24:46 +08:00
|
|
|
Silencing Unsigned Integer Overflow
|
|
|
|
===================================
|
|
|
|
To silence reports from unsigned integer overflow, you can set
|
|
|
|
``UBSAN_OPTIONS=silence_unsigned_overflow=1``. This feature, combined with
|
|
|
|
``-fsanitize-recover=unsigned-integer-overflow``, is particularly useful for
|
|
|
|
providing fuzzing signal without blowing up logs.
|
|
|
|
|
2015-12-05 01:30:29 +08:00
|
|
|
Issue Suppression
|
|
|
|
=================
|
|
|
|
|
|
|
|
UndefinedBehaviorSanitizer is not expected to produce false positives.
|
|
|
|
If you see one, look again; most likely it is a true positive!
|
|
|
|
|
|
|
|
Disabling Instrumentation with ``__attribute__((no_sanitize("undefined")))``
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
You disable UBSan checks for particular functions with
|
|
|
|
``__attribute__((no_sanitize("undefined")))``. You can use all values of
|
|
|
|
``-fsanitize=`` flag in this attribute, e.g. if your function deliberately
|
|
|
|
contains possible signed integer overflow, you can use
|
|
|
|
``__attribute__((no_sanitize("signed-integer-overflow")))``.
|
|
|
|
|
|
|
|
This attribute may not be
|
|
|
|
supported by other compilers, so consider using it together with
|
|
|
|
``#if defined(__clang__)``.
|
|
|
|
|
|
|
|
Suppressing Errors in Recompiled Code (Blacklist)
|
|
|
|
-------------------------------------------------
|
|
|
|
|
|
|
|
UndefinedBehaviorSanitizer supports ``src`` and ``fun`` entity types in
|
|
|
|
:doc:`SanitizerSpecialCaseList`, that can be used to suppress error reports
|
|
|
|
in the specified source files or functions.
|
|
|
|
|
2016-01-30 07:07:14 +08:00
|
|
|
Runtime suppressions
|
|
|
|
--------------------
|
|
|
|
|
|
|
|
Sometimes you can suppress UBSan error reports for specific files, functions,
|
|
|
|
or libraries without recompiling the code. You need to pass a path to
|
|
|
|
suppression file in a ``UBSAN_OPTIONS`` environment variable.
|
|
|
|
|
|
|
|
.. code-block:: bash
|
|
|
|
|
|
|
|
UBSAN_OPTIONS=suppressions=MyUBSan.supp
|
|
|
|
|
|
|
|
You need to specify a :ref:`check <ubsan-checks>` you are suppressing and the
|
|
|
|
bug location. For example:
|
|
|
|
|
|
|
|
.. code-block:: bash
|
|
|
|
|
|
|
|
signed-integer-overflow:file-with-known-overflow.cpp
|
|
|
|
alignment:function_doing_unaligned_access
|
|
|
|
vptr:shared_object_with_vptr_failures.so
|
|
|
|
|
|
|
|
There are several limitations:
|
|
|
|
|
|
|
|
* Sometimes your binary must have enough debug info and/or symbol table, so
|
|
|
|
that the runtime could figure out source file or function name to match
|
|
|
|
against the suppression.
|
|
|
|
* It is only possible to suppress recoverable checks. For the example above,
|
|
|
|
you can additionally pass
|
|
|
|
``-fsanitize-recover=signed-integer-overflow,alignment,vptr``, although
|
|
|
|
most of UBSan checks are recoverable by default.
|
|
|
|
* Check groups (like ``undefined``) can't be used in suppressions file, only
|
|
|
|
fine-grained checks are supported.
|
|
|
|
|
2015-12-05 01:30:29 +08:00
|
|
|
Supported Platforms
|
|
|
|
===================
|
|
|
|
|
2018-11-27 11:55:15 +08:00
|
|
|
UndefinedBehaviorSanitizer is supported on the following operating systems:
|
2015-12-05 01:30:29 +08:00
|
|
|
|
|
|
|
* Android
|
|
|
|
* Linux
|
2018-07-25 21:55:06 +08:00
|
|
|
* NetBSD
|
2015-12-05 01:30:29 +08:00
|
|
|
* FreeBSD
|
2018-07-25 21:55:06 +08:00
|
|
|
* OpenBSD
|
[Docs] Modernize references to macOS
Summary:
This updates all places in documentation that refer to "Mac OS X", "OS X", etc.
to instead use the modern name "macOS" when no specific version number is
mentioned.
If a specific version is mentioned, this attempts to use the OS name at the time
of that version:
* Mac OS X for 10.0 - 10.7
* OS X for 10.8 - 10.11
* macOS for 10.12 - present
Reviewers: JDevlieghere
Subscribers: mgorny, christof, arphaman, cfe-commits, lldb-commits, libcxx-commits, llvm-commits
Tags: #clang, #lldb, #libc, #llvm
Differential Revision: https://reviews.llvm.org/D62654
llvm-svn: 362113
2019-05-31 00:46:22 +08:00
|
|
|
* macOS
|
2018-11-27 11:55:15 +08:00
|
|
|
* Windows
|
|
|
|
|
|
|
|
The runtime library is relatively portable and platform independent. If the OS
|
|
|
|
you need is not listed above, UndefinedBehaviorSanitizer may already work for
|
|
|
|
it, or could be made to work with a minor porting effort.
|
2015-12-05 01:30:29 +08:00
|
|
|
|
|
|
|
Current Status
|
|
|
|
==============
|
|
|
|
|
|
|
|
UndefinedBehaviorSanitizer is available on selected platforms starting from LLVM
|
|
|
|
3.3. The test suite is integrated into the CMake build and can be run with
|
|
|
|
``check-ubsan`` command.
|
|
|
|
|
2016-05-13 00:51:36 +08:00
|
|
|
Additional Configuration
|
|
|
|
========================
|
|
|
|
|
|
|
|
UndefinedBehaviorSanitizer adds static check data for each check unless it is
|
|
|
|
in trap mode. This check data includes the full file name. The option
|
|
|
|
``-fsanitize-undefined-strip-path-components=N`` can be used to trim this
|
|
|
|
information. If ``N`` is positive, file information emitted by
|
|
|
|
UndefinedBehaviorSanitizer will drop the first ``N`` components from the file
|
|
|
|
path. If ``N`` is negative, the last ``N`` components will be kept.
|
|
|
|
|
|
|
|
Example
|
|
|
|
-------
|
|
|
|
|
|
|
|
For a file called ``/code/library/file.cpp``, here is what would be emitted:
|
2018-11-27 11:55:15 +08:00
|
|
|
|
2016-05-13 00:51:36 +08:00
|
|
|
* Default (No flag, or ``-fsanitize-undefined-strip-path-components=0``): ``/code/library/file.cpp``
|
|
|
|
* ``-fsanitize-undefined-strip-path-components=1``: ``code/library/file.cpp``
|
|
|
|
* ``-fsanitize-undefined-strip-path-components=2``: ``library/file.cpp``
|
|
|
|
* ``-fsanitize-undefined-strip-path-components=-1``: ``file.cpp``
|
|
|
|
* ``-fsanitize-undefined-strip-path-components=-2``: ``library/file.cpp``
|
|
|
|
|
2015-12-05 01:30:29 +08:00
|
|
|
More Information
|
|
|
|
================
|
|
|
|
|
|
|
|
* From LLVM project blog:
|
|
|
|
`What Every C Programmer Should Know About Undefined Behavior
|
|
|
|
<http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html>`_
|
|
|
|
* From John Regehr's *Embedded in Academia* blog:
|
|
|
|
`A Guide to Undefined Behavior in C and C++
|
2019-01-24 04:39:07 +08:00
|
|
|
<https://blog.regehr.org/archives/213>`_
|