Return-Path: X-Original-To: apmail-perl-docs-dev-archive@www.apache.org Delivered-To: apmail-perl-docs-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id AD7E5E62D for ; Mon, 26 Nov 2012 21:55:13 +0000 (UTC) Received: (qmail 58785 invoked by uid 500); 26 Nov 2012 21:55:13 -0000 Delivered-To: apmail-perl-docs-dev-archive@perl.apache.org Received: (qmail 58734 invoked by uid 500); 26 Nov 2012 21:55:13 -0000 Mailing-List: contact docs-dev-help@perl.apache.org; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Id: Delivered-To: mailing list docs-dev@perl.apache.org Received: (qmail 58726 invoked by uid 99); 26 Nov 2012 21:55:13 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 26 Nov 2012 21:55:13 +0000 X-ASF-Spam-Status: No, hits=-1.2 required=5.0 tests=RCVD_IN_IADB_DK,RCVD_IN_IADB_LISTED,RCVD_IN_IADB_MI_CPR_MAT,RCVD_IN_IADB_RDNS,RCVD_IN_IADB_SPF,RCVD_IN_IADB_UT_CPR_MAT,SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of andy@andybev.com designates 89.16.184.171 as permitted sender) Received: from [89.16.184.171] (HELO earth.simplelists.com) (89.16.184.171) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 26 Nov 2012 21:55:04 +0000 Received: from [109.246.137.107] (unknown [109.246.137.107]) by earth.simplelists.com (Postfix) with ESMTPA id 8F4FD1B3003D for ; Mon, 26 Nov 2012 21:54:43 +0000 (GMT) Message-ID: <1353966876.1779.13.camel@andrew-desktop> Subject: Global variables patch for v2 documentation From: Andrew Beverley To: docs-dev@perl.apache.org Date: Mon, 26 Nov 2012 21:54:36 +0000 Content-Type: multipart/mixed; boundary="=-lvqbW7nZbi3hT9BbU6/2" X-Mailer: Evolution 3.2.2- Mime-Version: 1.0 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=andybev.com; s=selector1; t=1353966883; bh=XuOLmUTby+3PU6UmHlwWrXYmUe9y3TSibBGdEfxgso4=; h=Message-ID:Subject:From:To:Date:Content-Type:Mime-Version; b=nWL1gzyuWC9kSYmhRqnqItCdMmTbjzAlOuSMZZ6ETas15k7vNV8hWGuysOKjm9DH6 lb1k9bS+tCLS3s19zkj/5pDW86unaZkocEPesu+G4xmEtDSlmzQzFphIW/CSVkYtE2 /6fAy7Fq//InKeYeCuQBm16GEIrOPG9DoRKh4LfE= X-Virus-Checked: Checked by ClamAV on apache.org --=-lvqbW7nZbi3hT9BbU6/2 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 7bit Guys, Further to my email (thanks for the replies) please find attached my first patch (mostly copied from v1 docs). This adds to the v2 documentation some information about the handling of global variables, which certainly confused me to begin with. I'll hopefully be following this with a couple more patches once I get the time. Thanks, Andy --=-lvqbW7nZbi3hT9BbU6/2 Content-Disposition: attachment; filename="sometimes.diff" Content-Type: text/x-patch; name="sometimes.diff"; charset="UTF-8" Content-Transfer-Encoding: 7bit diff -rupN modperl-docs.orig/src/docs/2.0/user/troubleshooting/troubleshooting.pod modperl-docs.sometimes/src/docs/2.0/user/troubleshooting/troubleshooting.pod --- modperl-docs.orig/src/docs/2.0/user/troubleshooting/troubleshooting.pod 2012-11-24 13:28:27.294345909 +0000 +++ modperl-docs.sometimes/src/docs/2.0/user/troubleshooting/troubleshooting.pod 2012-11-25 19:50:10.264734329 +0000 @@ -675,6 +675,158 @@ when you encounter this problem. +=head2 Variable $x will not stay shared at + +This warning is normally as a result of variables that your script is sharing +with subroutines globally, rather than passing by value or reference. As +the cause and solution of this is virtually identical to another commonly +encountered problem (L), +the text is not repeated here but is instead included in that section which +follows this one. + +You may have read somewhere F that this warning can be ignored, +but if you read on you will see that you should F ignore the warning. +The other thing that might confuse you is that this warning is normally +encountered when defining subroutines within subroutines. So why would you +experience it in your script where that is not the case? The reason is +because mod_perl wraps your script in its own subroutine (see the L +documentation for more details). + + + + +=head2 Sometimes it Works, Sometimes it Doesn't + +When you start running your scripts under mod_perl, you might find +yourself in a situation where a script seems to work, but sometimes it +screws up. And the more it runs without a restart, the more it screws +up. Often the problem is easily detectable and solvable. You have to +test your script under a server running in single process mode +(C). + +Generally the problem is the result of using global variables (normally accompanied +by a L warning). Because +global variables don't change from one script invocation to another +unless you change them, you can find your scripts do strange things. + +Let's look at three real world examples: + +=head3 An Easy Break-in + +The first example is amazing: Web Services. Imagine that you enter +some site where you have an account, perhaps a free email +account. Having read your own mail you decide to take a look at +someone else's. + +You type in the username you want to peek at and a dummy password and +try to enter the account. On some services this will work!!! + +You say, why in the world does this happen? The answer is simple: +B. You have entered the account of someone who +happened to be served by the same server child as you. Because of +sloppy programming, a global variable was not reset at the beginning +of the program and voila, you can easily peek into someone else's +email! Here is an example of sloppy code: + + use vars ($authenticated); + my $q = new CGI; + my $username = $q->param('username'); + my $passwd = $q->param('passwd'); + authenticate($username,$passwd); + # failed, break out + unless ($authenticated){ + print "Wrong passwd"; + exit; + } + # user is OK, fetch user's data + show_user($username); + + sub authenticate{ + my ($username,$passwd) = @_; + # some checking + $authenticated = 1 if SOME_USER_PASSWD_CHECK_IS_OK; + } + +Do you see the catch? With the code above, I can type in any valid +username and any dummy password and enter that user's account, +provided she has successfully entered her account before me using the +same child process! Since C<$authenticated> is global--if it becomes 1 +once, it'll stay 1 for the remainder of the child's life!!! The +solution is trivial--reset C<$authenticated> to 0 at the beginning of +the program. + +A cleaner solution of course is not to rely on global variables, but +rely on the return value from the function. + + my $q = CGI->new; + my $username = $q->param('username'); + my $passwd = $q->param('passwd'); + my $authenticated = authenticate($username,$passwd); + # failed, break out + unless ($authenticated){ + print "Wrong passwd"; + exit; + } + # user is OK, fetch user's data + show_user($username); + + sub authenticate{ + my ($username,$passwd) = @_; + # some checking + return (SOME_USER_PASSWD_CHECK_IS_OK) ? 1 : 0; + } + +Of course this example is trivial--but believe me it happens! + +=head3 Thinking mod_cgi + +Just another little one liner that can spoil your day, assuming you +forgot to reset the C<$allowed> variable. It works perfectly OK in +plain mod_cgi: + + $allowed = 1 if $username eq 'admin'; + +But using mod_perl, and if your system administrator with superuser +access rights has previously used the system, anybody who is lucky +enough to be served later by the same child which served your +administrator will happen to gain the same rights. + +The obvious fix is: + + $allowed = $username eq 'admin' ? 1 : 0; + +=head3 Regular Expression Memory + +Another good example is usage of the C regular expression +modifier, which compiles a regular expression once, on its first +execution, and never compiles it again. This problem can be difficult +to detect, as after restarting the server each request you make will +be served by a different child process, and thus the regex pattern for +that child will be compiled afresh. Only when you make a request that +happens to be served by a child which has already cached the regex +will you see the problem. Generally you miss that. When you press +reload, you see that it works (with a new, fresh child). Eventually it +doesn't, because you get a child that has already cached the regex +and won't recompile because of the C modifier. + +An example of such a case would be: + + my $pat = $q->param("keyword"); + foreach( @list ) { + print if /$pat/o; + } + +To make sure you don't miss these bugs always test your CGI in +L. + +To solve this particular C modifier problem refer to L. + +For more details and further examples please see the L documentation. + --=-lvqbW7nZbi3hT9BbU6/2 Content-Type: text/plain; charset=us-ascii --------------------------------------------------------------------- To unsubscribe, e-mail: docs-dev-unsubscribe@perl.apache.org For additional commands, e-mail: docs-dev-help@perl.apache.org --=-lvqbW7nZbi3hT9BbU6/2--