简体   繁体   中英

GCC `-fsanitize=bounds` strange behaviour with `std::array`

I'm trying find out of bounds problems in my code using -fsanitize=bounds option, but I faced with strange behaviour:

For instance in the following code:

#include <cstdlib>
#include <array>

int main (int, char **)
{
    std::array <char, 1> a;
    const char b = a [X]; // X <--- put index here!

    return EXIT_SUCCESS;
}

compiled with options: $ g++ -std=c++11 -fsanitize=bounds -O0 main.cpp -o main .

If I try access to element with index more than 1, errors are reported: /usr/include/c++/5/array:53:36: runtime error: index 2 out of bounds for type 'char [1]' .

But if I try access to element with index 1 - everything OK and no errors are reported.

Is it expected behaviour and may be I've missed something?

The example is tested on:
- $ g++ --version g++ (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609 ;
- $ g++ --version g++ (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005 .

UPD
I tried -fsanitize=bounds-stric in GCC 6 and result the same.

I can't immediately find documentation for this (or, really, strong documentation of any kind), but it strikes me as likely that this is an implementation detail for the feature. It is legal to obtain one-past-the-end pointers, so an implementation could not trap on this. It seems the implementation works by looking at the pointer, rather than waiting for such a pointer to be dereferenced (which makes some sense if you think about how you would create -fsanitize=bounds ).

In short, this may simply be a limitation of the tool.

In GCC 6, you might try -fsanitize=bounds-strict which increases the strength of the tool (including adding support for detecting OOB access to flexible member-like arrays).

I can't tell whether this is a library or compiler issue, but either way it's worth noting that the same problem is currently an open bug against clang ( #21485 ), and the supposition in comments there matches my ramblings above.

A third-party article on ubsan also implies that this is, ultimately, expected behaviour.

From https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html

-fsanitize=bounds This option enables instrumentation of array bounds. Various out of bounds accesses are detected. Flexible array members, flexible array member-like arrays, and initializers of variables with static storage are not instrumented.

Using X>1 makes this check (array out of bounds) to trigger, as expected because of 'a' char declaration, with size = 1.

EDIT

Being that said, as @Lightness Races in Orbit says, this is not an answer. But offers some info for readers.

The fact that the case X==1 is one-past-end makes me think of iterators, where one-past-end is allowed. IOW, it seems that GCC sanitizer gets an iterator for testing instead of a reference a[X].

@Gluttton confirms that using C-like array instead of std::array the case a[1] is showed as an error, as expected.

As @Ripi2 mentioned , the first element past the end of the array often considered as end iterator.

In this case, -fsanitize=address can detect out-of-bound bugs, when you access illeagal position of array, compiler can give more info.

g++ -std=c++11 -fsanitize=address -O0 main.cpp -o main

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM