Skip to content

Avoid referencing uninitialized memory in PerlIOScalar_write#24063

Merged
tonycoz merged 1 commit intoPerl:bleadfrom
t-a-k:fix-gh24008
Feb 1, 2026
Merged

Avoid referencing uninitialized memory in PerlIOScalar_write#24063
tonycoz merged 1 commit intoPerl:bleadfrom
t-a-k:fix-gh24008

Conversation

@t-a-k
Copy link
Copy Markdown
Contributor

@t-a-k t-a-k commented Jan 7, 2026

PerlIOScalar_write used to blindly use SvCUR() for SVs that is not SvPOK nor SvPOKp and bypasses the code that world normally clear out the leading bytes. This would result as garbage (uninitialized) bytes when the target scalar once held a non-empty string and then undef'ed.

This will fix #24008.


  • This set of changes requires a perldelta entry, and it is included.

Comment thread t/io/scalar.t Outdated
}

{ # GH #24008
open my $fh, '>', \my $str or BAIL_OUT $!;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm surprised to see that this suggests using BAIL_OUT. According to perldoc Test::More, BAIL_OUT

        Indicates to the harness that things are going so badly all testing
        should terminate. This includes the running of any additional test
        scripts.

        This is typically used when testing cannot continue such as a
        critical module failing to compile or a necessary external utility
        not being available such as a database connection failing.

        The test will exit with 255.

Why wouldn't a simple die suffice here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Agreed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@t-a-k I think we are waiting for changing to die, and then this p.r. can be merged

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.

Sorry for delayed response. I will make a commit shortly.

I think that BAIL_OUT is provided because die would change the behavior due to some internal state, such as $SIG{__DIE__}, $! and enclosing eval, so it might not be able to make the test fail reliably.

Comment thread perlio.c Outdated
@t-a-k
Copy link
Copy Markdown
Contributor Author

t-a-k commented Jan 17, 2026

I've pushed a commit to change BAIL_OUT to die, and another commit to change the way to avoid calling SvCUR on undef'ed scalar. I thought that this approach is simpler than previous one.

If these are OK, I will squash them to a single commit.

Comment thread perlio.c
if ((PerlIOBase(f)->flags) & PERLIO_F_APPEND) {
dst = SvGROW(sv, SvCUR(sv) + count + 1);
dst = SvGROW(sv, cur + count + 1);
offset = SvCUR(sv);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could this now be offset = cur; ?

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.

Could this now be offset = cur; ?

I think this has its pros and cons. Referencing cur after SvGROW will make this variable live across the function call, which will impose more register pressure and might worsen performance. (I assume that SvCUR is always valid after SvGROW, and re-fetching SvCUR is not so complex operation.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You could move the assignment before the SvGROW() to avoid that.

Though I doubt the extra memory access of the extra SvCUR() will make any measurable difference.

Copy link
Copy Markdown
Contributor Author

@t-a-k t-a-k Jan 19, 2026

Choose a reason for hiding this comment

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

You could move the assignment before the SvGROW() to avoid that.

There will be trade-offs here; doing so will extend the lifetime of offset instead.

Anyway, I think that it would be better to keep the changes minimal to fix the issue (#24008) and other improvements like this should be a separate PR.
In this case, I also think the code around here could be simplified so that I'm going to create another PR later.

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 assume that SvCUR is always valid after SvGROW,

This was my misunderstanding. SvGROW actually will not touch SvCUR so SvCUR might be invalid even after SvGROW. I'll submit another PR to fix this.

Comment thread pod/perldelta.pod Outdated
@t-a-k
Copy link
Copy Markdown
Contributor Author

t-a-k commented Jan 31, 2026

Thank you @mauke, I will further squash my commits.

@t-a-k t-a-k closed this Jan 31, 2026
@t-a-k
Copy link
Copy Markdown
Contributor Author

t-a-k commented Jan 31, 2026

Sorry, I closed by mistake.

@t-a-k t-a-k reopened this Jan 31, 2026
Once a scalar variable is undef'ed, its SvCUR might remain the previous
value.  Using SvCUR() blindly might bypass the code that world normally
clear out the leading bytes and result as garbage (uninitialized) bytes
when the target scalar once held a non-empty string and then undef'ed.
So only call SvCUR() when the SV is defined.

t/io/scalar.t: added a test for this.
Thanks to the comment from @jkeenan for improving the test.
@tonycoz tonycoz merged commit 1047968 into Perl:blead Feb 1, 2026
33 checks passed
@t-a-k t-a-k deleted the fix-gh24008 branch February 3, 2026 17:09
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.

Uninitialised memory use when Dumping undef'd string

7 participants