locale: stringify strftime fmt before querying length/utf8ness

POSIX::strftime() can call sv_strftime_common() with arbitrary SVs.
SvCUR() assumes it is being called on an actual string. With other SV
types it can return garbage or just crash.

Make sure SvPV() is called first to stringify the format, before
SvUTF8() and SvCUR() inspect the SV.

Fixes #22498.
This commit is contained in:
Lukas Mai 2024-08-11 08:25:03 +02:00 committed by mauke
parent 70f3e00650
commit 3e14b2fcf5
2 changed files with 17 additions and 3 deletions

View File

@ -9,7 +9,7 @@ use strict;
use Config;
use POSIX;
use Test::More tests => 27;
use Test::More tests => 31;
# For the first go to UTC to avoid DST issues around the world when testing. SUS3 says that
# null should get you UTC, but some environments want the explicit names.
@ -215,3 +215,14 @@ SKIP: {
ok(abs(POSIX::strftime('%s', localtime) - time) < 60,
'GH #22351; pr: GH #22369');
}
{
# GH #22498
is(strftime(42, CORE::localtime), '42', "strftime() works if format is a number");
my $obj = bless {}, 'Some::Random::Class';
is(strftime($obj, CORE::localtime), "$obj", "strftime() works if format is an object");
my $warnings = '';
local $SIG{__WARN__} = sub { $warnings .= $_[0] };
is(strftime(undef, CORE::localtime), '', "strftime() works if format is undef");
like($warnings, qr/^Use of uninitialized value in subroutine entry /, "strftime(undef, ...) produces expected warning");
}

View File

@ -8218,6 +8218,9 @@ S_sv_strftime_common(pTHX_ SV * fmt,
{ /* Documented above */
PERL_ARGS_ASSERT_SV_STRFTIME_COMMON;
STRLEN fmt_cur;
const char *fmt_str = SvPV_const(fmt, fmt_cur);
utf8ness_t fmt_utf8ness = (SvUTF8(fmt) && LIKELY(! IN_BYTES))
? UTF8NESS_YES
: UTF8NESS_UNKNOWN;
@ -8228,8 +8231,8 @@ S_sv_strftime_common(pTHX_ SV * fmt,
* to get almost all the typical returns to fit without the called function
* having to realloc; this is a somewhat educated guess, but feel free to
* tweak it. */
SV* sv = newSV(MAX(SvCUR(fmt) * 2, 64));
if (! strftime8(SvPV_nolen(fmt),
SV* sv = newSV(MAX(fmt_cur * 2, 64));
if (! strftime8(fmt_str,
sv,
locale,
mytm,