Community & Contributing
Rerius is Apache 2.0, developed in the open. There's no dark-pattern gating here: the CLI, C library, and npm package are the whole project; nothing functional is held back behind an account or a paid tier.
Contributing to Rerius
Repository: https://github.com/ECLS-Studio/rerius
Table of Contents#
- Code of Conduct
- Ways to Contribute
- Development Setup
- Submitting a Pull Request
- Code Style
- Commit Messages
- Testing
- Adding New Features
Code of Conduct#
All contributors are expected to follow the Code of Conduct.
Ways to Contribute#
- Report bugs: open a bug report
- Request features: GitHub Discussions or feature request
- Fix bugs: check issues labelled
bugorgood first issue - Improve decode coverage: add ARM64, x86-64, or RISC-V instructions to the decoders in
src/arch/ - Add architecture support: e.g. MIPS, PowerPC, Thumb-2
- Improve the decompiler / SSA-NR pass: better lifting patterns, type tagging, call-target resolution
- Write tests: expand
js/test/basic.js - Improve documentation: fix inaccuracies, add examples
Security vulnerabilities: report privately: see SECURITY.md. Do not open a public issue or PR for a security bug.
Development Setup#
git clone https://github.com/ECLS-Studio/rerius.git
cd Rerius
# Build CLI and JS addon
make
# Verify
./rerius -h
node js/test/basic.js # all 27 tests should pass
Termux:
pkg install nodejs clang make git
git clone https://github.com/ECLS-Studio/rerius.git && cd Rerius && make
Submitting a Pull Request#
- Fork the repository and create a branch from
main:bash git checkout -b fix/cfg-dead-bytes - Make your changes, following the Code Style guide below.
- Build cleanly:
make clean && make - Run the test suite:
node js/test/basic.js - Push and open a PR against
main. - Fill in the PR template completely: reviewers will ask for missing context otherwise.
PRs that fail CI or introduce new compiler warnings are not merged.
Code Style#
C (C99, strict)#
/* snake_case for functions and variables */
int dax_cfg_build(dax_binary_t *bin, uint8_t *code, size_t sz, uint64_t base, int func_idx);
/* _t suffix for types */
typedef struct { ... } dax_section_t;
/* ALL_CAPS for macros and enum values */
#define DAX_MAX_SECTIONS 128
typedef enum { SEC_TYPE_CODE, SEC_TYPE_DATA } dax_sec_type_t;
/* Explicit integer types */
uint32_t n; /* not: unsigned int */
uint64_t addr; /* not: unsigned long long */
/* Check all heap allocations */
bin->data = calloc(sz, 1);
if (!bin->data) return -1;
/* Return 0 on success, -1 on failure */
Favor self-documenting names over comments that just restate what a line does. That said, module-level and "why" comments are used throughout the codebase (see the header block in src/analysis/dsa.c for the expected style): explain non-obvious algorithm choices and tradeoffs, not what i++ does.
Fault isolation: expected for every new analysis module:
Every public entry point should include dax_guard.h (after dax.h) and open with a guard:
#include "dax.h"
#include "dax_guard.h"
void dax_mymodule(dax_binary_t *bin, dax_opts_t *opts, FILE *out) {
DAX_GUARD_BIN(bin); /* returns void on bad bin */
if (!opts || !out) return;
/* ... */
}
int dax_mymodule_build(dax_binary_t *bin, int fi) {
DAX_GUARD_BIN_RET(bin, -1); /* returns -1 on bad bin */
DAX_GUARD_FUNC_RET(bin, fi, -1); /* returns -1 on OOB fi */
/* ... */
}
All loops over dax_binary_t counter fields should have a DAX_MAX_* upper bound:
/* correct */
for (i = 0; i < bin->nfunctions && i < DAX_MAX_FUNCTIONS; i++) { ... }
/* missing the DAX_MAX guard: avoid this */
for (i = 0; i < bin->nfunctions; i++) { ... }
All section offset arithmetic should use the overflow-safe subtraction form:
/* correct */
if (sec->size > bin->size - sec->offset) continue;
/* can overflow on large offset values: avoid this */
if (sec->offset + sec->size > bin->size) continue;
Set the fault flag when aborting early so DAX_RUN_PASS can report it:
if (something_wrong) {
dax_fault_set("brief reason string");
return;
}
Avoid adding new external dependencies: no #include beyond what's already used in the codebase, no new npm packages, unless there's a strong reason and it's discussed first in an issue.
Code should compile cleanly under clang -std=c99 -Werror. Avoid non-standard compiler extensions (nested functions, __builtin_* without a portable fallback) so the project keeps building on all supported compilers.
JavaScript#
'use strict'; // always
const / let // never var
camelCase // functions and variables
#privateField // class private fields
Commit Messages#
Use Conventional Commits:
<type>(<scope>): <description>
| Type | When |
|---|---|
feat |
New feature |
fix |
Bug fix |
perf |
Performance improvement |
refactor |
No behavior change |
docs |
Documentation only |
build |
Makefile, build_js.sh, workflows |
test |
Tests |
chore |
Version bumps, formatting |
Examples:
feat(cfg): two-pass builder pre-registers all branch targets
fix(unicode): reject UTF-16LE strings without codepoints > U+02FF
fix(decomp): replace non-portable compiler extension with a static helper
build: add -lm to LDFLAGS for entropy log2()
docs: update CLI_REFERENCE.md with -e -R -V flags
Testing#
Rerius uses a hand-written test suite in js/test/basic.js (27 tests, no external test framework).
# Full test run
node js/test/basic.js
# Test against a specific binary
RERIUS_TEST_BIN=/path/to/binary node js/test/basic.js
# Quick CLI smoke tests
./rerius -x /bin/ls > /dev/null && echo OK
./rerius -e -R -V /bin/ls > /dev/null && echo OK
When contributing:
- All existing tests must still pass.
- Add new tests for any new JS API methods.
- For CFG changes: test against a binary with irregular control flow (computed jumps, jump tables).
- For Unicode changes: test against a Windows PE binary with UTF-16LE strings.
Adding New Features#
New CLI analysis module#
- Create the module under the matching subdirectory (e.g.
src/analysis/mymodule.cfor a new analysis pass) and implement the analysis function. - Add
#include "dax_guard.h"after#include "dax.h"in the new file. - Open every public entry point with
DAX_GUARD_BIN(bin)orDAX_GUARD_BIN_RET(bin, retval). - Cap all loops over
bin->nfunctions,bin->nsections, etc. with&& i < DAX_MAX_*. - Use the overflow-safe
sec->size > bin->size - sec->offsetform for all section bounds checks. - Declare the function in
include/core/dax.h:void dax_mymodule(dax_binary_t *bin, dax_opts_t *opts, FILE *out); - Add a flag to
dax_opts_t:int mymodule; - Wire it up in
src/cli/main.cusingDAX_RUN_PASS("mymodule", opts.color, dax_mymodule(&bin, &opts, stdout)); - Add the new source file to
SRCSinMakefileandLIB_SRCSinbuild_js.sh. - Add an N-API wrapper in
js/src/rerius_napi.c. - Add the method to
js/index.jsand its type declaration tojs/index.d.ts. - Add an endpoint to
js/server/server.js. - Add a panel to
js/server/ui.html. - Add tests to
js/test/basic.js. - Document the change in
CHANGELOG.md,docs/API.md, anddocs/CLI_REFERENCE.md.
New architecture#
- Add
ARCH_NEWARCHtodax_arch_tininclude/core/dax.h. - Create
include/arch/newarch.handsrc/arch/newarch_decode.c. - Add
dax_disasm_newarch()insrc/arch/disasm.c. - Add
dax_classify_newarch()insrc/analysis/analysis.c. - Wire it up in
src/core/loader.c,src/cli/main.c, andsrc/analysis/cfg.c. - Add the new source file(s) to the Makefile/build script.
New architecture support is a substantial undertaking: expect it to touch the decoder, classifier, CFG builder, and (if you want CFG/loop/call-graph support) the analysis passes that assume an instruction shape. Open an issue to discuss scope before starting.
License#
By contributing, you agree that your changes will be licensed under the Apache 2.0 License.