ASan does not report passing a non-null-terminated char array to std::ostream << const char*
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
## Summary
I would like to clarify whether this is expected behavior or a bug / limitation in AddressSanitizer.
The program below passes a non-null-terminated character array to `std::ostream << const char*`. My understanding is that this is undefined behavior, because `operator<<(std::ostream&, const char*)` expects a null-terminated C string.
## Code
```cpp
#include
struct Test
{
static constexpr char kString[] = { '1', '2', '3', '4', '5', '6', '7', '8' };
};
int main()
{
std::cout << Test::kString << '\n';
return 0;
}
```
## Build Command
I compiled it with:
```sh
clang++ main.cpp \
-std=c++20 -Wall -Wextra -Wpedantic \
-g -O0 -fno-omit-frame-pointer \
-fsanitize=address,leak,undefined
```
## Actual Behavior
At runtime, the output looks consistent with reading past the end of `kString`:
```
12345678��
```
However, I do not get an AddressSanitizer report.
## Notes
The same behavior is reproducible on Compiler Explorer: https://godbolt.org/z/cGa66Y3vc
In the generated assembly, I do not see any obvious ASan redzone around `Test::kString`:
```asm
Test::kString:
.ascii "12345678"
```
For comparison, ASan does report the error for this variant compiled with the same compiler and flags:
Compiler Explorer link for this variant: https://godbolt.org/z/KaoP113rW
```cpp
#include
int main()
{
static constexpr char kString[] = { '1', '2', '3', '4', '5', '6', '7', '8' };
std::cout << kString << '\n';
return 0;
}
```
That version produces an `AddressSanitizer: global-buffer-overflow` report:
```text
READ of size 9 at 0x... thread T0
#0 ... in strlen
#1 ... in std::operator<<(std::basic_ostream>&, char const*)
#2 ... in main /app/example.cpp:6:15
0x... is located 0 bytes after global variable 'main::kString' defined in '/app/example.cpp:5' ... of size 8
SUMMARY: AddressSanitizer: global-buffer-overflow ... in std::operator<<(std::basic_ostream>&, char const*)
...
Global redzone: f9
```
This difference is what makes me think I may be missing something about how ASan handles these two cases.
## Question
1. Is it expected that ASan does not diagnose this case?
2. If this is a known limitation, is there a recommended way to catch such cases?
Contributor guide
Research direction
Reproduce the two examples from main.cpp using the stated clang++ sanitizer command, then compare the static member case with the local static case and their Compiler Explorer outputs. Start by tracing the AddressSanitizer handling of the two global objects. Done means establishing whether the missing report is expected and documenting the limitation or identifying a concrete sanitizer change.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- testing-qa, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100