Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions examples/dev_flow/sanitizers/compiler_sanitizers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Compiler Sanitizers Example

This example follows the documented page https://docs.conan.io/2/examples/dev_flow/sanitizers/compiler_sanitizers.

## Examples

Here are some examples of using compiler sanitizers with Conan.

### Configuring Custom Settings

Before trying to build using the profiles prepared to work with sanitizers, you may want to configure some custom settings in your Conan home.
It's not needed to modify the `settings.yml` file, instead, you can install a custom settings using [settings_user.yml](https://docs.conan.io/2/reference/config_files/settings.html#settings-user-yml)

```
cp settings_user.yml $(conan config home)
```

This setting allows you to customize the behavior of the sanitizers, enabling or disabling specific checks as needed.

### Signed Integer Overflow

This example demonstrates how to detect signed integer overflow using compiler sanitizers. The provided C++ code intentionally causes a signed integer overflow, which can be detected when running the program with the appropriate sanitizer flags.

It explores the [Undefined Behavior Sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html), **ONLY** available in Clang and GCC; MSVC does not support it (yet).

In order to try the example, you may run the following commands:

```
conan create signed_integer_overflow/ -pr profiles/asan_ubsan
conan install --requires=signed_integer_overflow/0.1.0 -pr profiles/asan_ubsan -of install
source install/conanrun.sh
signed_integer_overflow
```
It's expected to observe a runtime error indicating a signed integer overflow has occurred:

```
Address sanitizer not enabled
/home/conan/.conan2/p/b/signe3b8ad6d59f30b/b/main.cpp:13:9: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /home/conan/.conan2/p/b/signe3b8ad6d59f30b/b/main.cpp:13:9
```

### Index Out of Bounds

This example demonstrates how to detect out-of-bounds memory access using compiler sanitizers. The provided C++ code intentionally accesses an out-of-bounds index in an array, which can be detected when running the program with the appropriate sanitizer flags.

