mirror of
https://github.com/elicpeter/nyx.git
synced 2026-07-09 20:52:11 +02:00
Phase 1 (#33)
* chore: Exclude CLAUDE.md from Cargo.toml * feat: add callgraph module and integrate into main analysis flow * feat: enhance CLI with new severity filtering and analysis modes * feat: update CHANGELOG with recent enhancements and fixes to severity filtering and output handling * feat: implement state-model dataflow analysis for resource lifecycle and auth state * feat: enhance diagnostic output formatting and add evidence structure * feat: implement attack surface ranking for diagnostics with scoring and sorting * feat: add comprehensive documentation for installation, usage, and rules reference * feat: add multiple language support for command execution and evaluation endpoints * feat: implement inline suppression for findings using `nyx:ignore` comments * feat: add confidence levels to AST patterns and update output structure * feat: implement low-noise prioritization system with category filtering, rollup grouping, and configurable budgets * feat: bump version to 0.4.0 and update changelog with new features and improvements * feat: add dead code allowances to various functions in mod.rs and real_world_tests.rs
This commit is contained in:
parent
19b578c5c4
commit
1bbe4b1cfb
456 changed files with 25628 additions and 1228 deletions
12
tests/fixtures/state/both_branches_close.c
vendored
Normal file
12
tests/fixtures/state/both_branches_close.c
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* Both branches close f — no leak on any path.
|
||||
Expected: NO state- findings. */
|
||||
void both_close(int cond) {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
if (cond) {
|
||||
fclose(f);
|
||||
} else {
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
13
tests/fixtures/state/chain_ops.c
vendored
Normal file
13
tests/fixtures/state/chain_ops.c
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* Multiple resource operations in sequence: open → read → write → close.
|
||||
Tests that repeated uses do not corrupt lifecycle state.
|
||||
Expected: NO state- findings. */
|
||||
void chain_ops(void) {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
char buf[256];
|
||||
fread(buf, 1, sizeof(buf), f);
|
||||
fwrite(buf, 1, sizeof(buf), f);
|
||||
fread(buf, 1, sizeof(buf), f);
|
||||
fclose(f);
|
||||
}
|
||||
9
tests/fixtures/state/clean.c
vendored
Normal file
9
tests/fixtures/state/clean.c
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include <stdio.h>
|
||||
|
||||
void clean_usage() {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
char buf[256];
|
||||
fread(buf, 1, sizeof(buf), f);
|
||||
fclose(f);
|
||||
// Clean: open, use, close — no bugs
|
||||
}
|
||||
7
tests/fixtures/state/double_close.c
vendored
Normal file
7
tests/fixtures/state/double_close.c
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
void double_close_bug() {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
fclose(f);
|
||||
fclose(f); // BUG: double close
|
||||
}
|
||||
14
tests/fixtures/state/double_close_branch.c
vendored
Normal file
14
tests/fixtures/state/double_close_branch.c
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* fclose inside a branch, then unconditional fclose after.
|
||||
True path: fclose(OPEN→CLOSED), then fclose(CLOSED) = double close.
|
||||
False path: skip inner fclose, then fclose(OPEN→CLOSED) = fine.
|
||||
Converged state at the second fclose: OPEN|CLOSED (join).
|
||||
Expected: NO state-double-close (conservative: join masks the bug). */
|
||||
void double_close_branch(int cond) {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
if (cond) {
|
||||
fclose(f);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
10
tests/fixtures/state/double_close_straight.c
vendored
Normal file
10
tests/fixtures/state/double_close_straight.c
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* Straight-line double close — no branching ambiguity.
|
||||
The converged state at the second fclose is definitely CLOSED.
|
||||
Expected: state-double-close. */
|
||||
void double_close_straight(void) {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
fclose(f);
|
||||
fclose(f);
|
||||
}
|
||||
11
tests/fixtures/state/early_return_may_leak.c
vendored
Normal file
11
tests/fixtures/state/early_return_may_leak.c
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* Early return leaks on the error path; normal path closes.
|
||||
Expected: state-resource-leak-possible (may-leak). */
|
||||
void early_return_leak(int err) {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
11
tests/fixtures/state/handle_overwrite.c
vendored
Normal file
11
tests/fixtures/state/handle_overwrite.c
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* The first fopen result is overwritten by the second fopen.
|
||||
The first handle leaks silently because per-variable tracking
|
||||
loses the old allocation. The second handle is properly closed.
|
||||
Expected: NO state- findings (known per-variable-tracking limitation). */
|
||||
void overwrite_handle(void) {
|
||||
FILE *f = fopen("a.txt", "r");
|
||||
f = fopen("b.txt", "r");
|
||||
fclose(f);
|
||||
}
|
||||
14
tests/fixtures/state/loop_clean.c
vendored
Normal file
14
tests/fixtures/state/loop_clean.c
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* Open before loop, use inside loop, close after loop.
|
||||
The back-edge should not prevent convergence.
|
||||
Expected: NO state- findings. */
|
||||
void loop_clean(void) {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
char buf[256];
|
||||
int i;
|
||||
for (i = 0; i < 10; i++) {
|
||||
fread(buf, 1, sizeof(buf), f);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
16
tests/fixtures/state/loop_use_after_close.c
vendored
Normal file
16
tests/fixtures/state/loop_use_after_close.c
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* Close before the loop, then use inside the loop body.
|
||||
The back-edge means the use node joins CLOSED (first iter)
|
||||
with CLOSED (back-edge, still CLOSED). The converged state
|
||||
at the fread call is CLOSED → use-after-close.
|
||||
Expected: state-use-after-close. */
|
||||
void loop_use_after_close(void) {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
fclose(f);
|
||||
char buf[256];
|
||||
int i;
|
||||
for (i = 0; i < 10; i++) {
|
||||
fread(buf, 1, sizeof(buf), f);
|
||||
}
|
||||
}
|
||||
10
tests/fixtures/state/malloc_free_clean.c
vendored
Normal file
10
tests/fixtures/state/malloc_free_clean.c
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
/* malloc followed by free — clean.
|
||||
Tests the memory resource pair.
|
||||
Expected: NO state- findings. */
|
||||
void malloc_free_clean(void) {
|
||||
void *p = malloc(100);
|
||||
*(char *)p = 'x';
|
||||
free(p);
|
||||
}
|
||||
9
tests/fixtures/state/malloc_leak.c
vendored
Normal file
9
tests/fixtures/state/malloc_leak.c
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
/* malloc without free — resource leak.
|
||||
Tests the memory resource pair (malloc → free).
|
||||
Expected: state-resource-leak. */
|
||||
void malloc_leak(void) {
|
||||
void *p = malloc(100);
|
||||
*(char *)p = 'x';
|
||||
}
|
||||
10
tests/fixtures/state/may_leak_branch.c
vendored
Normal file
10
tests/fixtures/state/may_leak_branch.c
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* Only the true branch closes f; the false branch leaks.
|
||||
Expected: state-resource-leak-possible (NOT state-resource-leak). */
|
||||
void may_leak(int cond) {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
if (cond) {
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
11
tests/fixtures/state/multiple_handles.c
vendored
Normal file
11
tests/fixtures/state/multiple_handles.c
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* Two separate handles: f1 is closed, f2 is leaked.
|
||||
Expected: state-resource-leak for f2, NO state-resource-leak for f1.
|
||||
(The finding message should contain "f2".) */
|
||||
void multiple_handles(void) {
|
||||
FILE *f1 = fopen("a.txt", "r");
|
||||
FILE *f2 = fopen("b.txt", "r");
|
||||
fclose(f1);
|
||||
/* f2 never closed */
|
||||
}
|
||||
16
tests/fixtures/state/nested_branch_leak.c
vendored
Normal file
16
tests/fixtures/state/nested_branch_leak.c
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* Nested if — only the innermost branch closes.
|
||||
Path true→true: fclose → CLOSED (clean)
|
||||
Path true→false: no close → OPEN (leak)
|
||||
Path false: no close → OPEN (leak)
|
||||
Joined at exit: OPEN|CLOSED → may-leak.
|
||||
Expected: state-resource-leak-possible. */
|
||||
void nested_branch_leak(int a, int b) {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
if (a) {
|
||||
if (b) {
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
tests/fixtures/state/reopen_after_close.c
vendored
Normal file
12
tests/fixtures/state/reopen_after_close.c
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* Open, close, then reopen the same variable and close again.
|
||||
The second fopen overwrites CLOSED with OPEN; the second fclose
|
||||
brings it back to CLOSED. Clean usage.
|
||||
Expected: NO state- findings. */
|
||||
void reopen_after_close(void) {
|
||||
FILE *f = fopen("a.txt", "r");
|
||||
fclose(f);
|
||||
f = fopen("b.txt", "r");
|
||||
fclose(f);
|
||||
}
|
||||
9
tests/fixtures/state/resource_leak.c
vendored
Normal file
9
tests/fixtures/state/resource_leak.c
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include <stdio.h>
|
||||
|
||||
void resource_leak_bug() {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
if (f == NULL) {
|
||||
return;
|
||||
}
|
||||
// Missing fclose(f) — resource leak
|
||||
}
|
||||
8
tests/fixtures/state/use_after_close.c
vendored
Normal file
8
tests/fixtures/state/use_after_close.c
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#include <stdio.h>
|
||||
|
||||
void use_after_close_bug() {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
fclose(f);
|
||||
char buf[256];
|
||||
fread(buf, 1, sizeof(buf), f); // BUG: use after close
|
||||
}
|
||||
16
tests/fixtures/state/use_closed_branch.c
vendored
Normal file
16
tests/fixtures/state/use_closed_branch.c
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* fclose in one branch, then unconditional fread after.
|
||||
True path: fclose(f) → fread(CLOSED) = use-after-close.
|
||||
False path: fread(OPEN) = fine.
|
||||
Converged state at fread: OPEN|CLOSED (join).
|
||||
Expected: NO state-use-after-close (conservative: join masks it).
|
||||
Expected: state-resource-leak-possible (false path never closes). */
|
||||
void use_closed_branch(int cond) {
|
||||
FILE *f = fopen("data.txt", "r");
|
||||
if (cond) {
|
||||
fclose(f);
|
||||
}
|
||||
char buf[256];
|
||||
fread(buf, 1, sizeof(buf), f);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue