Skip to content

fix(psd): avoid signed overflow computing layer/mask extents#5306

Open
lgritz wants to merge 1 commit into
AcademySoftwareFoundation:mainfrom
lgritz:lg-psd-overflow
Open

fix(psd): avoid signed overflow computing layer/mask extents#5306
lgritz wants to merge 1 commit into
AcademySoftwareFoundation:mainfrom
lgritz:lg-psd-overflow

Conversation

@lgritz

@lgritz lgritz commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

read_layer_record computed a layer's width/height as std::abs((int)right - (int)left). The rectangle coordinates are signed 32-bit values (layers can have negative offsets), but were stored in unsigned (uint32_t) struct fields, and subtracting two ints near the extremes overflows -- undefined behavior that UBSan flagged on a fuzzed file (1615681375 - -1605526113 cannot be represented in type 'int').

Retype Layer's and MaskData's top/left/bottom/right fields as int32_t, matching what they actually hold, instead of reinterpreting bits at the point of use. Widen to int64_t before subtracting so the computation can't overflow; the absolute difference of two int32 values always fits in uint32, and validate_resolution still rejects implausibly large extents.

The mask data rect (used for layer masks) had the identical std::abs((int)right - (int)left) overflow hazard in load_layer_channel and gets the same fix.

Assisted-by: Claude Code / Sonnet 5

read_layer_record computed a layer's width/height as
std::abs((int)right - (int)left). The rectangle coordinates are signed
32-bit values (layers can have negative offsets), but were stored in
unsigned (uint32_t) struct fields, and subtracting two ints near the
extremes overflows -- undefined behavior that UBSan flagged on a fuzzed
file (1615681375 - -1605526113 cannot be represented in type 'int').

Retype Layer's and MaskData's top/left/bottom/right fields as int32_t,
matching what they actually hold, instead of reinterpreting bits at the
point of use. Widen to int64_t before subtracting so the computation
can't overflow; the absolute difference of two int32 values always fits
in uint32, and validate_resolution still rejects implausibly large
extents.

The mask data rect (used for layer masks) had the identical
std::abs((int)right - (int)left) overflow hazard in
load_layer_channel and gets the same fix.

Assisted-by: Claude Code / Sonnet 5

Signed-off-by: Larry Gritz <lg@larrygritz.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.

1 participant