It explores the [Address Sanitizer](https://clang.llvm.org/docs/AddressSanitizer.html), available in Clang, GCC and MSVC.

In order to try the example, you may run the following commands:

```
conan create index_out_of_bounds/ -pr profiles/asan
conan install --requires=index_out_of_bounds/0.1.0 -pr profiles/asan -of install
source install/conanrun.sh
index_out_of_bounds
```

It's expected to observe a runtime error indicating an out-of-bounds memory access has occurred:

```
==357155==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcddcc40e0 at pc 0x5946a605f2eb bp 0x7ffcddcc3f10 sp 0x7ffcddcc3f00
WRITE of size 4 at 0x7ffcddcc40e0 thread T0
#0 0x5946a605f2ea in main (/home/conan/.conan2/p/b/index7e914f42d466f/p/bin/index_out_of_bounds+0x12ea)
#1 0x7722f0c29d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#2 0x7722f0c29e3f in __libc_start_main_impl ../csu/libc-start.c:392
#3 0x5946a605f3d4 in _start (/home/conan/.conan2/p/b/index7e914f42d466f/p/bin/index_out_of_bounds+0x13d4)

Address 0x7ffcddcc40e0 is located in stack of thread T0 at offset 448 in frame
#0 0x5946a605f1ef in main (/home/conan/.conan2/p/b/index7e914f42d466f/p/bin/index_out_of_bounds+0x11ef)

This frame has 1 object(s):
[48, 448) 'foo' (line 11) <== Memory access at offset 448 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/home/conan/.conan2/p/b/index7e914f42d466f/p/bin/index_out_of_bounds+0x12ea) in main
```

## Customizing Sanitizers

### Using Environment Variables

The `ASAN_OPTIONS` and `UBSAN_OPTIONS` environment variables can be used to customize the behavior of AddressSanitizer and UndefinedBehaviorSanitizer, respectively. For example, you can set the `ASAN_OPTIONS` variable to control the reporting format, enable or disable specific checks, and more.

To set these environment variables, you can use the `export` command in your terminal before running your program:

```bash
export ASAN_OPTIONS=detect_leaks=1:log_path=asan.log
export UBSAN_OPTIONS=print_stacktrace=1
```

This will enable leak detection for AddressSanitizer and print stack traces for UndefinedBehaviorSanitizer.

For more advanced configurations, you can refer to the [Clang AddressSanitizer](https://github.com/google/sanitizers/wiki/addresssanitizerflags#run-time-flags) and [MSVC AddressSanitizer](https://learn.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-170#differences) documentation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@echo off
setlocal enabledelayedexpansion

echo Setup settings user
for /f "usebackq delims=" %%H in (conan config home) do set "CONAN_HOME=%%H"
copy /Y settings_user.yml "%CONAN_HOME%"

echo Conan Examples 2: Compiler Sanitizers - Index Out of Bounds

conan export index_out_of_bounds/
conan install --requires=index_out_of_bounds/0.1.0 -pr profiles/asan -of index_out_of_bounds/install --build=missing -c tools.compilation:verbosity=verbose
call index_out_of_bounds\install\conanrun.bat
index_out_of_bounds.exe 2>nul || echo Process completed with errors (expected for sanitizer demo)
call index_out_of_bounds\install\deactivate_conanrun.bat

echo Conan Examples 2: Compiler Sanitizers - Signed Integer Overflow

conan export signed_integer_overflow/
conan install --requires=signed_integer_overflow/0.1.0 -pr profiles/asan_ubsan -of signed_integer_overflow/install --build=missing -c tools.compilation:verbosity=verbose
call signed_integer_overflow\install\conanrun.bat
signed_integer_overflow.exe 2>nul || echo Process completed with errors (expected for sanitizer demo)
call signed_integer_overflow\install\deactivate_conanrun.bat

exit /b 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

set -e
set -x

echo "Setup settings user"
cp -f settings_user.yml $(conan config home)

echo "Conan Examples 2: Compiler Sanitizers - Index Out of Bounds"

conan export index_out_of_bounds/
conan install --requires=index_out_of_bounds/0.1.0 -pr profiles/asan -of index_out_of_bounds/install --build=missing -c tools.compilation:verbosity=verbose
source index_out_of_bounds/install/conanrun.sh
index_out_of_bounds || true
. index_out_of_bounds/install/deactivate_conanrun.sh

echo "Conan Examples 2: Compiler Sanitizers - Signed Integer Overflow"

conan export signed_integer_overflow/
conan install --requires=signed_integer_overflow/0.1.0 -pr profiles/asan_ubsan -of signed_integer_overflow/install --build=missing -c tools.compilation:verbosity=verbose
source signed_integer_overflow/install/conanrun.sh
signed_integer_overflow || true
. signed_integer_overflow/install/deactivate_conanrun.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.15)
project(index_out_of_bounds LANGUAGES CXX)

add_executable(index_out_of_bounds main.cpp)
target_compile_features(index_out_of_bounds PUBLIC cxx_std_11)

include(GNUInstallDirs)
install(TARGETS index_out_of_bounds
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from conan import ConanFile
from conan.tools.cmake import CMake, cmake_layout, CMakeToolchain

required_conan_version = ">=2.1.0"

class IndexOutOfBoundsConan(ConanFile):
name = "index_out_of_bounds"
version = "0.1.0"
settings = "os", "arch", "compiler", "build_type"
exports_sources = "CMakeLists.txt", "main.cpp"
package_type = "application"
languages = ["C++"]

def layout(self):
cmake_layout(self)

def generate(self):
tc = CMakeToolchain(self)
tc.generate()

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def package(self):
cmake = CMake(self)
cmake.install()
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include <iostream>
#include <cstdlib>

int main() {
#ifdef __SANITIZE_ADDRESS__
std::cout << "Address sanitizer enabled\n";
#else
std::cout << "Address sanitizer not enabled\n";
#endif

int foo[100];
foo[100] = 42; // Out-of-bounds write

return EXIT_SUCCESS;
}
14 changes: 14 additions & 0 deletions examples/dev_flow/sanitizers/compiler_sanitizers/profiles/asan
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
include(default)

[settings]
build_type=Debug
compiler.sanitizer=Address

[conf]
tools.build:cflags=['-fsanitize=address']
tools.build:cxxflags=['-fsanitize=address']
tools.build:exelinkflags=['-fsanitize=address']
tools.build:sharedlinkflags+=["-fsanitize=address"]

[runenv]
ASAN_OPTIONS="halt_on_error=1:detect_leaks=1"
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
include(default)

[settings]
build_type=Debug
compiler.sanitizer=AddressUndefinedBehavior

[conf]
tools.build:cflags=['-fsanitize=address,undefined']
tools.build:cxxflags=['-fsanitize=address,undefined']
tools.build:exelinkflags=['-fsanitize=address,undefined']
tools.build:sharedlinkflags+=["-fsanitize=address"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
compiler:
gcc:
sanitizer: [null, Address, Leak, Thread, UndefinedBehavior, HardwareAssistanceAddress, KernelAddress, AddressUndefinedBehavior, ThreadUndefinedBehavior]
clang:
sanitizer: [null, Address, Leak, Thread, Memory, UndefinedBehavior, HardwareAssistanceAddress, KernelAddress, AddressUndefinedBehavior, ThreadUndefinedBehavior]
apple-clang:
sanitizer: [null, Address, Leak, Thread, Memory, UndefinedBehavior, HardwareAssistanceAddress, KernelAddress, AddressUndefinedBehavior, ThreadUndefinedBehavior]
msvc:
sanitizer: [null, Address, KernelAddress]
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.15)
project(signed_integer_overflow LANGUAGES CXX)

add_executable(signed_integer_overflow main.cpp)
target_compile_features(signed_integer_overflow PUBLIC cxx_std_11)

include(GNUInstallDirs)
install(TARGETS signed_integer_overflow
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from conan import ConanFile
from conan.tools.cmake import CMake, cmake_layout, CMakeToolchain

required_conan_version = ">=2.1.0"

class SignedIntegerOverflowConan(ConanFile):
name = "signed_integer_overflow"
version = "0.1.0"
settings = "os", "arch", "compiler", "build_type"
exports_sources = "CMakeLists.txt", "main.cpp"
package_type = "application"
languages = ["C++"]

def layout(self):
cmake_layout(self)

def generate(self):
tc = CMakeToolchain(self)
tc.generate()

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def package(self):
cmake = CMake(self)
cmake.install()
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <iostream>
#include <cstdlib>
#include <cstdint>

int main(int argc, char* argv[]) {
#ifdef __SANITIZE_ADDRESS__
std::cout << "Address sanitizer enabled\n";
#else
std::cout << "Address sanitizer not enabled\n";
#endif

int foo = 0x7fffffff;
foo += argc; // Signed integer overflow

return EXIT_SUCCESS;
}