Skip to content

Fix GH-17399: iconv memory leak with large line-length#21541

Open
iliaal wants to merge 4 commits intophp:PHP-8.4from
iliaal:fix/gh-17399-iconv-leak
Open

Fix GH-17399: iconv memory leak with large line-length#21541
iliaal wants to merge 4 commits intophp:PHP-8.4from
iliaal:fix/gh-17399-iconv-leak

Conversation

@iliaal
Copy link
Copy Markdown
Contributor

@iliaal iliaal commented Mar 26, 2026

Summary

_php_iconv_mime_encode() opens two iconv_t handles via system malloc, then calls safe_emalloc(1, max_line_len, 5). When max_line_len is PHP_INT_MAX, the allocation triggers an OOM bailout that skips iconv_close() cleanup, leaking both handles.

Fix: move safe_emalloc before both iconv_open() calls so a bailout happens before any handles exist.

Additionally, four iconv functions (php_iconv_string, _php_iconv_substr, _php_iconv_mime_encode, _php_iconv_mime_decode) have the same class of leak: smart_str or zend_string operations between iconv_open() and iconv_close() can trigger OOM bailouts that skip cleanup. These are now wrapped with zend_try/zend_catch to close iconv handles before re-throwing.

@cmb69 suggested the reordering approach in the issue thread.

Fixes #17399

Copy link
Copy Markdown
Member

@Girgias Girgias left a comment

Choose a reason for hiding this comment

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

As this is a bugfix this wouldn't require RM approval. :)

@iliaal iliaal force-pushed the fix/gh-17399-iconv-leak branch from a9eeac2 to 9604e4d Compare March 26, 2026 19:52
@iliaal iliaal changed the base branch from master to PHP-8.4 March 26, 2026 19:52
@iliaal
Copy link
Copy Markdown
Contributor Author

iliaal commented Mar 26, 2026

As this is a bugfix this wouldn't require RM approval. :)

@Girgias Updated to be against 8.4, once tests pass, could you please merge, I still don't have access to merge myself 😢

@ndossche
Copy link
Copy Markdown
Member

This doesn't fix the real issue as I noted in the issue report. This just fixes one particular case of it.

@iliaal
Copy link
Copy Markdown
Contributor Author

iliaal commented Mar 26, 2026

This doesn't fix the real issue as I noted in the issue report. This just fixes one particular case of it.

One issue at a time, there is no universal fix to allocations on interruption, best is to identify the underlying issues and resolve them one by one. Not sure holding a fix to a specific issue because not all issues can be fixed, makes sense. But that's just my opinion... I'll see if I can do handler for other cases @ least inside iconv() though.

@iliaal iliaal force-pushed the fix/gh-17399-iconv-leak branch from 9604e4d to 8f71d79 Compare March 26, 2026 21:59
Move the buf allocation in _php_iconv_mime_encode() before the
iconv_open() calls so an OOM bailout from safe_emalloc does not
leak iconv handles.

Additionally, wrap bailable sections in php_iconv_string(),
_php_iconv_substr(), _php_iconv_mime_encode(), and
_php_iconv_mime_decode() with zend_try/zend_catch to ensure
iconv handles allocated via system malloc are closed if a Zend
OOM bailout fires during smart_str or zend_string operations.

Closes phpGH-17399
@iliaal iliaal force-pushed the fix/gh-17399-iconv-leak branch from 8f71d79 to 4afdcf5 Compare March 26, 2026 22:05
@iliaal
Copy link
Copy Markdown
Contributor Author

iliaal commented Mar 26, 2026

@ndossche I updated the PR using zend_try {} blocks around critical areas, which addresses a few more memory leaks inside the iconv() extension. Additional tests that replicate those leaks were also added...

Copy link
Copy Markdown
Member

@iluuu1994 iluuu1994 left a comment

Choose a reason for hiding this comment

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

Luckily, the indentation applies cleanly to higher branches. LGTM otherwise.

char_cnt = max_line_len;

zend_try {

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.

Please avoid this newline.

}

smart_str_0(pretval);

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.

Same here. That's what the majority of the uses of zend_try/catch do.

iliaal added 2 commits March 27, 2026 11:19
Use a bool flag in zend_catch and let the existing out: cleanup path
handle resource freeing, then conditionally call zend_bailout() after.
Also fix test to use short array syntax and remove stray blank line.
…ialized

The bailout variable was declared after goto targets, so paths jumping
to out: via goto could reach the if (bailout) check without the
variable being initialized.
@iliaal
Copy link
Copy Markdown
Contributor Author

iliaal commented Mar 27, 2026

@iluuu1994 I think I got all the CS recommendation covered 🤞

@iliaal iliaal requested a review from iluuu1994 March 27, 2026 16:51
goto out;
}

buf = safe_emalloc(1, max_line_len, 5);
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.

This should be moved back (and into the zend_try).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done


smart_str_0(pretval);

} zend_catch {
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.

The newline above should be removed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

{
php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
iconv_t cd = (iconv_t)(-1), cd_pl = (iconv_t)(-1);
bool bailout = false;
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.

I'd prefer to place this directly above zend_try.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I left that one out, it triggered -Wsometimes-uninitialized on clang before, so while it could be moved a bit lower, this seem ok to me.

@iliaal iliaal requested a review from iluuu1994 March 27, 2026 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

iconv memory leak

4 participants