Google has published the source codes of the GWPSan toolkit, designed to detect runtime errors in applications compiled for x86-64 and ARM64 architectures. GWPSan is compiled as a shared library that links at application startup using LD_PRELOAD and utilizes available Linux kernel mechanisms for stopping (PERF_TYPE_BREAKPOINT) and process sampling for program analysis. The code is written in C++ and is distributed under the Apache 2.0 license.
GWPSan is structured as a modular framework that supports the addition of modules implementing various error class detectors. GWPSan performs dynamic analysis triggered through signal handlers, allowing it to operate without modifying the application's executable code. For most detectors to work effectively, the application must be compiled with certain compiler flags that add necessary metadata. At least Clang 18 and Linux kernel 6.4 are required.
Currently, three detectors are available:
- UAR (Use-after-return) — detects errors caused by using an object on the stack after exiting the function where the object was defined. Protection is organized through intercepting the entry and exit points for the function — upon entry, the stack is replaced with a copy for use during the function's execution, and upon exit, the old stack state is restored.
- TSan (Thread Sanitizer) — identifies race conditions between threads (Data-race), occurring when different concurrently running threads can read or modify shared memory areas without using synchronization primitives. Protection is based on using hardware breakpoints tied to shared memory areas. The triggering handler temporarily suspends the execution of the thread when accessing memory, checking during this pause whether a breakpoint was triggered for another thread.
- LMSan (Lightweight Memory Sanitizer) — detects the use of uninitialized data in memory. The detector is marked as experimental and is not recommended for use.
GWPSan analyzes the executable code of a program using the DynamoRIO framework to decode machine code into abstract ISA instructions, which are then executed using emulation. Periodic signals from a timer trigger a unified handler, which executes a specific portion of instructions for the analyzed thread with each call. If certain instructions are detected during execution, a specific problem detector for those instructions is launched; for example, a race condition detector is initiated for instructions that access memory.
Source: opennet.ru
