Commit graph

8 commits

Author SHA1 Message Date
6a68c9d69b
passes,core: debug fakes - line numbers and source removal
DebugConfig gains fake_line_numbers (deterministic upward walk
replacing LineNumberTable rows when stripping is off; strip wins)
and strip_source_file (drops SourceFile entirely, beating spoof).
Debug tests moved to passes/tests/debug_info.rs with new cases
for both flags and their precedence.
2026-10-09 14:08:08 +02:00
2cbb9db31e
passes: junk classes with real bodies and no fingerprint
NoisePass now builds branching helper methods (counted int loop,
random arithmetic, even/odd merge, non-throwing ops only) whose
results the entry sums into a private static field, instead of an
empty run()V. Names come from the same NameGenerator styles as
real code and live in a random real package (no more shadow/decoy
uniformity for grep to catch); every generated method gets fresh
StackMapTable frames. weave_first_reachable takes (class, entry)
pairs. New NoiseConfig.junk_methods_per_class (default 3).

Tests assert invariants (unique valid identifiers, calls, field
store, determinism) plus real-JVM verification of junk classes;
paranoid+junk_ratio=1 smoke on lorep: 18 junk classes, all load.
2026-10-09 14:04:24 +02:00
139aea9a8f
frames,jar,passes: verifier-driven hardening from real jars
Proven by paranoid runs over lorep (17 classes, fully green),
LoVisual (4081 classes) and oc2r (1278 classes) with per-class
java -Xverify:all, each fix first reproduced as a red test:

- merge: Top absorbs instead of Top-wins (javac declares Top for
  slots unwritten on some inflow; precise types reject those edges).
  Regression: loop_head_keeps_top_for_loop_local.
- emit: collapse [Long|Double, Top] pairs on operand stacks
  (javac writes one entry; the pair is rejected). Regression:
  wide_stack_join_emits_single_entries.
- xfer ArrayLoad: push the wide pair, fixing lcmp underflow.
  Regression: array_load_wide_pushes_pair.
- xfer <init>: convert only the receiver's own allocation site
  instead of every Uninitialized (nested construction clobbered
  the outer object). Regression: nested_construction_keeps_outer.
- xfer ANewArray: array operands gain one dimension ([B] -> [[B)
  instead of an illegal L-wrap ([L[B;). Covered by the same test.
- jar load: duplicate class names (multi-release module-info
  twins) keep the first occurrence instead of crashing save.
  Test: duplicate_class_names_keep_first.
- strings/constants: skip methods past MAX_METHOD_INSNS (8000)
  so giants cannot overflow the 64KB writer ceiling. Tests:
  oversized_methods_are_skipped in both passes.
- merge errors now name both types being merged.

Also: em-dash removed repo-wide (724 spots, rule added to
todo.md), allow-lints only in tests (scratch example deleted),
code comments migrated to English in every file this change
touches.
2026-10-09 13:47:27 +02:00
2172206e83
passes: implement control-flow pass (4 schemes + rotation)
FlowPass rebuilds one method per scheme picked from FlowConfig:
state-spread (dense tableswitch dispatcher), computed-switch
(sparse lookupswitch over a counter local), butterfly (branch
inversion), exception-goto (dispatcher under try with a dead
catch-all), plus opaque goto-splices inside every method and
StackMapTable recomputation afterwards. Now in standard_pipeline
(between constants and noise); --no-flow is an honest off-flag.

Acceptance is real JVM, not shapes: per-scheme verify, rotation
spread, calc-prints-45 execution, paranoid smoke on lorep-1.1.0
(131 methods rebuilt, no new failures over standard).

Two verifier rules learned the hard way are now construction
invariants: no inserted mark shares a bytecode offset with a
foreign one (nop pads), and no frameless gap follows a terminal
(dead blocks are opaque-entered and throw).

Also fixes a latent frame-emitter bug the pass exposed: wide
stack values were written as slot pairs ([Double, Top]) while
javac writes one entry ([Double]); HotSpot rejects the pair.
Stacks now collapse like locals (emit::stack_vars), with a
regression test in classfile/tests/frames.rs.
2026-10-09 11:11:55 +02:00
39178420e4
structure-check: gate counts code lines, docs and comments in English
Gate ignores blank and full-line comment lines so the 250-line limit
measures code bulk, not documentation weight; docs/README.md synced.
Translate code comments to English in classfile, core config, namegen,
rename assign, constants forms. Expand Plausible word bank with
client-ecosystem terms (Module, Setting, Mixin, ...). cargo fmt clean,
check.sh green.
2026-10-09 10:31:02 +02:00
f08bf60635 classfile: intern constant-pool entries on write (fix LVTT/LVT ClassFormatError)
ristretto's ConstantPool never deduplicates: every add_* pushes a new entry.
HotSpot matches each LocalVariableTypeTable entry to a LocalVariableTable
entry by raw name_index, so when a name (e.g. a local's) was interned twice
the two tables got different indices and the class failed to load:
'ClassFormatError: LVTT entry ... does not match any LVT entry'.

The writer now memoizes every pool builder by its semantic key and rebuilds
composite constants (Class/NameAndType/Fieldref/Methodref/MethodHandle/
Dynamic) from our own utf8/class primitives so ristretto never mints a
shadow Utf8. This also shrinks the pool (no more ldc -> ldc_w widening that
changed code length on a pure round-trip).

Split pool.rs into a pool/ module (refs in pool/refs.rs) to respect the
file-size gate. Regression test: tests/pool asserts the written pool has no
duplicate CONSTANT_Utf8. Verified: pure parse->write of the neoforge jar
(92 classes) now loads under java -Xverify:all with 0 errors.
2026-10-08 22:55:49 +02:00
2674d7fc89 classfile,passes: model Nest attributes as IR (fix ClassFormatError)
NestHost/NestMembers were carried as Attribute::Raw with constant-pool
indices baked in. During writing the pool is rebuilt in a different order,
so those indices pointed at the wrong entries and the JVM rejected the
class: ClassFormatError: Nest member/host class_info_index N has bad
constant type.

Model them explicitly in the IR, convert on parse and write (resolving
class names through the new pool), and remap their class names during
rename. Add a NestMembers round-trip regression test. Verified on a real
jar: all Nest ClassFormatErrors gone.
2026-10-08 22:26:58 +02:00
a641e69455 Initial commit: noxis JVM bytecode obfuscator
Workspace of 9 crates (noxis, noxis-core, noxis-classfile, noxis-analysis,
noxis-passes, noxis-runtime, noxis-jar, noxis-verify, noxis-structure-check).
AGPL-3.0-only license, Rust 2024 edition, unsafe_code denied.
2026-10-08 22:01:03 +02:00