Introduction to DevEco Studio for HarmonyOS Next Development: ASan and TSan Detection to Cure Your C++ Phobia
1. Background Introduction
Many developers feel intimidated by C++, primarily due to memory operations. Improper memory operations such as array out-of-bounds access, memory leaks, and double-freeing can cause performance issues like high memory consumption,卡顿 (lag), or even program crashes. When an error terminates an app process, error logs are thrown to indicate the crash cause. Developers can analyze these logs—collected automatically by the system as FaultLog—to identify the problematic code. FaultLog includes:
- App Freeze
- CPP Crash
- JS Crash
- System Freeze
- ASan
- TSan
While other tools are commonly used, this article focuses on DevEco Studio's memory and thread debugging tools: ASan (Address Sanitizer) and TSan (Thread Sanitizer), as ArkTS's single-threading and non-shared memory multi-threading often shift complex multi-threading to the C++ layer.
2. ASan Detection
C++ memory issues mainly involve out-of-bounds access, memory leaks, and double-freeing. For performance reasons, compilers and runtime frameworks don’t check memory operations by default. DevEco Studio’s ASan helps detect such issues.
2.1 ASan Configuration
ASan is controlled by ASAN_OPTIONS
parameters, which set detection levels, output formats, and error report details. Configure parameters in:
- The project’s
app.json5
(higher priority) - Run/Debug Configurations
2.1.1 Configuring in app.json5
In AppScope > app.json5
:
{
"app": {
"appEnvironments": [
{
"name": "ASAN_OPTIONS",
"value": "log_exe_name=true abort_on_error=0 print_cmdline=true" // For reference only
}
],
...
}
}
2.1.2 Configuring in Run/Debug Configurations
Add a configuration named ASAN_OPTIONS
with the value: log_exe_name=true abort_on_error=0 print_cmdline=true
.
2.1.3 Configurable Parameters
Parameter | Default | Required | Description |
---|---|---|---|
log_exe_name | true | Yes | Includes the executable name in memory error logs (non-modifiable). |
log_path | /dev/asanlog/asan.log | No | Required for ROM versions < NEXT.0.0.68 (non-modifiable); deprecated in NEXT.0.0.68+. |
abort_on_error | false | Yes | Specifies whether to call abort() or _exit() after printing errors:- false : Use _exit() - true : Use abort()
|
strip_path_prefix | - | No | Removes the configured prefix from file paths in error logs (e.g., /data/storage/el1 ). |
detect_stack_use_after_return | false | No | Checks for access to freed stack space: - true : Enable check- false : Disable check. |
halt_on_error | 0 | No | Determines if the program continues after detecting errors: - 0 : Continue- 1 : Terminate. |
malloc_context_size | - | No | Number of call stack layers shown when a memory error occurs. |
suppressions | "" | No | Suppresses specified file names. |
handle_segv | - | No | Checks for segmentation faults. |
handle_sigill | - | No | Checks for SIGILL signals. |
quarantine_size_mb | 256 | No | Size of the quarantine area for detecting freed stack space access errors. |
2.2 Enabling ASan
Enable ASan in two ways:
- In the run/debug window, click Diagnostics and check Address Sanitizer.
- Add ASan configuration in
AppScope/app.json5
.
Note: For dependent native libraries, configure arguments: "-DOHOS_ENABLE_ASAN=ON"
in the library’s build-profile.json5
to compile SO files in ASan mode.
When a memory error occurs, ASan logs appear. Click the link in the log to jump to the problematic code. For example, an array out-of-bounds error triggers:
2.3 ASan Error Codes
ASan reports specific error codes with causes:
2.3.1 heap-buffer-overflow
- Cause/Impact: Out-of-bounds access, leading to security vulnerabilities and crash risks.
- Fix: Check bounds for known-size collections; validate sizes before accessing dynamic collections.
- Example:
int heapBufferOverflow() {
char *buffer = (char *)malloc(10);
*(buffer + 11) = 'n'; // Overflow
*(buffer + 12) = 'n'; // Overflow
free(buffer);
return buffer[1];
}
2.3.2 stack-buffer-underflow
- Cause/Impact: Access below the buffer bound, risking security and crashes.
- Fix: Ensure indices are not less than the lower bound.
- Example:
int stackBufferUnderflow() {
int subscript = -1;
char buffer[42];
buffer[subscript] = 42; // Underflow
return 0;
}
2.3.3 stack-use-after-scope
- Cause/Impact: Using stack variables outside their scope, risking security and crashes.
- Fix: Mind variable scoping.
- Example:
int *gp;
bool b = true;
int stackUseAfterScope() {
if (b) {
int x[5];
gp = x + 1; // Pointer to stack variable
}
return *gp; // Use after scope ends
}
2.3.4 attempt-free-nonallocated-memory
- Cause/Impact: Freeing non-heap or unallocated memory, risking security and crashes.
-
Fix: Avoid
free()
on non-heap or unallocated memory. - Example:
int main() {
int value = 42;
free(&value); // Free stack variable
return 0;
}
2.3.5 double-free
- Cause/Impact: Freeing memory twice, risking security and crashes.
-
Fix: Initialize pointers to
NULL
and reset them after freeing. - Example:
int main() {
int *x = new int[42];
delete [] x;
delete [] x; // Double-free
return 0;
}
2.3.6 heap-use-after-free
- Cause/Impact: Accessing freed memory, risking security and crashes.
-
Fix: Implement a
free()
alternative or destructor to reset pointers. - Example:
#include <stdlib.h>
int main() {
int *array = new int[5];
delete[] array;
return array[5]; // Use after free
}
2.4 Additional Notes
- If any module enables ASan, the entry module must also enable ASan; otherwise, the app will crash on startup with a CPP Crash error.
3. TSan Detection
Another C++ challenge is multi-threading, where unpredictable execution orders complicate debugging. DevEco Studio’s TSan (ThreadSanitizer) detects data races, using a compiler instrumentation module and runtime library.
3.1 Key Application Scenarios
TSan helps identify multi-threading issues:
- Data Race Detection: Occurs when two or more threads access the same memory without proper synchronization (at least one write), causing unpredictable behavior.
-
Lock Error Detection:
- Deadlock: Threads wait for each other’s locks, halting execution.
- Double Unlock: Unlocking an already unlocked lock.
- Unlock Without Hold: Unlocking a lock not held by the thread.
-
Condition Variable Error Detection:
- Wait Without Lock: Calling
wait()
without holding the related lock. - Signal/Broadcast Without Lock: Calling
signal()
/broadcast()
without holding the related lock.
- Wait Without Lock: Calling
3.2 TSan Configuration
Enable TSan in two ways:
- In the run/debug window, click Diagnostics and check Thread Sanitizer.
- Modify
AppScope/app.json5
to add TSan configuration.
Note: For referenced native libraries, configure arguments: "-DOHOS_ENABLE_TSAN=ON"
in the library’s build-profile.json5
to compile SO files in TSan mode.
3.3 Enabling TSan
When a thread error occurs during app run/debug, TSan logs appear. Click the link to jump to the problematic code:
TSan reports include:
- Error type (e.g., data race, deadlock)
- Memory address
- Thread info (ID and stack trace)
- Source code locations and stack traces
- Context (read/write type, access size)
Note: call_once
may trigger false positives. Add __attribute__((no_sanitize("thread")))
before the function to suppress this.
3.4 Additional Notes
- TSan reduces performance by 5–15x and increases memory usage by 5–10x, potentially affecting features like GPU rendering.
- ASan and TSan cannot be enabled simultaneously.
- TSan supports API 12 and above.
4. Summary
This article introduces DevEco Studio’s ASan and TSan tools for debugging C++ memory and thread issues:
- ASan detects address overflows, memory leaks, and double-freeing.
- TSan detects data races, lock errors, and condition variable issues.
DevEco Studio’s tooling simplifies C++ development by identifying and resolving complex issues. Familiarizing yourself with these tools empowers you to tackle C++ challenges confidently, eliminating hidden risks through systematic detection.
Top comments (0)