Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.97k stars 560 forks source link

tr/// or s/// on reference stringifies without warning #2608

Closed p5pRT closed 20 years ago

p5pRT commented 24 years ago

Migrated from rt.perl.org#4282 (status was 'resolved')

Searchable as RT4282$

p5pRT commented 24 years ago

From epa98@doc.ic.ac.uk

Created by epa98@doc.ic.ac.uk

If you accidentally use something like tr/\d// on a reference\, the variable becomes stringified without any warning. Later on if you try to use it as a reference\, the error message produced is confusing.

#!/usr/bin/perl -w use IO​::File; use strict; use diagnostics; my $t = IO​::File->new_tmpfile(); if ($t =~ tr/\d//) {   print "string $t contains digits\n"; } $t->close();

A better error message would warn that the variable had been stringified earlier on and had lost its reference-ness. Alternatively you could give a warning when the stringification happens\, or even a fatal error. (Nobody would really want to use tr/// on a reference\, it must be a mistake.)

I reported this to comp.lang.perl.moderated and Yitzchak Scott-Thoennes \sthoenna@​efn\.org suggested a fix​:

s/// is broken\, too.

Here's one way to fix tr///​:

Inline Patch ```diff --- doop.c.orig Fri Sep 1 14:09:46 2000 +++ doop.c Sat Sep 9 22:37:38 2000 @@ -438,7 +438,7 @@ I32 hasutf = (PL_op->op_private & (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF)); - if (SvREADONLY(sv) && !(PL_op->op_private & OPpTRANS_IDENTICAL)) + if ((SvREADONLY(sv) || SvROK(sv)) && !(PL_op->op_private & OPpTRANS_IDENTICAL)) Perl_croak(aTHX_ PL_no_modify); (void)SvPV(sv, len); ```

End of Patch.

but that would prevent doing anything useful with an overloaded object (but that should be ok since it is broken as it is now). And the error message may need to be more specific.

Are there any cases where a non-readonly non-reference would have get magic but not set magic? If so\, these would be broken too.

I also noticed that $x =~ tr/x// is calling get magic twice.

Perl Info ``` Site configuration information for perl 5.00503: Configured by root at Wed Feb 2 15:34:50 EST 2000. Summary of my perl5 (5.0 patchlevel 5 subversion 3) configuration: Platform: osname=linux, osvers=2.2.5-22smp, archname=i386-linux uname='linux porky.devel.redhat.com 2.2.5-22smp #1 smp wed jun 2 09:11:51 edt 1999 i686 unknown ' hint=recommended, useposix=true, d_sigaction=define usethreads=undef useperlio=undef d_sfio=undef Compiler: cc='cc', optimize='-O2 -m486 -fno-strength-reduce', gccversion=egcs-2.91.66 19990314/Linux (egcs-1.1.2 release) cppflags='-Dbool=char -DHAS_BOOL -I/usr/local/include' ccflags ='-Dbool=char -DHAS_BOOL -I/usr/local/include' stdchar='char', d_stdstdio=undef, usevfork=false intsize=4, longsize=4, ptrsize=4, doublesize=8 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12 alignbytes=4, usemymalloc=n, prototype=define Linker and Libraries: ld='cc', ldflags =' -L/usr/local/lib' libpth=/usr/local/lib /lib /usr/lib libs=-lnsl -ldl -lm -lc -lposix -lcrypt libc=, so=so, useshrplib=false, libperl=libperl.a Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-rdynamic' cccdlflags='-fpic', lddlflags='-shared -L/usr/local/lib' Locally applied patches: @INC for perl 5.00503: /homes/epa98/lib/perl5 /homes/epa98/lib/perl5/site_perl/i386-linux /homes/epa98/lib/perl5/site_perl /homes/epa98/lib/perl5/site_perl/5.005/i386-linux /homes/epa98/lib/perl5/site_perl/5.005 /homes/epa98/lib/perl5/site_perl/5.005/i386-linux /usr/lib/perl5/5.00503/i386-linux /usr/lib/perl5/5.00503 /usr/lib/perl5/site_perl/5.005/i386-linux /usr/lib/perl5/site_perl/5.005 . Environment for perl 5.00503: HOME=/homes/epa98 LANG=en_GB LANGUAGE (unset) LD_LIBRARY_PATH=/homes/epa98/lib:/homes/epa98/wine/inst/lib:/usr/local/lib LOGDIR (unset) PATH=/homes/epa98/bin:/homes/epa98/wine/inst/bin:/vol/lab/cs2/bin:/vol/lab/cs2/bin/i386:/vol/lab/secondyear/bin:/vol/lab/secondyear/bin/i386:/vol/lab/secondyear/bin/Linux/i386:/vol/lab/bin:/vol/lab/bin/i386:/vol/lab/bin/Linux/i386:/usr/bin:/bin:/usr/X11R6/bin:/usr/local/bin:/opt/bin:/opt/kde/bin:/usr/local/X11/bin:/usr/krb5/bin:/vol/labsrc/src/cocktail/bin:/usr/athena/bin:/sbin:/usr/sbin:/usr/local/jdk1.2.2/bin:/usr/share/smlnj/bin:/vol/linux/apps/bin:/usr/games:/vol/csg/public/bin:.:/homes/aces98/bin:/homes/mtm98/bin:/homes/pl198/bin:/homes/jkst98/micq PERL5LIB=/homes/epa98/lib/perl5:/homes/epa98/lib/perl5/site_perl:/homes/epa98/lib/perl5/site_perl/5.005:/homes/epa98/lib/perl5/site_perl/5.005/i386-linux PERL_BADLANG (unset) SHELL=/bin/bash ```
p5pRT commented 24 years ago

From @ysth

In article \200009111001\.LAA17175@​dynamic08\.doc\.ic\.ac\.uk\, Edward Avis \epa98@​doc\.ic\.ac\.uk wrote​:

If you accidentally use something like tr/\d// on a reference\, the variable becomes stringified without any warning. Later on if you try to use it as a reference\, the error message produced is confusing. \ I reported this to comp.lang.perl.moderated and Yitzchak Scott-Thoennes \sthoenna@​efn\.org suggested a fix​:

s/// is broken\, too.

Here's one way to fix tr///​: --- doop.c.orig Fri Sep 1 14​:09​:46 2000 +++ doop.c Sat Sep 9 22​:37​:38 2000 @​@​ -438\,7 +438\,7 @​@​ I32 hasutf = (PL_op->op_private & (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF));

- if (SvREADONLY(sv) && !(PL_op->op_private & OPpTRANS_IDENTICAL)) + if ((SvREADONLY(sv) || SvROK(sv)) && !(PL_op->op_private & OPpTRANS_IDENTICAL)) Perl_croak(aTHX_ PL_no_modify);

 \(void\)SvPV\(sv\, len\);

End of Patch.

but that would prevent doing anything useful with an overloaded object (but that should be ok since it is broken as it is now). And the error message may need to be more specific.

Are there any cases where a non-readonly non-reference would have get magic but not set magic? If so\, these would be broken too.

I also noticed that $x =~ tr/x// is calling get magic twice.

I didn't give the correct fix\, since even a 'counting' tr seems to implicity stringify the reference. (That is\, $x =~ tr/x// is equivalent to ($x = "$x") =~ tr/x//. It probably should be equivalent to "$x" =~ tr/x// instead.)

Also problematic are s///\, chop\, chomp\, 4-arg substr\, and 3-arg rvalue substr. Each of these operating on a reference $x implicitly do ($x = "$x") first. Are there other operators that give string lvalue context?

3-arg lvalue substr (e.g. substr($x\,0\,0)='') does give a warning "Attempt to use reference as lvalue in substr" but goes ahead and stringifies the reference.

I'd be inclined to say all the others should do the same\, but the wording of the warning bothers me since it is not just attempting to use the reference as an lvalue\, it actually is using it as an lvalue.

p5pRT commented 24 years ago

From @abigail

On Mon\, Sep 11\, 2000 at 02​:40​:03PM -0700\, Yitzchak Scott-Thoennes wrote​:

Also problematic are s///\, chop\, chomp\, 4-arg substr\, and 3-arg rvalue substr. Each of these operating on a reference $x implicitly do ($x = "$x") first. Are there other operators that give string lvalue context?

vec().

Abigail