Skip to content
exteraStuffPublic

About

A JVM class file parser written in Rust

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

6 Commits

Folders and files

Repository files navigation

jvm-class

crates.io docs.rs license

A JVM class file parser written in Rust.

jvm-class turns the bytes of a .class file into a typed structure: constant pool, access flags, fields, methods and attributes. Parsing borrows from the input buffer, so string data, bytecode and unknown attribute payloads are slices, not copies.

Features

  • Zero-copy: Class<'a> borrows the input slice; no allocation for UTF-8 data or code arrays.
  • Strict validation: magic, class file version, constant pool bounds and slot usage, attribute lengths and constant pool entry kinds are all checked, and trailing bytes are an error.
  • CESU-8 aware: constant pool strings are exposed as Cesu8Bytes, decoded on demand (Java's modified UTF-8, including surrogate pairs and the two-byte encoded NUL).
  • Typed attributes: all attributes defined up to Java SE 8 are parsed into enum variants; unrecognized ones are kept verbatim as AttributeInfo::Unknown.
  • No unsafe, two small dependencies (bitflags, cesu8).

Supported class file versions

Major versions 45 to 52 — Java 1.1 through Java 8. Anything outside that range is rejected with Error::UnsupportedVersion.

Installation

cargo add jvm-class

Or add it manually:

[dependencies]
jvm-class = "0.1"

Usage

use jvm_class::{Class, MethodAccessFlags};

let bytes = std::fs::read("Sample.class")?;
let class = Class::parse(&bytes)?;

println!("class {} (major version {})", class.name()?, class.major_version);

for method in &class.methods {
    let name = method.name(&class.constant_pool)?;
    let descriptor = method.descriptor(&class.constant_pool)?;
    let is_static = method.access_flags.contains(MethodAccessFlags::STATIC);

    println!("  {}{name}{descriptor}", if is_static { "static " } else { "" });
}
# Ok::<(), Box<dyn std::error::Error>>(())

Bytecode and the exception table live in the Code attribute:

use jvm_class::{AttributeInfo, Class};

# let bytes = std::fs::read("Sample.class")?;
# let class = Class::parse(&bytes)?;
for method in &class.methods {
    for attribute in &method.attributes {
        if let AttributeInfo::Code { max_stack, max_locals, code, .. } = attribute {
            println!(
                "{}: {} bytes of bytecode, max_stack={max_stack}, max_locals={max_locals}",
                method.name(&class.constant_pool)?,
                code.len(),
            );
        }
    }
}
# Ok::<(), Box<dyn std::error::Error>>(())

The constant pool is indexed exactly like in the class file — 1-based, with Long and Double taking two slots. Reading the unusable second slot is an error rather than a panic:

use jvm_class::{Class, ConstantPoolInfo};

# let bytes = std::fs::read("Sample.class")?;
# let class = Class::parse(&bytes)?;
for (index, entry) in class.constant_pool.iter() {
    if let ConstantPoolInfo::Utf8 { bytes } = entry {
        println!("#{index} = {}", bytes.decode()?);
    }
}
# Ok::<(), Box<dyn std::error::Error>>(())

If you need to parse a class embedded in a larger buffer, use Class::try_read with a Cursor instead of Class::parse; it leaves the remaining bytes in the cursor rather than failing with Error::TrailingBytes.

Error handling

Every fallible operation returns jvm_class::Result<T>, an alias for std::result::Result<T, jvm_class::Error>. Error implements Display and std::error::Error, and each variant carries the offending value — the tag, index, version or byte count that caused the failure.

Minimum supported Rust version

Rust 1.85 (edition 2024).

Testing

The test suite parses real class files compiled from the Java sources in tests/fixtures/java, plus hand-built malformed classes that exercise every error variant.

cargo test

To rebuild the fixtures you need a javac that supports --release 8 on PATH:

tests/fixtures/build.sh

License

MIT — see LICENSE.

About

A JVM class file parser written in Rust

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages