Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Bug in 'strict'??

by Jouke (Curate)
on Apr 05, 2001 at 16:45 UTC ( [id://70066]=perlquestion: print w/replies, xml ) Need Help??

Jouke has asked for the wisdom of the Perl Monks concerning the following question:

I have the strangest problem I've seen so far in Perl. Please let someone explain what is going wrong here:

The case is simple. I have a file to upload via HTTP (you know: upload button, use CGI and get the file). I've rewritten the original script to this:
#!/usr/bin/perl -w use strict; use CGI; $|=1; my $buffer; print "Content-type: text/html\n\n"; print "<html><body>"; my $req = CGI->new; my $filename = $req->param("filename"); $filename =~ m/(.*?$CGI::SL)*(.*)(?=$)/; my $localfilename = "$2"; open(FILE, ">$localfilename") || print "Could not open $localfilename +for output: $!<br>\n"; while (my $bytesread = read($filename,$buffer,1024)) { print FILE $buffer; } close(FILE); print "File saved as $localfilename (original filename=$filename)<br>" +; print "</body></html>";
the HTML file looks like this (most simple form of course)
<html> <body> <form method=POST encoding="multipart/form-data" action="http://blur/n +ewtest.cgi"> <table border=1> <tr><td>Filename: </td><td><input type=file name="filename"></td></tr> <tr><td colspan=2><input type=submit></td></tr> </table> </form> </body> </html>
When I run this code and select any file, the moment the 'open' is called, the value of $localfilename is erased. Originally I used FileHandle but to make sure the error wasn't in that module, I replaced it with the plain open statement.

Now the strange part: when I leave out the use strict; everything works fine and the value of $localfilename is preserved.

I'm at a new job here, and everyone here tells me 'use strict' is no good, and I'm trying to convince them of the opposite, 'cause I always use it, and really believe anyone should use it, but this is making my statement a bit hard to defend....

Jouke Visser, Perl 'Adept'

Replies are listed 'Best First'.
Re: Bug in 'strict'? - CGI::SL, upload, CGI::Carp and stuff
by bjelli (Pilgrim) on Apr 05, 2001 at 19:27 UTC

    I played around with your Code with Netscape on Windows 2000 as the client, Apache on Debian. I ran into different problems:

    1) CGI::SL

    My client supplies the Filename "C:\WINNT\Media\Chimes.wav", while CGI::SL is /. Your pattern-matching/substitution thing did not work out, localfile got set to the whole filename. I'd recommend To be safe, use the upload() function (new in version 2.47). When called with the name of an upload field, upload() returns a filehandle, or undef if the parameter is not a valid filehandle. $fh = $query->upload('uploaded_file'); while (<$fh>) { print; } This is the recommended idiom.

    2) upload and strict refs

    trying to read from $filehandle I got the error:

    Can't use string ("C:\WINNT\Media\chimes.wav") as a symbol ref while "strict
    refs"...

    In the manpage for CGI I found:

    However, there are problems with the dual nature of the upload fields. If you use strict, then Perl will complain when you try to use a string as a filehandle. You can get around this by placing the file reading code in a block containing the no strict pragma.

    So a quick way to fix your code turned out to be

    { no strict; while (my $bytesread = read($filename,$buffer,1024)) { print FILE $buffer; } }

    But Beware! the CGI man page goes on to talk about security problems with this whole filename/filehandle-duality.

    To be safe, use the upload() function (new in version 2.47). When called with the name of an upload field, upload() returns a filehandle, or undef if the parameter is not a valid filehandle.
    $fh = $query->upload('uploaded_file'); while (<$fh>) { print; }
    This is the recommended idiom.

    Debugging-Output from CGI

    When debugging CGI don't count on the fact that your script "didn't even get there" if you can't see a certain line of debugging output. In my experience webservers tend to chew off some of the output (just when you least expect it, see also Murphys Law :-). Look into the server logfiles, or use CGI::Carp qw(fatalsToBrowser);

    That gives you all the error-messages right in the Browser.

    --
    Brigitte    'I never met a chocolate I didnt like'    Jellinek
    http://www.horus.com/~bjelli/         http://perlwelt.horus.at

      > or use CGI::Carp qw(fatalsToBrowser);

      > That gives you all the error-messages right in the Browser

      This too, is a misleading statement. If you have compile-time errors, these may or may not appear in the browser, depending upon whether the 'use CGI::Carp' has been evaluated before the compile-time error.

      I've unfortunately had way too many situations where I was forced to look in the server error log (difficult, at best, if you're using a hosting company) anyway, even with use CGI::Carp qw(fatalsToBrowser);.

      But then, this is a little off-topic, is it not?

      (we now return you to your regularly-scheduled debate)
Re: Bug in 'strict'??
by OeufMayo (Curate) on Apr 05, 2001 at 18:04 UTC

    Jouke,
    Beware of using $CGI::LS as it can bite you pretty badly. I was trying to reproduce your problem on my machine (Win2K), but it failed miserabily on compilation because of a missing parens in the regex. After checking the regex, I realized that $CGI::LS was equal to '\' in Win32 systems, and thus the regex was interpolated like that m/(.*?\)*(.*)(?=$)/, which is obviously a Bad Thing™.

    It doesn't have much to do with your use strict problem, but I thought you'd like to know!

    <kbd>--
    my $OeufMayo = new PerlMonger::Paris({http => 'paris.mongueurs.net'});</kbd>

    Edit 2001-03-05 by tye to close <code>

      Time to repeat my lastest rant: If you put a variable inside of a regex because you want to match that variable as a string (which is usually what you want to do), then you need to tell the regex that: /\Q$CGI::SL\E/

              - tye (but my friends call me "Tye")
Re: Bug in 'strict'??
by merlyn (Sage) on Apr 05, 2001 at 16:51 UTC
    You're using $2 without verifying the previous match truly matched. That's a "reject from code review" mistake in my book. Go back and ensure that the regex is matching.

    -- Randal L. Schwartz, Perl hacker

      You're right merlyn but that's not the case here. I just reduced it to the minimum, and this DOES work without 'strict' and DOESN'T with 'strict'. I surely want to know why (and btw: it matches...)

      Jouke Visser, Perl 'Adept'
Re: Bug in 'strict'??
by arturo (Vicar) on Apr 05, 2001 at 17:16 UTC

    I don't know what's going on, but let me give you a response to your cow orkers: let's suppose, worst-case scenario (and highly unlikely) that this is a bug in strict -- the claim that strict is "no good" is still silly (lots of good and useful software tools have bugs). It makes you *think* about your variables and how they're going to be scoped, rather than just splashing them anywhere, and possibly making tyops. I maintain a bunch of scripts that were written without strict in mind, and when things go wrong, tracking down the error is very very hard, because you have no idea where the variable was defined. IF, of course, one is so disciplined as to make the things that should be globals globals, and keep the things that should have local scope local, you won't run into problems. But why should you have to manage those issues yourself when there's a tool that manages that for you? It won't solve all your problems, but it will give you a huge head start on solving them over someone who *doesn't* use strict vars.

    And note, that's just strict 'vars' ... you could go on about strict 'refs' and strict 'subs' too =)

    Philosophy can be made out of anything. Or less -- Jerry A. Fodor

Re: Bug in 'strict'??
by TheoPetersen (Priest) on Apr 05, 2001 at 17:53 UTC
    I've tried this on two platforms (SCO and RH Linux) with two versions of Perl (5.005_03 and 5.6 respectively) and can't produce the bug; I get the same behavior in either case. I'm using the original code as posted (though I cut everything after the open) and ensured that my parameter matched the regex.

    What are your platform's vital statistics, out of curiousity?

    I'm curious if varying the regex or doing without it will affect the problem. Have you tried doing the same thing via another means? A split on a literal delimiter or some such?

    Update: after a flurry of /msgs we established that the script works correctly from the command line but not when run from VN Server. It does display the correct version of Perl in the latter case. I'm stumped as to what the server could do to induce this error.

    ..Theo

      We're running on Debian Linux with VN Server as webserver (don't ask me why they do here), but no Apache...perl is 5.005_03.

      Jouke Visser, Perl 'Adept'
Re: Bug in 'strict'??
by modred (Pilgrim) on Apr 05, 2001 at 16:54 UTC
    I don't know if it is a bug in strict or not but you need to check to make sure that the match works before assigning $2 to anything. If the match fails then $localfilename will be empty and the open will fail.

    Something like

    my $localfilename; if($filename =~ m/(.*?$CGI::SL)*(.*)(?=$)/ ) { $localfilename = $2; } else { # handle the error however you need to }
      You're right modred (I could have predicted these replies of course), but it does match. That's not even the case. $localfilename gets a value from $2. Take that as true, but just by calling open() the value disappears.

      Jouke Visser, Perl 'Adept'
Re: Bug in 'strict'??
by Jouke (Curate) on Apr 05, 2001 at 17:44 UTC
    OK, so here's for the people who think there's a problem with the regex (there isn't): this is a version which checks if the thing matches. If it doesn't, it gets a silly value...

    After the assignment of the $2 to $localfilename, I print out the value of $localfilename, and yet it prints out the errormessage with an empty string for $localfilename...

    #!/usr/bin/perl -w use strict; use CGI; $|=1; # Don't buffer the output my $buffer; #print out the correct content-type print "Content-type: text/html\n\n"; # start with nice html-tags print "<html><body>"; # new CGI object my $req = CGI->new; #retrieve the value of the selected filename my $filename = $req->param("filename"); # get only the filename (not the entire path) and if it doesn't match, + give $localfilename a silly value my $localfilename = $filename =~ m/(.*?$CGI::SL)*(.*)(?=$)/ ? $2 : "AS +illyValue"; # print out $localfilename to see if it has the correct value print $localfilename; # open $localfilename for output (and here it fails, with the $localfi +lename as an empty string) open(FILE, ">$localfilename") || print "Could not open $localfilename +for output: $!<br>\n"; # it doesn't even get here...so ignore please... while (my $bytesread = read($filename,$buffer,1024)) { print FILE $buffer; } close(FILE); print "File saved as $localfilename (original filename=$filename)<br>" +; print "</body></html>";


    Jouke Visser, Perl 'Adept'

      I'll go w a y out on a limb and blame this on a bug in the regex engine.

      m/(.*?$CGI::SL)*(.*)(?=$)/ is pretty, um, well, isn't pretty. ;) m/([^$CGI::SL]+)$/ is going to give the regex engine much fewer fits. See if that fixes things (that requires that you use $1 instead of $2 or just use my( $localfilename )= m/... instead).

              - tye (but my friends call me "Tye")
Re: Bug in 'strict'??
by perigeeV (Hermit) on Apr 05, 2001 at 17:53 UTC
    Forgive my paranoia, but:
    if( ($you == $new_employee) && (defined $strict_argument)) { haze($new_employee); }
    Sorry, but I've been there. You might get a clean CGI.pm
    and diff it against what you're using.
    As I said, probably just paranoid.
      HAHAHA ....

      anyways ... i've run into this problem before ... what you have to do is change the variable name of $localfilename to  $ZardonsBlackendCrownOfThorns and that way you won't be overwriting somebody else's globally defined variable ... but at the same time you get to praise our dark master Zardon every time you recieve an upload.

      in all my DarkUpload scripts I add the line

      if $ZardosEternalRagingHunger++ > rand() { unlink FILEHANDLE; print "It was the whim of the dark lord to devour your file\n"; }

      PS. i'm looking for work, if anyone needs a good perl programmer with CGI experience ;)

        "PS. i'm looking for work, if anyone needs a good perl programmer with CGI experience ;)"

        When looking for work, always advertise anonymously and leave no contact details. Works a treat.

        ;-)

        cLive ;-)

Re: Bug in 'strict'??
by grinder (Bishop) on Apr 05, 2001 at 17:03 UTC

    I think we may safely assume that strict does not contain bugs. Small comfort indeed.

    What about trying

    my $filename = $req->param("filename"); my ($localfilename) = ($filename =~ m/(?:.*?$CGI::SL)*(.*)(?=$)/);

    Otherwise, no, I don't see it...


    --
    g r i n d e r
Works great for me!
by osorronophris (Novice) on Apr 05, 2001 at 20:27 UTC
    I stuck this script in my cgi-bin on my own machine and it worked like a charm! The only change I made was changing open(FILE, ">$localfilename") to open(FILE, ">/tmp/$localfilename"). Here are my system stats:

    OpenBSD 2.8 (i386)
    perl v5.6.0 built for i386-openbsd
    Apache 1.3


    And here's the output of your script:
    File saved as test (original filename=/home/mosfet/test)

    so.... All idiomatic problems aside (like that whole "if" around the regex thing) your script is FINE. There are no relevent bugs in "use strict", which using, by the way, is about the best thing anyone can do in a production environment. If your coworkers give you that whole *@#$! about use strict being only for beginners or what-not, I'm sorry, they're just wrong. use strict is a GOOD IDEA. Unwillingness to use strict can lead to large problems that wouldn't happen in other languages. That's why it's there.

    The one reason I can find that your script may not be working is the use of $CGI::SL. On my system it's "/", which is correct for *nix. Since this is determined by the server, it may not change properly for Windows. I can't test this because I don't have access to Windows. But if that's the case, that could be your problem.

    PS: Just for kicks I tried it with "use diagnostics" and no errors were produced...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://70066]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (8)
As of 2024-04-18 21:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found