Skip to content

Fix: CIccXform::Create overloads leak/double-free pProfile via bOwnsProfile (#1308)#1347

Merged
xsscx merged 1 commit into
InternationalColorConsortium:masterfrom
colourbill-ctrl:fix-1308-create-ownership-param
Jun 14, 2026
Merged

Fix: CIccXform::Create overloads leak/double-free pProfile via bOwnsProfile (#1308)#1347
xsscx merged 1 commit into
InternationalColorConsortium:masterfrom
colourbill-ctrl:fix-1308-create-ownership-param

Conversation

@colourbill-ctrl

Copy link
Copy Markdown
Contributor

Summary

Resolves #1308 (follow-up to #1304/#1305). CIccXform::Create takes ownership of pProfile only on success (SetParams hands it to the new xform). Two defects flowed from that:

  1. Leak (Leak: sibling CIccXform::Create / CIccXformMpe::Create overloads leak pProfile on failure paths (follow-up to #1304) #1308): the tag-based Create(CIccProfile*, CIccTag*, …) overload returned NULL on every failure path without freeing the owned profile — so AddXform(CIccProfile*, CIccTag*) leaked it (the call site even comments "CIccXform::Create has already deleted the profile", which was aspirational for this overload).
  2. Latent double-free: the no-tag overload (post-Fix: leak in CIccXform::Create on failure paths (#1304) #1305) freed pProfile unconditionally on failure. At the MCS-link path in Begin() it is called with a profile borrowed from a live xform, so a failed Create freed a profile that xform still owned → double-free/UAF.

Fix (Option B — ownership parameter)

Adds bool bOwnsProfile = true to the three pointer-based Create overloads (CIccXform no-tag, CIccXform tag, CIccXformMpe). Each failure path frees pProfile only when the caller owns it:

Also removes the now-redundant delete in the reference-based Create overload: the pointer Create it delegates to already owns and frees the copy on failure, so that extra delete had become a double-free after #1305.

Inline comments at each overload and call site document the ownership contract and when to pass false. Success paths are unchanged (ownership still transfers via SetParams, released by the borrowed callers' ShareProfile()). CIccXformMpe::Create currently has no callers; it is updated for family consistency so any future caller is leak-safe.

Verification (AddressSanitizer / LeakSanitizer, clang-18)

Notes

  • Library-only change (IccProfLib/), no fork-gate split needed.
  • The deterministic CTest regression is filed separately as an upstream PR (it touches .github/ + Build/Cmake). Merge this fix first; the test PR goes green once this lands.

🤖 Generated with Claude Code

…rofile (InternationalColorConsortium#1308)

Follow-up to InternationalColorConsortium#1304/InternationalColorConsortium#1305. CIccXform::Create owns pProfile only on success
(SetParams hands it to the new xform); the tag-based overload returned NULL
on its failure paths without freeing the owned profile, leaking it (InternationalColorConsortium#1308),
while the no-tag overload (post-InternationalColorConsortium#1305) freed it unconditionally -- which
double-freed a profile borrowed from a live xform at the MCS-link path.

Adds a bool bOwnsProfile=true parameter to the three pointer-based Create
overloads (CIccXform no-tag, CIccXform tag, CIccXformMpe). Every failure path
now frees pProfile only when the caller owns it, so:
  - owned callers (the default) get a leak-free Create on all failure paths
    (closes the InternationalColorConsortium#1308 tag-overload leak), and
  - the two borrowed callers -- CheckPCSConnections' HToS injection and Begin's
    MCS-link conversion -- pass bOwnsProfile=false, so a failed Create no longer
    deletes a profile still owned by a live xform.

Also removes the now-redundant delete in the reference-based Create overload:
the pointer Create it delegates to already owns and frees the copy on failure,
so the extra delete had become a double-free after InternationalColorConsortium#1305.

Inline comments at each overload and call site document the ownership contract
and when to pass bOwnsProfile=false. Success paths are unchanged (ownership is
still transferred via SetParams and released by the borrowed callers'
ShareProfile()).

Verified with AddressSanitizer/LeakSanitizer: the tag-overload AddXform path
leaks 608 B pre-fix and is clean post-fix; valid conversions and the
CheckPCSConnections/MCS-link chains run without leak, double-free, or UAF.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@xsscx xsscx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2026-06-14 19:01:25 UTC

@xsscx xsscx added this to the v2.3.2.2 milestone Jun 14, 2026
@xsscx xsscx added the Merge Ready Approved, mergeable, and all CI checks passed label Jun 14, 2026
colourbill-ctrl added a commit that referenced this pull request Jun 14, 2026
…1308/#1348)

The CI tool-test job and ICCDEV_TEST_ENV both export
ASAN_OPTIONS=...detect_leaks=0 to silence unrelated leaks in the smoke-tested
tools.  This LSan-based leak regression inherited that and therefore PASSED
even on pre-fix master where the profile leaks 608 bytes -- a false green that
defeats the test's purpose.

Launch the test through `cmake -E env ASAN_OPTIONS=detect_leaks=1` (the same
override mechanism the script tests use) so leak detection is forced back on
for this test's own process.  Set ONLY detect_leaks=1: appending
halt_on_error=0 makes the runtime print the leak but exit 0 (ctest would still
pass), and a ':' option separator is mis-parsed and silently disables the
check -- both verified.

Verified on a clean build: under the CI env (detect_leaks=0 exported) the test
now FAILS with the 608-byte leak on pre-fix master and PASSES with the #1347
fix applied.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@xsscx xsscx merged commit 06ac2d5 into InternationalColorConsortium:master Jun 14, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Merge Ready Approved, mergeable, and all CI checks passed Source C or C++ source code changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Leak: sibling CIccXform::Create / CIccXformMpe::Create overloads leak pProfile on failure paths (follow-up to #1304)

2 participants