From 3e14b2fcf59b5b88b289caa973f0b8748c93a594 Mon Sep 17 00:00:00 2001 From: Lukas Mai Date: Sun, 11 Aug 2024 08:25:03 +0200 Subject: [PATCH] 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. --- ext/POSIX/t/time.t | 13 ++++++++++++- locale.c | 7 +++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/ext/POSIX/t/time.t b/ext/POSIX/t/time.t index ec5e9b42cf..0d52ac5b24 100644 --- a/ext/POSIX/t/time.t +++ b/ext/POSIX/t/time.t @@ -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"); +} diff --git a/locale.c b/locale.c index 15eae3a444..98bccfdb95 100644 --- a/locale.c +++ b/locale.c @@ -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,