Skip to content

Commit 31be53c

Browse files
dfa1claude
andcommitted
docs: update CLAUDE/SECURITY/CHANGELOG for proto-rewrite
CLAUDE.md: - regenerate-sources flow: drop `brew install protobuf`, add `./mvnw compile -pl proto-gen` pre-step - metadata-only encoding example uses `.encode()` not `.toByteArray()` and includes the decode-side snippet - note `ProtoReader`/`ProtoWriter` are package-private + the `ofXxxValue` factory pattern for oneof messages SECURITY.md: - update threat-model intro to reference the in-tree `ProtoReader` instead of `protobuf-java` - supported versions bumped: 0.6.x supported, 0.5.x critical-only, < 0.5 EOL - drop `protobuf-java` from out-of-scope deps; add ProtoReader hardening to defensive guarantees (varint cap, truncated-len-delim, bounds) - exception list: `IOException` from proto reader replaces "raw Protobuf parser exceptions" CHANGELOG.md: - new [0.6.0] section: proto-rewrite summary, ProtoReader/Writer, proto-gen module, oneof factories, dependency removal (`protobuf-java`), wire-format compatibility evidence (Rust integration tests), perf note (within noise on bulk reads) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 618391b commit 31be53c

3 files changed

Lines changed: 103 additions & 17 deletions

File tree

CHANGELOG.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,70 @@ All notable changes to **vortex-java** are documented here.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.6.0] — Unreleased
9+
10+
The headline theme is the **proto-rewrite**: `protobuf-java` is dropped in favour of an
11+
in-tree MemorySegment-native proto3 codec, generated from `.proto` schemas by a new
12+
`proto-gen` module. CLI uber-jar shrinks ~14% and the JDK 25 `sun.misc.Unsafe` stderr
13+
warning (emitted by `protobuf-java`'s `UnsafeUtil`) is gone.
14+
15+
### Added
16+
17+
- **`proto-gen` module** — build-time `.proto` to Java code generator. Lexer + parser +
18+
type registry + emitter. Outputs one immutable Java `record` per message and one Java
19+
`enum` per proto enum, each carrying a `@Generated("io.github.dfa1.vortex.protogen.CodeGen")`
20+
annotation. Records expose `decode(MemorySegment, long, long)` static factories and
21+
`encode()` instance methods that operate directly on a memory segment — zero `byte[]`
22+
copy, no `protobuf-java` runtime.
23+
- **`ProtoReader` / `ProtoWriter`** — package-private proto3 wire-format primitives
24+
under `io.github.dfa1.vortex.proto`. Reads varint / sint64 / fixed32 / fixed64 /
25+
length-delimited / packed-repeated payloads, with bounds checks and a 10-byte cap on
26+
varint length. 42 unit tests cover happy path + truncation + bounds.
27+
- **Oneof factories** on generated records (e.g. `ScalarValue.ofInt64Value(123L)`) —
28+
avoids the 11-arg constructor for `ScalarValue`'s oneof.
29+
- **`PatchedMetadata` / `VariantMetadata`** — added to `encodings.proto`. Previously
30+
hand-parsed with `CodedInputStream`; now go through the generated record path.
31+
32+
### Changed
33+
34+
- **Build-time tooling**: `regenerate-sources` profile no longer shells out to `protoc`.
35+
Run `./mvnw compile -pl proto-gen` once, then
36+
`./mvnw generate-sources -pl core -P regenerate-sources`. `brew install protobuf` is
37+
no longer needed for normal development.
38+
- **Encoding consumers**: 25 encoding classes (`ALP`, `Bitpacked`, `Dict`, `Rle`,
39+
`Sparse`, `Sequence`, etc.) and 23 test files rewritten to use the new record API.
40+
Constructor calls are positional; field accessors follow proto3 snake_case
41+
(`meta.bit_width()`, not `meta.getBitWidth()`).
42+
43+
### Removed
44+
45+
- **`com.google.protobuf:protobuf-java`** dependency dropped from `core`, `reader`,
46+
`writer`, and root `dependencyManagement`. The `protobuf.version` property is gone.
47+
CLI uber-jar: **14 MB → 12 MB**. JDK 25 `sun.misc.Unsafe::arrayBaseOffset` stderr
48+
warning emitted by `UnsafeUtil` on every cold start: **gone**.
49+
- `protoc` no longer required by the build. `brew install flatbuffers` covers `.fbs`
50+
edits; `.proto` edits use the in-process generator.
51+
52+
### Compatibility
53+
54+
Wire-format compatibility with the Rust reference implementation is unchanged and is
55+
verified by the full integration suite:
56+
57+
- `RustWritesJavaReadsIntegrationTest` (10 tests) — Rust writes, Java reads
58+
- `JavaWritesRustReadsIntegrationTest` (194 tests) — Java writes, JNI reads
59+
- `RustJavaReaderComparisonIntegrationTest` (25 tests) — both readers, same file
60+
- `ParquetImportIntegrationTest` (5 tests) — round-trip through ParquetImporter
61+
62+
All 872 unit + 243 integration tests pass on JDK 25.
63+
64+
### Performance
65+
66+
No measurable change on bulk-read benchmarks (`RustVsJavaReadBenchmark.javaReadCascading`
67+
within 1% of main, stdev ±2 ops/s). Proto metadata parse is < 1% of work on multi-million-row
68+
scans; the win is architectural, not throughput.
69+
70+
[0.6.0]: https://github.com/dfa1/vortex-java/compare/v0.5.0...main
71+
872
## [0.5.0] — 2026-06-09
973

1074
The headline themes are an **interactive inspector TUI** for navigating Vortex files

CLAUDE.md

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,24 @@ Never use `mvn install` or `./mvwn install`.
1818

1919
Generated sources (`fbs`/`proto` → Java) are committed under `core/src/main/java`.
2020
Normal builds need no external tools.
21+
22+
Proto-to-Java generation is in-process via the `proto-gen` module (no `protoc` needed).
23+
The generator emits one record per message with a {@code decode(MemorySegment, long, long)} static
24+
factory and an {@code encode()} method that operate directly on a memory segment — no `byte[]`
25+
copy, no `protobuf-java` runtime, no `sun.misc.Unsafe`.
26+
2127
To regenerate after editing `.fbs` or `.proto` schemas:
2228

2329
```bash
24-
brew install flatbuffers protobuf
30+
brew install flatbuffers # only needed for .fbs edits
31+
./mvnw compile -pl proto-gen # build the proto generator (only on .proto edits)
2532
./mvnw generate-sources -pl core -P regenerate-sources
2633
# then commit the updated files
2734
```
2835

2936
Any `flatc` version works — the profile strips the version guard automatically.
37+
`flatc` runs every time the profile is active; if you only changed `.proto` files, revert any
38+
spurious `fbs/` diffs with `git checkout -- core/src/main/java/io/github/dfa1/vortex/fbs/`.
3039

3140
```bash
3241
# Build all modules
@@ -276,18 +285,26 @@ Simple encodings (≤ ~80 lines total, e.g. `NullEncoding`, `BoolEncoding`) are
276285

277286
### Metadata-only encodings
278287

279-
Some encodings store all data in protobuf metadata — no buffers, no children (e.g. `SequenceEncoding`).
288+
Some encodings store all data in proto3 metadata — no buffers, no children (e.g. `SequenceEncoding`).
280289
Their `EncodeResult` uses an `EncodeNode` with `metadata` set and an empty `bufferIndices` array:
281290

282291
```java
283-
ByteBuffer metaBuf = ByteBuffer.wrap(meta.toByteArray());
292+
ByteBuffer metaBuf = ByteBuffer.wrap(meta.encode());
284293
EncodeNode node = new EncodeNode(encodingId, metaBuf, new EncodeNode[0], new int[]{});
285-
return new
294+
return new EncodeResult(node, List.of(), null, null);
295+
```
286296

287-
EncodeResult(node, List.of(), null,null);
297+
The decoder reads back via `ctx.metadata()`, not `ctx.buffer(n)`:
298+
299+
```java
300+
MemorySegment metaSeg = MemorySegment.ofBuffer(ctx.metadata().duplicate());
301+
FooMetadata meta = FooMetadata.decode(metaSeg, 0, metaSeg.byteSize());
288302
```
289303

290-
The decoder reads back via `ctx.metadata()`, not `ctx.buffer(n)`.
304+
Generated proto records live in `io.github.dfa1.vortex.proto`. The runtime decoder
305+
(`ProtoReader`, `ProtoWriter`) is package-private — generated code calls it directly.
306+
For oneof messages (e.g. `ScalarValue`), prefer the static `ofXxxValue(v)` factory over
307+
the 11-arg constructor.
291308

292309
## Testing
293310

SECURITY.md

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
# Security Policy
22

33
`vortex-java` reads and writes the [Vortex columnar file format](https://github.com/vortex-data/vortex).
4-
The reader memory-maps and parses untrusted binary input — trailers, FlatBuffers, Protobuf
5-
metadata, and per-segment encoded data. Robustness against malformed input is treated as a
6-
correctness contract, not a best-effort feature.
4+
The reader memory-maps and parses untrusted binary input — trailers, FlatBuffers, proto3
5+
metadata (via the in-tree MemorySegment-native `ProtoReader` — no `protobuf-java` runtime),
6+
and per-segment encoded data. Robustness against malformed input is treated as a correctness
7+
contract, not a best-effort feature.
78

89
## Supported versions
910

@@ -12,9 +13,9 @@ only if the vulnerability is critical and the fix is mechanical.
1213

1314
| Version | Status |
1415
| ------- | ----------------------- |
15-
| 0.4.x | Supported |
16-
| 0.3.x | Critical fixes only |
17-
| < 0.3 | End of life |
16+
| 0.6.x | Supported |
17+
| 0.5.x | Critical fixes only |
18+
| < 0.5 | End of life |
1819

1920
## Reporting a vulnerability
2021

@@ -46,7 +47,7 @@ In scope:
4647
- Any malformed `.vortex` input that causes the reader to throw an exception other than
4748
`io.github.dfa1.vortex.core.VortexException` (e.g. `IndexOutOfBoundsException`,
4849
`NegativeArraySizeException`, `OutOfMemoryError`, `StackOverflowError`, raw FlatBuffer
49-
runtime exceptions, raw Protobuf parser exceptions, or a JVM crash via the FFM layer).
50+
runtime exceptions, raw `IOException` from the proto3 reader, or a JVM crash via the FFM layer).
5051
- Any malformed `.vortex` input that causes the reader to allocate memory disproportionate
5152
to its on-disk size (zip-bomb-style amplification).
5253
- Any malformed `.vortex` input that causes silent data corruption — wrong row count,
@@ -58,9 +59,10 @@ Out of scope:
5859

5960
- Denial of service from legitimately large inputs (multi-gigabyte files). Use the
6061
resource caps in `ReadOptions` (planned) to bound them.
61-
- Vulnerabilities in third-party dependencies (`vortex-jni`, `zstd-jni`, FlatBuffers runtime,
62-
Protobuf runtime). Report those upstream; we'll bump the dependency once a fixed version
63-
is available.
62+
- Vulnerabilities in third-party dependencies (`vortex-jni`, `zstd-jni`, FlatBuffers runtime).
63+
Report those upstream; we'll bump the dependency once a fixed version is available.
64+
Vortex no longer depends on `protobuf-java` — proto3 parsing is handled by the in-tree
65+
`ProtoReader` (issues there are in scope).
6466
- Performance regressions or correctness bugs unrelated to malformed input — please open
6567
a regular issue.
6668

@@ -76,9 +78,12 @@ exception**. Concretely:
7678
self-referential FlatBuffer cycles).
7779
- Layout metadata is capped at 4 MiB.
7880
- `Decimal` precision is restricted to `[1, 38]`; `scale` to `[0, precision]`.
79-
- `PType` ordinals from Protobuf are bounds-checked.
81+
- `PType` ordinals from proto3 are bounds-checked.
8082
- `ConstantEncoding` and dict-layout decode allocate `O(1)` memory regardless of the
8183
declared row count (zip-bomb mitigation).
84+
- `ProtoReader` enforces varint length ≤ 10 bytes, rejects truncated len-delim regions,
85+
and validates segment bounds on every read. (0.6.0+ — replaces the `protobuf-java`
86+
parser path; same exception contract.)
8287

8388
The regression suite lives under `reader/src/test/java/.../*SecurityTest`. Run with
8489
`./mvnw test -Dtest='*SecurityTest'`.

0 commit comments

Comments
 (0)