summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYves Orton <demerphq@gmail.com>2022-03-03 15:24:03 +0100
committerYves Orton <demerphq@gmail.com>2022-03-07 16:22:12 +0100
commit8b03aeb95ab72abdb2fa40f2d1196ce42f34708d (patch)
tree5ec32d32dc62e922697511b5404d9440d7ea006e
parent7ea8b04b5a0e6952b7ffd5a8fd96468b72da6bea (diff)
downloadperl-8b03aeb95ab72abdb2fa40f2d1196ce42f34708d.tar.gz
Fix GH Issue #19472: read warnings from open($fh,">",\(my $x))
We produce all kinds of warnings if someone opens a scalar reference that is undef. Prior to this we handled write operations ok, at least in blead, but read operations would produce a plethora of warnings. To me this analogous to treating an undef var as hash and trying to read from it, we autovivify the undef var to be a hash. So in this case we should just "autovivify" the referenced scalar to be an empty string. Eg. before this patch: ./perl -Ilib -wle'open my $fh,"+>", \(my $v); my @x=<$fh>; print 0+@x' Use of uninitialized value $fh in <HANDLE> at -e line 1. Use of uninitialized value $fh in <HANDLE> at -e line 1. Use of uninitialized value $fh in <HANDLE> at -e line 1. Use of uninitialized value $fh in <HANDLE> at -e line 1. Use of uninitialized value $fh in <HANDLE> at -e line 1. Use of uninitialized value $fh in <HANDLE> at -e line 1. Use of uninitialized value $fh in <HANDLE> at -e line 1. 0 After it: ./perl -Ilib -wle'open my $fh,"+>", \(my $v); my @x=<$fh>; print 0+@x' 0
-rw-r--r--doio.c10
-rw-r--r--pod/perlfunc.pod12
-rw-r--r--t/io/open.t24
3 files changed, 43 insertions, 3 deletions
diff --git a/doio.c b/doio.c
index 87790da137..4009545ffc 100644
--- a/doio.c
+++ b/doio.c
@@ -639,6 +639,16 @@ Perl_do_open6(pTHX_ GV *gv, const char *oname, STRLEN len,
goto say_false;
}
#endif /* USE_STDIO */
+ if (SvROK(*svp) && !sv_isobject(*svp)) {
+ /* if they pass in a reference and its not an object
+ * and the reference is to undef, "autovivify" it to
+ * the empty string. See GH Issue #19472
+ */
+ SV *sv= SvRV(*svp);
+ if (!SvOK(sv) && !SvREADONLY(sv))
+ sv_setpvs(MUTABLE_SV(sv),"");
+ }
+
p = (SvOK(*svp) || SvGMAGICAL(*svp)) ? SvPV(*svp, nlen) : NULL;
if (p && !IS_SAFE_PATHNAME(p, nlen, "open")) {
diff --git a/pod/perlfunc.pod b/pod/perlfunc.pod
index 26d59a580e..1950e95cd0 100644
--- a/pod/perlfunc.pod
+++ b/pod/perlfunc.pod
@@ -4657,8 +4657,8 @@ L<C<seek>|/seek FILEHANDLE,POSITION,WHENCE> to do the reading.
=item Opening a filehandle into an in-memory scalar
You can open filehandles directly to Perl scalars instead of a file or
-other resource external to the program. To do so, provide a reference to
-that scalar as the third argument to C<open>, like so:
+other resource external to the program. To do so, provide an unblessed
+reference to that scalar as the third argument to C<open>, like so:
open(my $memory, ">", \$var)
or die "Can't open memory file: $!";
@@ -4674,6 +4674,14 @@ The scalars for in-memory files are treated as octet strings: unless
the file is being opened with truncation the scalar may not contain
any code points over 0xFF.
+Be aware that attempting to open a reference to a readonly scalar will
+cause a warning and the open to fail.
+
+Prior to Perl version 5.36.0, passing in a reference to an undef scalar
+could cause strange warnings. As of Perl version 5.36.0, provided the
+reference is unblessed, the scalar will be "autovivified" to be an empty
+string, even for read mode open operations.
+
Opening in-memory files I<can> fail for a variety of reasons. As with
any other C<open>, check the return value for success.
diff --git a/t/io/open.t b/t/io/open.t
index 7fa492342d..86ca8a8498 100644
--- a/t/io/open.t
+++ b/t/io/open.t
@@ -10,7 +10,7 @@ $| = 1;
use warnings;
use Config;
-plan tests => 188;
+plan tests => 193;
sub ok_cloexec {
SKIP: {
@@ -410,6 +410,28 @@ SKIP: {
or unlink \*STDOUT;
}
+# [GH Issue #19472] Opening a reference to an undef scalar
+SKIP: {
+ skip_if_miniperl("no dynamic loading on miniperl, so can't load PerlIO::scalar", 5);
+ use strict;
+ my $var;
+ open my $fh, "+>", \$var;
+ is defined($var) ? "defined" : "undef", "defined",
+ '[GH Issue #19472]: open $fh, ">", \$undef_var leaves var defined';
+ is $var, "",
+ '[GH Issue #19472]: open $fh, ">", \$undef_var leaves var empty string';
+ my $warn_count= 0;
+ my $warn_text= "";
+ local $SIG{__WARN__}= sub { $warn_count++; $warn_text .= shift; };
+ my @x= <$fh>;
+ is $warn_count, 0, '[GH Issue #19472]: read after open $fh, ">", ' .
+ '\$undef_var produces 0 warnings';
+ is $warn_text, "", '[GH Issue #19472]: read after open $fh, ">", ' .
+ '\$undef_var produces no warning text';
+ is 0+@x, 0, '[GH Issue #19472]: <$fh> after open $fh, ">", ' .
+ '\$undef_var returns nothing';
+}
+
# check that we can call methods on filehandles auto-magically
# and have IO::File loaded for us
SKIP: {