Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
97086af
Add Sanitizers documentation
uilianries Aug 20, 2025
50fd020
Add Sanitizers
uilianries Aug 20, 2025
21c0d73
Add more sections
uilianries Aug 21, 2025
91c72e4
Sanitizer setting is optional
uilianries Aug 22, 2025
a8e0744
Add toolchain and hook section
uilianries Aug 22, 2025
99a9004
Improve description
uilianries Aug 22, 2025
a4ab90f
Remove unsed header.
uilianries Oct 1, 2025
5635544
Update sanitizers warning
uilianries Oct 1, 2025
ab0bacc
Improve document description
uilianries Oct 1, 2025
000fed7
Remove Sanitizers with Conan hooks section
uilianries Oct 2, 2025
287a6d0
Add Sanitizers documentation
uilianries Aug 20, 2025
2b1d233
Add Sanitizers
uilianries Aug 20, 2025
e016d2f
Add more sections
uilianries Aug 21, 2025
1e6e16d
Sanitizer setting is optional
uilianries Aug 22, 2025
277548e
Add toolchain and hook section
uilianries Aug 22, 2025
370259c
Improve description
uilianries Aug 22, 2025
a056050
Remove unsed header.
uilianries Oct 1, 2025
3502b82
Update sanitizers warning
uilianries Oct 1, 2025
2b02ba7
Improve document description
uilianries Oct 1, 2025
1f94538
Remove Sanitizers with Conan hooks section
uilianries Oct 2, 2025
c4e0c36
Add tables
uilianries Oct 2, 2025
3760901
Fix warning message
uilianries Oct 2, 2025
92f2581
Reorganize reader flow 1
uilianries Oct 2, 2025
38524c3
Reestructured page
uilianries Oct 2, 2025
bb30880
Add ABI compatibility section
uilianries Oct 2, 2025
ebab68d
Merge branch 'sanitizers' of github.com:uilianries/conan-docs into sa…
uilianries Oct 2, 2025
a502719
Restore back sanitizers page
uilianries Oct 2, 2025
4311346
Add note about having multiple sanitizers in settings
uilianries Oct 2, 2025
81e012b
Use Conan build command instead of install --build
uilianries Oct 2, 2025
a1095e2
Move sanitizers page to security folder
uilianries Oct 2, 2025
a39cb7d
Update folder name for examples
uilianries Oct 2, 2025
5786822
Simplify index out of bounds commands
uilianries Nov 5, 2025
fe106a3
Simplify signed integer overflow commands
uilianries Nov 5, 2025
26700f7
Be more consistent about mixing sanitizers
uilianries Nov 5, 2025
6a05558
Improve environment variables descriptioN
uilianries Nov 5, 2025
b6da388
Windows support Asan for both x86 and x64
uilianries Nov 5, 2025
74acf05
Separare sanitizers examples
uilianries Nov 5, 2025
11caff3
Improve example title page
uilianries Nov 5, 2025
6fd87de
Improve example title page
uilianries Nov 5, 2025
cd416bf
Improve sanitizers title
uilianries Nov 5, 2025
0779b86
Make explicit profile
uilianries Nov 5, 2025
25403f6
Use explicit profiles
uilianries Nov 5, 2025
d239adc
Fix profile names
uilianries Nov 5, 2025
d596bc2
Move sanitizer example to parent folder
uilianries Nov 5, 2025
c5271dd
Update example link reference
uilianries Nov 5, 2025
763e8e3
Explicit note about using cmake toolchain
uilianries Nov 5, 2025
c5544ce
Change clang profiles to gcc
uilianries Nov 5, 2025
2decba9
Add GCC and MSVC to user_settings
uilianries Nov 5, 2025
9b6a1cd
Give back leak sanitizer to gcc
uilianries Nov 5, 2025
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
1 change: 1 addition & 0 deletions examples/dev_flow.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ Developer tools and flows

dev_flow/debug/step_into_dependencies
dev_flow/debug/debugging_visual
dev_flow/sanitizers/compiler_sanitizers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure this is the best section? I'd say sanitizing is not necessarily a "developer flow", but instead something that likely runs on CI. Maybe it could be part of "Security"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially, I did have a clear idea where to put it, as Conan 1.x documentation does not follow the same structure. I just moved to the security section on the commit a1095e2.

dev_flow/tool_requires/mingw
356 changes: 356 additions & 0 deletions examples/dev_flow/sanitizers/compiler_sanitizers.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,356 @@
### Compiler sanitizers

.. _examples_dev_flow_sanitizers_compiler_sanitizers:

Compiler sanitizers
===================

.. warning::

Using sanitizers in production, particularly with SUID binaries, is dangerous. The libsanitizer
runtimes rely on environment variables that could enable privilege escalation attacks.
Use sanitizers only in development and testing environments.

Sanitizers are powerful tools for detecting runtime bugs like buffer overflows, data races, memory leaks,
dangling pointers, use-of-uninitialized memory, and various types of undefined behavior. Compilers such as
GCC, Clang, and MSVC support these tools through specific compiler and linker flags.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to talk about the difference in sanitizer support for each compiler, maybe do a comparative table or something like that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be huge, considering the number of sanitizers supported by llvm. I pointed the sanitizers pages as a link in the documentation.

Let me add a table, in case it gets too big, we can still summarize to most important sanitizers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just for consideration, if you think that it would add value...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just added some tables, indeed it is much clearer and visible now. Thank you for that suggestion! Please, take a look.


This document explains recommended approaches for integrating compiler sanitizers into your Conan 2.x workflow.

Modeling and applying sanitizers using settings
-----------------------------------------------
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good, before this section, to add a bit of explanation about how sanitizers influence binary compatibility and then, as a result, explain how you can model it for these cases.

Also, it would be great to do some research about if all the sanitizers will make binaries to break compatibility or there are cases were you can apply the sanitizers just as flags without the risk of producing incompatible binaries.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added an explanation about what each sanitizers does in the library/application and their abi compatibility as well. Please, review it again.


If you want to model sanitizer options so that the package ID is affected by them, you can
:ref:`customize new compiler sub-settings <reference_config_files_customizing_settings>`. You should not need
to modify ``settings.yml`` directly; instead add :ref:`the settings_user.yml <examples_config_files_settings_user>`.

This approach is preferred because enabling a sanitizer alters the package ID, allowing you to build and use
the same binary package with or without sanitizers. This is ideal for development and debugging workflows.
Comment on lines 178 to 179
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this, once it has been defined above the importance of using sanitizers only in dev-environments, I fully agree that a different package_id is quite good default approach, even if binary compatibility isn't fully necessary


To better illustrate this, please clone the sources to recreate this project. You can find them in the
`examples2 repository <https://github.com/conan-io/examples2>`_ on GitHub:

.. code-block:: bash
git clone https://github.com/conan-io/examples2.git
cd examples2/examples/dev_flow/sanitizers/compiler_sanitizers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’d suggest restructuring the page so readers get the why/what before the how. Right now the doc asks to clone the repo in the middle of conceptual explanations, which interrupts the flow. It would be clearer to start with the important concepts and only then move to the hands-on example.

Depending on how extensive we want the theoretical part to be, we might even split it out into a separate page (so this page stays more tutorial-oriented, and the other more reference-style).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved to the end of the document:

Present everything about Sanitizers -> How to configure Sanitizer with Conan -> Example -> Final considerations.

In this example we will see how to prepare Conan to use sanitizers in different ways.

Configuring sanitizers as part of settings
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If you typically use a specific set of sanitizers or combinations for your builds, you can specify
a sub-setting as a list of values in your ``settings_user.yml``. For example, for Clang:

.. code-block:: yaml
:caption: settings_user.yml
:emphasize-lines: 3
compiler:
clang:
sanitizer: [null, Address, Leak, Thread, Memory, UndefinedBehavior, HardwareAssistanceAddress, KernelAddress, AddressUndefinedBehavior, ThreadUndefinedBehavior]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to enable more than 1 sanitizer simultaneously? How would that be represented?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see, some of them are actually combinations of Address+Undefined, for example. I think this deserves a line of explanation

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an explanation on the commit 4311346

This example defines a few common sanitizers. You can add any sanitizer your compiler supports.
The ``null`` value represents a build without sanitizers. The above models the use of ``-fsanitize=address``,
``-fsanitize=thread``, ``-fsanitize=memory``, ``-fsanitize=leak``, ``-fsanitize=undefined``, ``-fsanitize=hwaddress``,
``-fsanitize=kernel-address``, as well as combinations like ``-fsanitize=address,undefined`` and ``-fsanitize=thread,undefined``.

It may seem like a large number of options, but for Clang, these are only a portion. To obtain the complete list,
refer to:

* Clang: `AddressSanitizer <https://clang.llvm.org/docs/AddressSanitizer.html>`_,
`ThreadSanitizer <https://clang.llvm.org/docs/ThreadSanitizer.html>`_,
`MemorySanitizer <https://clang.llvm.org/docs/MemorySanitizer.html>`_,
`UndefinedBehaviorSanitizer <https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html>`_.
* GCC: `Instrumentation Options <https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html>`_.
* MSVC: `MSVC Sanitizers <https://learn.microsoft.com/en-us/cpp/sanitizers/>`_.

**Notes on combinations**:

* AddressSanitizer (ASan), ThreadSanitizer (TSan), and MemorySanitizer (MSan) are mutually exclusive with one another.
* Address + UndefinedBehavior (UBSan) is a common and supported combination.
* Thread + UndefinedBehavior is also supported.
* MemorySanitizer often requires special flags such as ``-O1``, ``-fno-omit-frame-pointer`` and fully-instrumented dependencies.

Adding sanitizers as part of the profile
----------------------------------------

Another option is to add the sanitizer values as part of a profile. This way, you can easily switch between
different configurations by using dedicated profiles.

.. code-block:: ini
:caption: compiler_sanitizers/profiles/asan
include(default)
[settings]
build_type=Debug
compiler.sanitizer=Address
[conf]
tools.build:cflags+=["-fsanitize=address", "-fno-omit-frame-pointer"]
tools.build:cxxflags+=["-fsanitize=address", "-fno-omit-frame-pointer"]
tools.build:exelinkflags+=["-fsanitize=address"]
tools.build:sharedlinkflags+=["-fsanitize=address"]
[runenv]
ASAN_OPTIONS="halt_on_error=1:detect_leaks=1"
For Visual Studio (MSVC) we can obtain an equivalent profile for AddressSanitizer:

.. code-block:: ini
:caption: ~/.conan/profiles/asan
include(default)
[settings]
build_type=Debug
compiler.sanitizer=Address
[conf]
tools.build:cxxflags+=["/fsanitize=address", "/Zi"]
tools.build:exelinkflags+=["/fsanitize=address"]
The Conan client is not capable of deducing the necessary flags from the settings and applying them automatically
during the build process. It is necessary to pass the expected sanitizer flags according to the
``compiler.sanitizer`` value as part of the compiler and linker flags.
Conan's built-in toolchains (like ``CMakeToolchain`` and ``MesonToolchain``) will automatically
pick up the flags defined in the ``[conf]`` section and apply them to the build.


Building examples using sanitizers
----------------------------------

To show how to use sanitizers in your builds, let's consider two examples.

.. note::

To build your project with a sanitizer, simply use the corresponding profile.
It is crucial to **rebuild all dependencies from source** to ensure they are also instrumented,
which prevents false positives and other issues.

AddressSanitizer: index out of bounds
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In this example, we will build a simple C++ program that intentionally accesses an out-of-bounds index
in an array, which should trigger ASan when running the program.

.. code-block:: cpp
:caption: index_out_of_bounds/main.cpp
:emphasize-lines: 11
#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;
}
**Note:** The preprocessor check above is portable for GCC, Clang and MSVC.
The define ``__SANITIZE_ADDRESS__`` is present when ASan is active;

**To build and run this example using Conan:**

.. code-block:: bash
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
# Activate run environment to ensure sanitizer runtime and paths are set
source index_out_of_bounds/install/conanrun.sh
index_out_of_bounds
**Expected output (abbreviated):**

.. code-block:: text
Address sanitizer enabled
==32018==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffbe04a6d0 ...
WRITE of size 4 at 0x7fffbe04a6d0 thread T0
#0 ... in main .../index_out_of_bounds+0x12ea
...
SUMMARY: AddressSanitizer: stack-buffer-overflow ... in main
This frame has 1 object(s):
[48, 448) 'foo' (line 11) <== Memory access at offset 448 overflows this variable
UndefinedBehaviorSanitizer: signed integer overflow
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This example demonstrates how to use UBSan to detect signed integer overflow. It combines ASan and UBSan.
Create a dedicated profile:

.. code-block:: ini
:caption: ~/.conan/profiles/asan_ubsan
:emphasize-lines: 7
include(default)
[settings]
build_type=Debug
compiler.sanitizer=AddressUndefinedBehavior
[conf]
tools.build:cflags+=["-fsanitize=address,undefined", "-fno-omit-frame-pointer"]
tools.build:cxxflags+=["-fsanitize=address,undefined", "-fno-omit-frame-pointer"]
tools.build:exelinkflags+=["-fsanitize=address,undefined"]
tools.build:sharedlinkflags+=["-fsanitize=address,undefined"]
It is supported by GCC and Clang. MSVC does not support UBSan.

**Source code:**

.. code-block:: cpp
:caption: signed_integer_overflow/main.cpp
:emphasize-lines: 14
#include <iostream>
#include <cstdlib>
#include <climits>
int main() {
#ifdef __SANITIZE_ADDRESS__
std::cout << "Address sanitizer enabled\n";
#else
std::cout << "Address sanitizer not enabled\n";
#endif
int x = INT_MAX;
x += 42; // signed integer overflow
return EXIT_SUCCESS;
}
**Build and run:**

.. code-block:: bash
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not simplify to a conan build command?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conan export + conan install is olde school. Let me update to conan build then :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, updated in the commit 81e012b

source signed_integer_overflow/install/conanrun.sh
signed_integer_overflow
**Expected output (abbreviated):**

.. code-block:: text
Address sanitizer enabled
.../main.cpp:16:9: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
Passing the information to the compiler or build system
-------------------------------------------------------

Besides using Conan profiles to manage sanitizer settings, you can also use other approaches.

Managing sanitizers with a CMake toolchain
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If you already have a :ref:`custom CMake toolchain file <conan_cmake_user_toolchain>` to manage compiler
and build options, you can pass the necessary flags to enable sanitizers there instead of profiles.

.. code-block:: cmake
:caption: cmake/my_toolchain.cmake
# Apply to all targets; consider per-target options for finer control
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address,undefined")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address,undefined")
Then, specify this toolchain file as part of your Conan profile:

.. code-block:: ini
:caption: profiles/asan_ubsan
include(default)
[settings]
build_type=Debug
compiler.sanitizer=AddressUndefinedBehavior
[conf]
tools.cmake.cmaketoolchain:user_toolchain=cmake/my_toolchain.cmake
This way, you can keep your existing CMake toolchain file and still leverage Conan profiles to manage other settings.

Managing sanitizers with Conan hooks
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Another approach is using :ref:`Conan hooks <reference_extensions_hooks>`. With hooks, you can inject compiler
flags on-the-fly during the build process, allowing for dynamic configurations without modifying the original
build files.

For instance, add a ``pre_generate`` hook to append the necessary sanitizer flags based on the
``compiler.sanitizer`` setting:

.. code-block:: python
:caption: ~/.conan2/extensions/hooks/hook_sanitizer_flags.py
def pre_generate(conanfile):
sani = conanfile.settings.get_safe("compiler.sanitizer")
if not sani or sani == "null":
return
mapping = {
"Address": "address",
"Leak": "leak",
"Thread": "thread",
"Memory": "memory",
"UndefinedBehavior": "undefined",
"HardwareAssistanceAddress": "hwaddress",
"KernelAddress": "kernel-address",
"AddressUndefinedBehavior": "address,undefined",
"ThreadUndefinedBehavior": "thread,undefined",
}
fs = mapping.get(sani)
if not fs:
return
flag = f"-fsanitize={fs}"
for k in ("tools.build:cflags", "tools.build:cxxflags",
"tools.build:exelinkflags", "tools.build:sharedlinkflags"):
conanfile.conf.append(k, flag)
# Optional: better stack traces
conanfile.conf.append("tools.build:cxxflags", "-fno-omit-frame-pointer")
The ``pre_generate`` hook is executed before Conan generates toolchain files, so it can contribute to the final
configuration for compiler and linker flags. This approach is flexible, but can increase maintenance complexity
as it moves logic out of profile management.

Additional recommendations
--------------------------

* Debug info and optimization:

* For ASan/TSan, ``-O1`` or ``-O2`` generally works; for MSan, prefer ``-O1`` and avoid aggressive inlining.
* ``-fno-omit-frame-pointer`` helps stack traces.

* Runtime symbolization:

* Useful settings for CI:

* ``ASAN_OPTIONS=halt_on_error=1:detect_leaks=1:log_path=asan``.
* ``UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1:log_path=ubsan``.

* Suppressions:

* For ASan: ``ASAN_OPTIONS=suppressions=asan.supp``.
* For UBSan: ``UBSAN_OPTIONS=suppressions=ubsan.supp``.
* Keep suppressions under version control and load them in CI jobs.

* Third-party dependencies:

* Mixed instrumented/uninstrumented code can lead to false positives or crashes, especially with MSan.
* Prefer building dependencies with the same sanitizer or limit sanitizers to leaf applications.

* MSVC and Windows notes:

* ASan with MSVC/Clang-cl uses ``/fsanitize=address`` and PDBs via ``/Zi``. Not supported for 32-bit targets.
* KAsan requires Windows 11.
* Some features are limited when using whole program optimization (``/GL``) or certain runtime libraries.