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
20 changes: 15 additions & 5 deletions .github/workflows/CITest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,17 @@ jobs:
build_type: 'Debug'
}
- {
name: 'ubuntu-22.04 x64 release - assert warn',
name: 'ubuntu-22.04 x64 debug - assert warn',
os: ubuntu-22.04,
arch: x64,
build-system: 'cmake',
diet-build: 'OFF',
enable-asan: 'OFF',
build_type: 'Release',
build_type: 'Debug',
build_options: '-DCAPSTONE_ASSERTION_WARNINGS=ON'
}
- {
name: 'ubuntu-22.04 x64 release - no asserts',
name: 'ubuntu-22.04 x64 release - no assert warnings',
os: ubuntu-22.04,
arch: x64,
build-system: 'cmake',
Expand All @@ -73,6 +73,16 @@ jobs:
build_type: 'Release',
build_options: '-DCAPSTONE_ASSERTION_WARNINGS=OFF'
}
- {
name: 'ubuntu-22.04 x64 release - assert warn',
os: ubuntu-22.04,
arch: x64,
build-system: 'cmake',
diet-build: 'OFF',
enable-asan: 'OFF',
build_type: 'Release',
build_options: '-DCAPSTONE_ASSERTION_WARNINGS=ON'
}
- {
name: 'ubuntu-24.04 x64 ASAN',
os: ubuntu-24.04,
Expand Down Expand Up @@ -112,10 +122,10 @@ jobs:
run: |
mkdir build && cd build
# build static library
cmake -DCAPSTONE_INSTALL=1 -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_ASAN=${asan} -DCAPSTONE_BUILD_DIET=${diet_build} ${build_option} ..
cmake -DCMAKE_BUILD_TYPE=${build_type} -DCAPSTONE_INSTALL=1 -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_ASAN=${asan} -DCAPSTONE_BUILD_DIET=${diet_build} ${build_option} ..
cmake --build . --config ${build_type}
# build shared library
cmake -DCAPSTONE_INSTALL=1 -DCAPSTONE_BUILD_SHARED_LIBS=1 -DCMAKE_INSTALL_PREFIX=/usr -DCAPSTONE_BUILD_CSTEST=ON -DENABLE_ASAN=${asan} ${build_option} ..
cmake -DCMAKE_BUILD_TYPE=${build_type} -DCAPSTONE_INSTALL=1 -DCAPSTONE_BUILD_SHARED_LIBS=1 -DCMAKE_INSTALL_PREFIX=/usr -DCAPSTONE_BUILD_CSTEST=ON -DENABLE_ASAN=${asan} ${build_option} ..
sudo cmake --build . --config ${build_type} --target install

- name: Lower number of KASL randomized address bits
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ option(CAPSTONE_USE_DEFAULT_ALLOC "Use default memory allocation functions" ON)
option(CAPSTONE_USE_ARCH_REGISTRATION "Use explicit architecture registration" OFF)
option(CAPSTONE_ARCHITECTURE_DEFAULT "Whether architectures are enabled by default" ON)
option(CAPSTONE_DEBUG "Whether to enable extra debug assertions (enabled with CMAKE_BUILD_TYPE=Debug)" OFF)
option(CAPSTONE_ASSERTION_WARNINGS "Warns about hit assertions in release builds." OFF)
option(CAPSTONE_ASSERTION_WARNINGS "Disables some asserts and warns instead when hit. Does not disable all asserts." OFF)
option(CAPSTONE_INSTALL "Generate install target" ${PROJECT_IS_TOP_LEVEL})
option(ENABLE_ASAN "Enable address sanitizer" OFF)
option(ENABLE_COVERAGE "Enable test coverage" OFF)
Expand Down
63 changes: 41 additions & 22 deletions cs_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,28 @@ extern cs_realloc_t cs_mem_realloc;
extern cs_free_t cs_mem_free;
extern cs_vsnprintf_t cs_vsnprintf;

/// By defining CAPSTONE_DEBUG assertions can be used.
/// For the release build the @expr is not included.
#ifdef CAPSTONE_DEBUG
/// Capstone assert macros. They can be configured to print warnings
/// when the `expr` is false.
/// This can be enabled by defining CAPSTONE_ASSERTION_WARNINGS.
/// Debug builds will always include an `assert(expr)` and hard fail
/// if `!expr`.
/// Release builds will not have `assert(expr)` code.

/// An simple assert.
#if defined(CAPSTONE_DEBUG) && !defined(CAPSTONE_ASSERTION_WARNINGS)
#define CS_ASSERT(expr) assert(expr)
#elif CAPSTONE_ASSERTION_WARNINGS
#elif defined(CAPSTONE_DEBUG) && defined(CAPSTONE_ASSERTION_WARNINGS)
#define CS_ASSERT(expr) \
do { \
if (!(expr)) { \
fprintf(stderr, \
"Capstone hit the assert: \"" #expr \
"\": %s:%" PRIu32 "\n", \
__FILE__, __LINE__); \
assert(expr) \
} \
} while (0)
#elif defined(CAPSTONE_ASSERTION_WARNINGS)
#define CS_ASSERT(expr) \
do { \
if (!(expr)) { \
Expand All @@ -125,42 +142,44 @@ extern cs_vsnprintf_t cs_vsnprintf;
#define CS_ASSERT(expr)
#endif

/// If compiled in debug mode it will assert(@expr).
/// In the release build it will check the @expr and return @val if false.
#ifdef CAPSTONE_DEBUG
/// An assert which returns the value in release builds if `!expr`.
#if defined(CAPSTONE_DEBUG) && !defined(CAPSTONE_ASSERTION_WARNINGS)
#define CS_ASSERT_RET_VAL(expr, val) assert(expr)
#elif CAPSTONE_ASSERTION_WARNINGS
#elif defined(CAPSTONE_ASSERTION_WARNINGS)
#define CS_ASSERT_RET_VAL(expr, val) \
do { \
if (!(expr)) { \
fprintf(stderr, \
"Capstone hit the assert: \"" #expr \
"\": %s:%" PRIu32 "\n", \
__FILE__, __LINE__); \
CS_ASSERT(expr); \
return val; \
} \
} while (0)
#else
#define CS_ASSERT_RET_VAL(expr, val)
#define CS_ASSERT_RET_VAL(expr, val) \
do { \
if (!(expr)) { \
return val; \
} \
} while (0)
#endif

/// If compiled in debug mode it will assert(@expr).
/// In the release build it will check the @expr and return if false.
#ifdef CAPSTONE_DEBUG
/// An assert which returns in release builds if `!expr`.
#if defined(CAPSTONE_DEBUG) && !defined(CAPSTONE_ASSERTION_WARNINGS)
#define CS_ASSERT_RET(expr) assert(expr)
#elif CAPSTONE_ASSERTION_WARNINGS
#elif defined(CAPSTONE_ASSERTION_WARNINGS)
#define CS_ASSERT_RET(expr) \
do { \
if (!(expr)) { \
fprintf(stderr, \
"Capstone hit the assert: \"" #expr \
"\": %s:%" PRIu32 "\n", \
__FILE__, __LINE__); \
CS_ASSERT(expr); \
return; \
} \
} while (0)
#else
#define CS_ASSERT_RET(expr)
#define CS_ASSERT_RET(expr) \
do { \
if (!(expr)) { \
return; \
} \
} while (0)
#endif

#endif
14 changes: 9 additions & 5 deletions tests/integration/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@ add_test(NAME integration_compat_headers
)

set(INTEGRATION_TEST_SRC test_litbase.c)
if(CMAKE_BUILD_TYPE STREQUAL "Release")
set(INTEGRATION_TEST_SRC ${INTEGRATION_TEST_SRC} test_assert_macros.c)
endif()

foreach(TSRC ${INTEGRATION_TEST_SRC})
string(REGEX REPLACE ".c$" "" TBIN ${TSRC})
add_executable(${TBIN} "${TESTS_INTEGRATION_DIR}/${TSRC}")
target_link_libraries(${TBIN} PRIVATE capstone)
add_test(NAME "integration_${TBIN}" COMMAND ${TBIN})
endforeach()
string(REGEX REPLACE ".c$" "" TBIN ${TSRC})
add_executable(${TBIN} "${TESTS_INTEGRATION_DIR}/${TSRC}")
target_link_libraries(${TBIN} PRIVATE capstone)
add_test(NAME "integration_${TBIN}" COMMAND ${TBIN})
endforeach()
32 changes: 32 additions & 0 deletions tests/integration/test_assert_macros.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-FileCopyrightText: 2025 Rot127 <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only

// Has to be built as Release build or with CAPSTONE_ASSERTION_WARNINGS.

#include <capstone/platform.h>
#include <capstone/capstone.h>

// Test: https://github.com/capstone-engine/capstone/issues/2791
static bool test_cs_reg_null_case()
{
csh handle;
if (cs_open(CS_ARCH_AARCH64, (cs_mode)0, &handle) != CS_ERR_OK) {
printf("Open failed\n");
return false;
}
// Invalid register id 0 should return NULL.
if (cs_reg_name(handle, 0) != NULL) {
printf("NULL check failed\n");
return false;
}
cs_close(&handle);
return true;
}

int main()
{
bool result = true;
result &= test_cs_reg_null_case();

return result ? 0 : -1;
}
Loading