Assertion failure in Perl_sv_vcatpvfn_flags (sv.c:13127) #16881
Comments
From @dur-randirCreated by @dur-randirWhile fuzzing perl v5.29.8-21-gde59f38ed9 built with afl and run printf q)%7000000000E)=> to cause an assertion failure perl: sv.c:13127: Perl_sv_vcatpvfn_flags: Assertion `elen >= width' failed. GDB stack trace is following: #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50 This is a regression between 5.26 and 5.28, bisect points to commit 5860c1e S_expect_number(): return STRLEN not I32 This static function is used by Perl_sv_vcatpvfn_flags() to read in Change it to return STRLEN, and to croak on the value being greater than Perl Info
|
From @tonycozOn Fri, 08 Mar 2019 15:36:30 -0800, randir wrote:
The bug causing this is this code: if (width) { since base is an int, the very large 7000000000 becomes a largish negative But fixing that reveals a different issue. The return type of v?snprintf() is int, so such a large result can't be reported So fail earlier than this by checking the expected width fits in an int. Tony |
From @tonycoz0001-perl-133913-limit-numeric-format-results-to-INT_MAX.patchFrom 24d96eaa52130354efe282f202083d6e8dd7549d Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Wed, 20 Mar 2019 16:47:49 +1100
Subject: (perl #133913) limit numeric format results to INT_MAX
The return value of v?snprintf() is int, and we pay attention to that
return value, so limit the expected size of numeric formats to
INT_MAX.
---
pod/perldiag.pod | 6 ++++++
sv.c | 7 +++++++
t/op/sprintf2.t | 7 +++++++
3 files changed, 20 insertions(+)
diff --git a/pod/perldiag.pod b/pod/perldiag.pod
index 8163dde583..125afe66b4 100644
--- a/pod/perldiag.pod
+++ b/pod/perldiag.pod
@@ -4346,6 +4346,12 @@ the meantime, try using scientific notation (e.g. "1e6" instead of
a number. This happens, for example with C<\o{}>, with no number between
the braces.
+=item Numeric format result too large
+
+(F) The length of the result of a numeric format supplied to sprintf()
+or printf() would have been too large for the underlying C function to
+report. This limit is typically 2GB.
+
=item Octal number > 037777777777 non-portable
(W portable) The octal number you specified is larger than 2**32-1
diff --git a/sv.c b/sv.c
index e9a46827d3..53dad06889 100644
--- a/sv.c
+++ b/sv.c
@@ -13080,6 +13080,13 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
if (float_need < width)
float_need = width;
+ if (float_need > INT_MAX) {
+ /* snprintf() returns an int, and we use that return value,
+ so die horribly if the expected size is too large for int
+ */
+ Perl_croak(aTHX_ "Numeric format result too large");
+ }
+
if (PL_efloatsize <= float_need) {
/* PL_efloatbuf should be at least 1 greater than
* float_need to allow a trailing \0 to be returned by
diff --git a/t/op/sprintf2.t b/t/op/sprintf2.t
index 3f4c126c68..eda4e67e99 100644
--- a/t/op/sprintf2.t
+++ b/t/op/sprintf2.t
@@ -1141,4 +1141,11 @@ foreach(
is sprintf("%.0f", $_), sprintf("%-.0f", $_), "special-case %.0f on $_";
}
+# large uvsize needed so the large width is parsed properly
+# large sizesize needed so the STRLEN check doesn't
+if ($Config{intsize} == 4 && $Config{uvsize} > 4 && $Config{sizesize} > 4) {
+ eval { my $x = sprintf("%7000000000E", 0) };
+ like($@, qr/^Numeric format result too large at /,
+ "croak for very large numeric format results");
+}
done_testing();
--
2.11.0
|
The RT System itself - Status changed from 'new' to 'open' |
From @iabynOn Tue, Mar 19, 2019 at 11:01:08PM -0700, Tony Cook via RT wrote:
Your suggested patch looks good to me. -- |
From @dur-randirCan this patch be applied now? |
From @tonycozOn Wed, 01 May 2019 05:55:57 -0700, davem wrote:
Applied in 027471c. Thanks for the report and the reminder. Tony |
@tonycoz - Status changed from 'open' to 'pending release' |
Migrated from rt.perl.org#133913 (status was 'pending release')
Searchable as RT133913$
The text was updated successfully, but these errors were encountered: