Skip to content

[GPOS] Clamp anchor coordinates when converting them from float - #6587

Merged
behdad merged 1 commit into
harfbuzz:mainfrom
b84330808:gpos-clamp-float-anchors
Nov 8, 2026
Merged

behdad merged 1 commit into
harfbuzz:mainfrom
b84330808:gpos-clamp-float-anchors

Conversation

@b84330808

Copy link
Copy Markdown
Contributor

Anchor coordinates are scaled as float, and the cursive and mark attachment code converted them to hb_position_t with a plain cast or an implicit conversion. A value out of the target type's range makes that conversion undefined; on x86 it produces INT32_MIN. #6154 made the additions around these conversions saturate, but not the conversions themselves.

With NotoNastaliqUrdu-Regular.ttf at a scale of INT32_MAX, a cursive anchor scales to 2.23e9 and the glyph ends up with an x_advance of -2147483648.

This converts with hb_clamp_to(), and negates the cursive cross-direction offsets with hb_saturate_neg(), since they can now be INT32_MIN. Results that fit in range do not change.

Testing (Linux; the branch is already on top of current main):

  • The new test_shape_cursive_anchor_overflow in test/api/test-shape.c: with the src changes reverted and the test kept, it fails with "assertion failed (pos[i].x_advance >= 0): (-2147483648 >= 0)"; with the fix it passes.
  • Full meson test -C build: 270 ok, 0 fail, 7 skipped (subset+repack, the same skips as unrelated runs on main).

Not covered: no test reaches the two conversions in MarkArray.hh (mark.x_offset, mark.y_offset); they are changed to match the cursive ones, as the commit message also notes.

AI disclosure: this change was prepared with AI assistance, as the commit's Assisted-by trailer says. I have read the full diff and run the tests above myself before submitting.

Anchor coordinates are scaled as float, and apply_cursive_attachment()
and the mark attachment code converted them to hb_position_t with a
plain cast or an implicit conversion. A value out of range for the
target type makes that conversion undefined; on x86 it gives INT32_MIN.
harfbuzz#6154 made the additions around these conversions saturate, but not
the conversions themselves.

With NotoNastaliqUrdu-Regular.ttf at a scale of INT32_MAX, a cursive
anchor scales to 2.23e9, and the glyph ended up with an x_advance of
-2147483648.

Convert with hb_clamp_to(), and negate the cursive cross-direction
offsets with hb_saturate_neg(), since they can now be INT32_MIN.
Results that fit do not change.

Tested with test-shape under UBSan: the new test fails on the base
commit at CursivePosFormat1.hh:141 and passes here. No test reaches
the two conversions in MarkArray.hh; they are changed to match.

Assisted-by: Claude
@b84330808
b84330808 requested a review from a team November 5, 2026 17:42
@behdad
behdad merged commit d1520e8 into harfbuzz:main Nov 8, 2026
27 checks passed
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