Skip to content

Validate update control ranges in ApplyChanges - #29

Merged
philliphoff merged 1 commit into
mainfrom
claude/relaxed-chandrasekhar-4165a9
Oct 11, 2026
Merged

philliphoff merged 1 commit into
mainfrom
claude/relaxed-chandrasekhar-4165a9

Conversation

@philliphoff

Copy link
Copy Markdown
Owner

Summary

S57Document.ApplyChanges passed the FSPC, FFPC, VRPC and SGCC index and count straight to ImmutableArray.RemoveRange and InsertRange. An update whose range fell outside the base record's array (a malformed .00N, or one that doesn't match the base cell) threw ArgumentOutOfRangeException from System.Collections.Immutable, with nothing to identify the record or field. Found with a synthetic update generator: an SGCC modify longer than the base edge's coordinate list crashed ApplyChanges.

The splice helpers now check the range and throw InvalidDataException, for example:

Update control field SGCC on record RCNM=130, RCID=1 (Modify at index 2, count 5) is outside the base record's 3 entries (S-57 Part 3, 8.4.3). The update does not match the base cell.

  • Insert: index 1 to length + 1 (length + 1 appends).
  • Delete and modify: the whole range must lie inside the array.
  • Still skipped without a check: an array the update leaves untouched (no update data, or a delete on an empty array). SGCC controls both SG2D and SG3D, so every SGCC update also reaches a record's empty array, and checking it would reject valid updates.

Why throw rather than log and skip: S57DocumentReader logs and continues because a field it can't parse is just lost data. A skipped splice would instead return a record with silently wrong geometry. ApplyChanges also has no logger, so throwing is the smaller change. The behaviour is documented in an <exception> tag and a remarks paragraph on ApplyChanges.

Standards alignment

  • ISO/IEC 8211 (iso8211)
  • S-57 records, topology, updates or exchange sets (s57-enc)
  • Legacy chart viewer, maintenance only (chart-viewer)
  • N/A: build, CI, docs or tooling only

Standard section references cited in code or docs: S-57 Part 3, 8.4.3 (update control fields).

Tests

  • Added or updated xUnit tests under tests/
  • Test input is built in memory; no real ENC cells are committed
  • dotnet test --configuration Release passes locally

New tests in S57DocumentApplyChangesTests.cs: out-of-range SGCC modify, FSPC delete, FFPC insert, VRPC index 0, plus two boundary cases that must still work (a modify covering the last entry, an insert that appends).

On the unchecked box: the machine I ran on couldn't reach nuget.org, so package validation couldn't restore the 0.7.2 baseline. All 498 tests pass with dotnet test --configuration Release -p:EnablePackageValidation=false. CI runs the full command.

Documentation

  • Updated the affected package's src/<project>/README.md
  • Updated guides under docs/ if user-facing behavior changed
  • New public APIs have XML doc comments
  • docfx docfx.json --warningsAsErrors passes, if docs changed

No new public API. The existing ApplyChanges XML docs gain the exception and range rules. The README and guides don't cover ApplyChanges errors, so they're unchanged.

Dependencies

  • No new NuGet dependencies, OR versions added to Directory.Packages.props (not in the .csproj)
  • gh-advisory-database security check run for any new dependency

Breaking changes

No binary change; only private helpers changed. Behavioural change: for an out-of-range update control, ApplyChanges now throws InvalidDataException instead of ArgumentOutOfRangeException. EncDotNet.S100 code that catches ArgumentOutOfRangeException around ApplyChanges (in EncDotNet.S100.Datasets.S57) would need to catch InvalidDataException instead. Valid updates behave as before.

An FSPC, FFPC, VRPC or SGCC index or count outside the base record's
array made ApplyChanges throw ArgumentOutOfRangeException from
System.Collections.Immutable, with nothing to identify the record or
field. The splice helpers now check the range (S-57 Part 3, 8.4.3) and
throw InvalidDataException naming the control field and the record's
RCNM/RCID.

Throwing rather than logging and skipping: a skipped splice would return
a record with silently wrong geometry, and ApplyChanges has no logger.
Arrays the update leaves untouched (no update data, or a delete on an
empty array) are still skipped without a check, because SGCC controls
both SG2D and SG3D.
@philliphoff
philliphoff merged commit 5b6950d into main Oct 11, 2026
11 checks passed
@philliphoff
philliphoff deleted the claude/relaxed-chandrasekhar-4165a9 branch October 11, 2026 18:24
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.

1 participant