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
|
|
|
|
============
|
|
|
|
|
|
|
|
Build LLVM/Clang with `CMake <http://llvm.org/docs/CMake.html>`_.
|
|
|
|
|
|
|
|
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
|
|
|
|
of a misaligned reference.
|
|
|
|
- ``-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
|
|
|
|
destination.
|
|
|
|
- ``-fsanitize=float-divide-by-zero``: Floating point division by
|
|
|
|
zero.
|
|
|
|
- ``-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).
|
[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=implicit-integer-truncation``: Implicit conversion from
|
|
|
|
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.
|
|
|
|
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
|
[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
|
|
|
``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``.
|
|
|
|
- ``-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``,
|
|
|
|
``shift``, ``integer-divide-by-zero``, and ``implicit-integer-truncation``.
|
|
|
|
- ``-fsanitize=implicit-conversion``: Checks for suspicious behaviours of
|
|
|
|
implicit conversions.
|
|
|
|
Currently, only ``-fsanitize=implicit-integer-truncation`` is implemented.
|
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
|
|
|
|
basic issue logging and deduplication, and does not support ``-fsanitize=vptr``
|
|
|
|
checking.
|
|
|
|
|
|
|
|
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
|
|
|
|
===================
|
|
|
|
|
|
|
|
UndefinedBehaviorSanitizer is supported on the following OS:
|
|
|
|
|
|
|
|
* 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
|
2015-12-05 01:30:29 +08:00
|
|
|
* OS X 10.6 onwards
|
|
|
|
|
|
|
|
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:
|
|
|
|
* 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++
|
|
|
|
<http://blog.regehr.org/archives/213>`_
|