Skip to content

Preserve empty Access values and harden timestamp parsing#9

Merged
dominion525 merged 2 commits into
dominion525:mainfrom
Else00:fix-jet4-offset-underflow
Jun 20, 2026
Merged

Preserve empty Access values and harden timestamp parsing#9
dominion525 merged 2 commits into
dominion525:mainfrom
Else00:fix-jet4-offset-underflow

Conversation

@Else00

@Else00 Else00 commented Jun 6, 2026

Copy link
Copy Markdown

Summary

This fixes a few correctness edge cases in Jet/ACE row decoding:

  • avoid underflow while scanning truncated Jet4/ACE variable-offset tables
  • preserve non-null empty variable values instead of converting them to Value::Null
  • reject malformed DateTimeExtended payloads instead of parsing them as zero/epoch-like dates
  • normalize rounded timestamps that carry past 23:59:59 to the next day at 00:00:00

Details

For variable-length values, start == end is a valid non-null empty value. The decoder now treats only start > end or out-of-bounds offsets as invalid.

For DateTimeExtended, the parser now validates the expected 42-byte layout, separators, marker bytes, ASCII digits, and ranges before returning a parsed value. Malformed payloads are preserved as raw binary by the existing caller behavior.

Timestamp formatting now handles rounding to 86400 seconds by carrying to the next day.

Note

I am using jetdb in a personal desktop application that needs to read Microsoft Access databases, and it has been genuinely useful for that use case. It is a pity that the project is not more widely known, because a pure Rust Access reader fills a very practical gap.

Relation to #8

This partially overlaps with #8 in crack_row_jet4. That PR prevents the debug overflow panic by keeping wrapping_sub and making the bounds check panic-safe with checked_add. This PR instead avoids the wrap at the subtraction step with checked_sub, and keeps the same intended behavior of stopping the offset-table scan when the declared variable-column count extends before the row start.

Tests

  • scripts/quality-check.sh
    • tests: pass
    • clippy: pass
    • audit: pass
    • docs: pass
    • coverage: pass, 94.37% lines
    • complexity gate: pass

senpai added 2 commits June 6, 2026 13:49
Truncated or inconsistent Jet4 variable-column offset tables can ask the reader to step backwards past the start of the row. Using wrapping subtraction turns that into a huge index, so stop scanning when the next offset entry would underflow.

Tested: cargo test -p jetdb
Access rows can distinguish a non-null empty Text/Binary value from NULL via the null mask. The parser also accepted malformed DateTimeExtended payloads by parsing failures as zero, and rounded ordinary timestamps could produce 24:00:00 instead of carrying into the next day.

Constraint: Keep the public Value API unchanged for an upstream-friendly focused fix

Rejected: Add a new invalid/raw cell variant in this patch | broader public API change best handled as a separate diagnostics design

Confidence: high

Scope-risk: narrow

Tested: cargo test -p jetdb

Tested: scripts/quality-check.sh
@Else00

Else00 commented Jun 10, 2026

Copy link
Copy Markdown
Author

@dominion525 ping

@dominion525

Copy link
Copy Markdown
Owner

Hi @Else00 — sorry for the long delay, and for not responding to the ping sooner.

Reviewed everything and all four fixes are genuine correctness improvements:

  • the checked_sub/saturating_sub rewrite in crack_row_jet4 is the cleaner approach of the two between this and Fix crack_row_jet4 overflow panic when var-offset table wraps #8 (no wrapped value ever ends up in pos)
  • start == end preserving non-null empty values is an actual data-correctness bug I had not noticed — thank you for catching it
  • the parse_ext_datetime hardening (length-equals-42, separator/marker/digit validation, range check, parse_zero_padded_i64) is a clear improvement over the previous unwrap_or(0) behavior
  • the timestamp_to_parts carry on >= 86400 is the right fix for the rounding boundary

Merging this now. After it lands I'll cherry-pick the regression test from #8 on top of main (Bradyok's var_col_count=100 reproducer — independently useful even though this PR's checked_sub supersedes #8's fix itself), and close #8 with a note.

Re: your note in the PR description — really glad to hear someone is actually using jetdb in a real application. Thank you for the patch and for the patience.

@dominion525 dominion525 merged commit 4e2c68b into dominion525:main Jun 20, 2026
7 checks passed
dominion525 pushed a commit that referenced this pull request Jun 20, 2026
Cherry-picked the regression test from #8. The underlying overflow itself was addressed in #9 via a different approach (checked_sub), but this var_col_count=100 / 7-byte reproducer is independently useful for guarding against future regressions.

(cherry picked from commit 2d924b5)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants