Troubleshooting
Common build and runtime issues with Rerius and their solutions.
Repository: https://github.com/ECLS-Studio/rerius
Build Issues#
log2 undefined / linker error#
Symptom: undefined reference to 'log2' or similar during link.
Cause: The entropy module uses log2() from <math.h> which requires -lm on Linux.
Fix: LDFLAGS lives in setup.sh, not the top-level Makefile (which just delegates to setup.sh):
grep LDFLAGS setup.sh # should include -lm
If it's missing there, that's worth filing as a bug rather than patching locally, since every build would hit this.
open_memstream undeclared / not found#
Symptom: warning: implicit declaration of 'open_memstream' or linker error.
Cause: open_memstream is a POSIX extension. It requires:
- Linux: -D_GNU_SOURCE (already set in Makefile)
- macOS: -D_DARWIN_C_SOURCE (set automatically in build_js.sh for macOS)
- Minimum versions: Linux glibc ≥ 2.10, macOS ≥ 10.13
Fix (macOS):
# Ensure you're on macOS 10.13+
sw_vers -productVersion
Note: setup.sh autodetects its own compiler and doesn't read a CFLAGS_EXTRA environment variable, so make CC=clang CFLAGS_EXTRA=... won't have any effect: if -D_DARWIN_C_SOURCE genuinely isn't being set on macOS, that's a build_js.sh/setup.sh bug worth reporting rather than something to work around with env vars.
node_api.h not found#
Symptom: fatal error: node_api.h: No such file or directory
Fix:
# Debian/Ubuntu
sudo apt install libnode-dev
# Fedora
sudo dnf install nodejs-devel
# Termux - headers bundled with nodejs
pkg install nodejs
# macOS with Homebrew
brew install node
# Headers at: $(brew --prefix)/include/node/
# Or find them manually
node -p "require('path').join(process.execPath,'../../include/node')"
isprint / stdbool undeclared (Clang strict C99)#
Symptom: error: implicit declaration of function 'isprint' or error: unknown type name '_Bool'
Cause: Missing explicit includes in rerius_napi.c.
Fix: <ctype.h> and <stdbool.h> are explicitly included in the current js/src/rerius_napi.c. If you still hit this, make sure you're building from the latest tagged release rather than an old checkout or fork.
auto nested functions (GCC extension rejected by Clang)#
Symptom: error: function definition is not allowed here in src/analysis/decomp.c
Cause: GCC auto nested functions are a non-standard extension, not valid C99.
Fix: The current decomp.c uses static file-scope helpers instead. If you hit this, check you're on the latest release rather than an old checkout or fork.
macOS assembler errors in platform/arm64_bsd.S#
Symptom:
platform/arm64_bsd.S:1:19: error: unexpected token in '.section' directive
.section .note.GNU-stack,"",@progbits
Cause: arm64_bsd.S uses Linux/BSD ELF assembly syntax. macOS uses Mach-O syntax, which platform/arm64_macos.S provides instead.
Fix: build_js.sh should select platform/arm64_macos.S automatically when it detects Darwin as the OS. If you're seeing this error, the OS detection likely picked the wrong stub: check the platform-detection logic in build_js.sh/setup.sh, or file a bug with your uname -a output.
--unresolved-symbols=ignore-all not supported (LLD on Android)#
Symptom: ld: unknown argument '--unresolved-symbols=ignore-all' on Termux.
Cause: Some LLD versions use different flags.
Fix: build_js.sh detects this and falls back automatically. You can also force:
# Try alternate flag
CC=clang LDFLAGS="-Wl,-z,nodefaultlib -lm" bash build_js.sh
make says gmake not found on BSD#
# FreeBSD/OpenBSD/NetBSD
pkg install gmake # or pkg_add gmake
gmake clean && gmake
dax_guard.h not found#
Symptom: fatal error: dax_guard.h: No such file or directory during compile.
Cause: The fault isolation header introduced in v1.0.0 lives in include/. The compiler needs -I./include to find it. setup.sh includes this in BASE_CFLAGS automatically.
Fix:
# If building manually, add -I./include:
clang -std=c99 -I./include ...
# Verify setup.sh has it:
grep -- "-I./include" setup.sh # should match
Runtime Issues#
Analysis pass aborted: [!] pass 'X' recovered from fault#
Symptom: stderr shows a yellow warning like:
[!] pass 'cfg-build' recovered from fault: invalid dax_binary_t
…but analysis continues for other passes.
Cause: This is the fault isolation system (v1.0.0+) working correctly. A pass encountered a structural error in the binary (corrupt section bounds, truncated data, invalid counter) and returned early rather than crashing.
Interpretation: - The binary is likely malformed, packed, or truncated. - The output from the recovered pass is absent or partial; output from all other passes is complete. - This is not a Rerius bug.
If you believe this is a Rerius bug (the pass fails on a valid binary), build with ASan directly (setup.sh doesn't read CFLAGS_EXTRA, so compile by hand: see the source list in BUILDING.md):
clang -std=c99 -D_GNU_SOURCE -O1 -g -fsanitize=address,undefined \
-I./include -I./include/core -I./include/formats -I./include/arch -I./include/ui \
src/cli/main.c src/cli/interactive.c src/core/*.c src/formats/*.c src/arch/*.c \
src/analysis/*.c src/emu/*.c src/util/*.c -lm -o rerius-asan
# -X also enables interactive mode -- close stdin so it exits after the analysis output
./rerius-asan -X ./binary < /dev/null 2>&1 | grep -A2 "recovered from fault"
Then open a bug report with the fault message and binary details.
rerius.node not found after npm install#
Symptom: Error: Rerius native addon not found: .../js/rerius.node
Fix:
# Trigger rebuild
npm run build
# or
npm rebuild
# or from repo root
bash build_js.sh
sections() returns empty array on macOS binary#
Symptom: sections: 0 when analyzing a macOS .app binary or /bin/ls.
Cause: If this happens on the current release, check whether the Mach-O magic constants in your build match what a little-endian CPU actually reads from the file: 0xFEEDFACF should be ARM64 LE (swap=0), not big-endian. See MACHO_SUPPORT.md.
Verify:
node -e "const n=require('rerius'); n.withBinary('/bin/ls', b => console.log('sections:', b.sections().length));"
# Should print: sections: 20+ (not 0)
functions() returns empty on macOS stripped binary#
Symptom: functions: 0 on macOS ARM64 stripped binary.
Expected behavior: the prologue detector recognizes stp x29,x30, paciasp, bti, and sub sp,sp,#N (common on macOS ARM64) and falls back to the section entry point if no prologue is recognized, so functions().length should be ≥ 1 on any binary with a code section. If you're seeing 0 on the current release, that's worth a bug report with the binary's file output: see FUNCTION_DETECTION.md for how detection works and its known limitations.
disasmJson() segfaults (exit code 139)#
Symptom: Node process exits with code 139 when calling bin.disasmJson('.text') on x86-64.
Cause: A struct-layout mismatch between a local typedef in rerius_napi.c and the real x86_insn_t in x86.h would cause this kind of out-of-bounds read. If the layouts are still out of sync in the release you're on, that's a real bug worth reporting with a minimal reproduction.
The fault isolation layer (dax_guard.h) now guards all three disassembly entry points. If a section read would cause a fault, the pass recovers and prints a diagnostic instead of crashing the process.
rda() returns object instead of string#
Symptom: typeof bin.rda('.text') === 'object' (should be 'string').
Expected behavior: rda() should return an empty string "" (not null) when the section isn't found: typeof null === 'object' in JavaScript, which is the likely source of this symptom if you see it. If the current release still returns null here, that's a real bug worth reporting.
Analysis is slow on large binaries (> 10 MB)#
The main bottlenecks (see PERFORMANCE.md for measured numbers on a small binary) are:
- dax_xref_build() - single-pass O(instructions), fast in practice
- dax_rda_section() - BFS with an O(N) linear visited-set lookup (up to 65,536 entries), which dominates on large binaries with a lot of reachable code
For large binaries in a production service, cache parsed handles keyed by SHA-256:
const cache = new Map();
function getCached(file) {
const b = rerius.load(file);
if (cache.has(b.sha256)) { b.close(); return cache.get(b.sha256); }
cache.set(b.sha256, b);
return b;
}
// Clean up on exit
process.on('exit', () => cache.forEach(b => b.close()));
Valgrind reports memory errors#
setup.sh doesn't read a CFLAGS_EXTRA variable, so build with ASan directly instead (see the full source list in BUILDING.md):
clang -std=c99 -D_GNU_SOURCE -O1 -g -fsanitize=address,undefined \
-I./include -I./include/core -I./include/formats -I./include/arch -I./include/ui \
src/cli/main.c src/cli/interactive.c src/core/*.c src/formats/*.c src/arch/*.c \
src/analysis/*.c src/emu/*.c src/util/*.c -lm -o rerius-asan
./rerius-asan -x ./binary
ASan will print exact locations of any memory errors. Report findings via SECURITY.md.
AIRE#
Q: AIRE prints nothing / "no significant patterns detected".
AIRE needs upstream analysis data to synthesize. Run with the full pipeline:
./rerius -V -I --poly --aire ./binary
Without -V (IVF), --poly, and -I (emulator), AIRE has no data to interpret and will report nothing significant.
Q: AIRE shows a Memory recall banner for a binary I've never analyzed.
Memory entries are keyed by SHA-256 content hash, not file path. If you received a copy of a binary that was previously analyzed (e.g. from a coworker or CI system that also has .aire_memory in the same working directory), AIRE will match on content. Delete .aire_memory to start fresh.
Q: .aire_memory is growing too large / I want to reset it.
Delete .aire_memory from your working directory. It will be recreated fresh on the next AIRE run. The file holds at most 32 entries (~20 KB); it does not grow unboundedly.
Q: AIRE context block says "general analysis" even though the binary is clearly packed.
AIRE's packer detection requires entropy scan data. Make sure to include -e in your flags:
./rerius -e -V --poly --aire ./binary
Getting Help#
If none of the above solves your issue:
- Check existing issues
- Include: Rerius version, OS/arch, compiler version, exact error output
- Open a bug report
For security vulnerabilities, see SECURITY.md - do not open public issues.
docs/TROUBLESHOOTING.md · Rerius v1.0.0