Skip to content

unstable: fix subsliceOffset regression for non-suffix subslices#1055

Closed
alliasgher wants to merge 3 commits intopelletier:v2from
alliasgher:fix-subslice-offset-regression
Closed

unstable: fix subsliceOffset regression for non-suffix subslices#1055
alliasgher wants to merge 3 commits intopelletier:v2from
alliasgher:fix-subslice-offset-regression

Conversation

@alliasgher
Copy link
Copy Markdown

Fixes #1047.

subsliceOffset computed byte offsets by subtracting the slice length from len(p.data). This only works for tail (suffix) slices. Sub-slices taken from the middle — e.g. b[0:1] in parseSimpleKey's error path — return a wrong offset.

This was exposed by #1041 (which correctly fixed a different bug): after that change the parseSimpleKey error highlight is still b[0:1], a non-suffix slice, so the offset computation gives len(p.data) - 1 instead of the actual character position.

Fix: use pointer arithmetic (unsafe.Pointer) to compute the actual offset of any subslice relative to p.data. An empty-slice fallback preserves the existing behaviour for nil inputs.

Includes TestRangeOffsetAfterComment from #1047.

isEmptyStruct returns true whenever a struct has no exported fields,
even if that struct holds a meaningful value. This caused types like
netip.Addr — which have no exported fields but implement IsZero() and
encoding.TextMarshaler — to be unconditionally omitted when tagged
with `omitempty`.

Fix shouldOmitEmpty by preferring the IsZero() method over the
field-scanning fallback, mirroring the logic already used in
shouldOmitZero. Additionally, for structs that implement TextMarshaler
without an IsZero() method, fall back to reflect.Value.IsZero() instead
of the field-based scan.

Fixes pelletier#955

Signed-off-by: alliasgher <alliasgher123@gmail.com>
The subsliceOffset helper computed byte offsets by subtracting the
length of the slice from the total data length. This only works for
tail (suffix) slices; any sub-slice taken from the middle — such as
b[0:1] in parseSimpleKey's error path — returns an incorrect offset.

This was exposed by pelletier#1041, which correctly fixed a different error
position bug, but the existing formula is fundamentally wrong for
non-suffix slices.

Fix: use pointer arithmetic (via unsafe.Pointer) to compute the actual
offset of any subslice relative to p.data, regardless of its length.
An empty-slice fallback preserves the existing behaviour for the nil
case.

Fixes pelletier#1047

Signed-off-by: alliasgher <alliasgher123@gmail.com>
Comment thread unstable/parser.go Outdated
Use cap(p.data)-cap(b) to compute the byte offset of a subslice
within the parser's data without importing unsafe. This works because
cap reports the distance from the slice start to the end of its
backing array, so the difference between two subslices of the same
array is their offset delta.

Also fix errorlint: use errors.As instead of type assertion.

Signed-off-by: Ali <alliasgher123@gmail.com>
@alliasgher alliasgher requested a review from pelletier April 16, 2026 12:19
@pelletier
Copy link
Copy Markdown
Owner

Merged c171216 to solve this with more testing. I think there is a deeper fix to be made but good enough to fix the symptoms for users.

@pelletier pelletier closed this Apr 16, 2026
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.

v2.3.0 regression with "invalid character at start of key" error positions

2 participants