ID:               21306
 Comment by:       eric dot ritchie at dorten dot com
 Reported By:      Xuefer at 21cn dot com
 Status:           No Feedback
 Bug Type:         Session related
 Operating System: linux
 PHP Version:      4.3.0
 New Comment:

I think I may be able to cast some light on this particular problem.
First the important info:

OS: Suse Linux 8.1 / Suse Linux 7.0 / Windows 2000
PHP: 4.3.1 / 4.3.0 / 4.3.1 & 4.3.2PL4
Apache: 1.3.27+ssl1.48 / same / 1.3.26

PHP is compiled into Apache on the Linux machines and inserted as a
module under Windows.

The application, that am developing for my company, is a large project
with user management, sessions, SSL admin and non SSL user sections
etc. I first started to get this problem frequently after making one
particular change to the application. Since one user should only have
one connection to the application, I checked the session table (in a
MySQL database) and deleted all previous sessions that contained the
same user ID.

The problem came when someone was still using the session that was
deleted. Depending apon what that user was doing at the time of the
deletion, the application would either take them back to the login
screen and report the session had expired (what I intended) or crash
within the PEAR:throwError() method in the PEAR.php library. Checking
with debug_backtrace() I could see that a constant
(DB_FETCHMODE_ASSOC), passed to  one of the preceeding function calls,
was being corrupted during the call.

I thought that there was something screwed up with the MySQL session
handling code (in our application), so I switched back to using file
based sessions and found the same problem to exist. After some time I
found the following solution (see the comment for details):


function read($id) {
  $hackStr =
"selectedParts|a:0:{}selectedCars|a:0:{}selectedCountries|a:0:{}cartHead|a:0:{}sessionUser|a:0:{}sessionCustomer|a:0:{}";
  $db = &$GLOBALS['db'];
  $db->setFetchMode(DB_FETCHMODE_ASSOC);
    
  $q = "SELECT * FROM ourSession WHERE id = '".$id."'";
  $res = $db->query($q);
  if (PEAR::isError($res) || !($row = $res->fetchRow())) {
    // WARNING returning '' seems to crash PHP. Therefore, 
    // I return a empty session instead.    
    return $hackStr;
  }
  return base64_decode($row['data']);
} // read()


Which is of course called via session_set_save_handler(). I noted the
same problem with file session handling. If the contents of the file
are emptied (or the file is deleted) then the application crashed.
However, if I overwrote the file with a dummy session string, then all
worked well.

I am guessing that the version 4.3.x of PHP have a problem initialising
sessions and can cause buffer overflows under certain conditions.

I hope you all find this useful!
Eric Ritchie
Dorten GmbH.


Previous Comments:
------------------------------------------------------------------------

[2003-05-25 21:53:44] [EMAIL PROTECTED]

No feedback was provided. The bug is being suspended because
we assume that you are no longer experiencing the problem.
If this is not the case and you are able to provide the
information that was requested earlier, please do so and
change the status of the bug back to "Open". Thank you.

..and this is not likely anything wrong in PHP, some broken HTML can
make your script getting run twice too.


------------------------------------------------------------------------

[2003-05-20 13:13:43] xuefer at 21cn dot com

sorry, i meant chance, not change

------------------------------------------------------------------------

[2003-05-20 13:11:56] xuefer at 21cn dot com

sorry, i don't have change to test it yet
so will soletan confirm the snapshot
thx

------------------------------------------------------------------------

[2003-05-20 10:03:32] [EMAIL PROTECTED]

Code being executed twice really sounds like a problem in the scripting
engine to me. It could be caused or triggered by defects in the tool
chain (buggy compiler optimizer, broken bison/flex).

Please retest with current Stable snapshot from snaps.php.net.

------------------------------------------------------------------------

[2003-03-14 13:00:31] soletan at toxa dot de

I tried to compile some information on that bug, that probably helps to
understand my problems. Because this report system lacks of a support
for attachments (which is quite reasonable to me, of course). But I
guess you won't read >3MB text files unzipped or 86 KB archived, but
binary here ... I send the compilation to anyone who likes to get. 

Several php-scripts, some modifications to php-source I made, two quite
large but still „simple“ syslog-excerpts, a copy of output are included
with that compilation. The scripts are excerpts only, because a full
backup of my scripts’ source tree would take 190 KB gzipped. If you
need more information (sources) to reproduce the malfunction, send me a
mail, but I hope this is enough and maybe you don’t need that much
additional information.


Some first idea of what’s wrong: In my case this bug doesn’t
immediately belong to sessions. It’s probably some scripting failure or
a malfunction of how several parts of PHP-core and ext’s – zend
scripting engine and altered session handler – work together. It looks
like some overflow, like something’s trashing PHP’s heap. As a
consequence, or in conjunction with that, PHP doesn’t end and gets
dropped by maximum-execution-time observer, which then ignores any
session save procedures and cleans up everything. During this the
session still gets informed about restoring the ini-environment and
produces the posted error message.


Here is what I did:

The bug appeared again and I couldn't find any place in my scripts
missed to include some session_write_close() + exit() – this in
consequence to my last comment!

One of my scripts is a layouter (lib/layout.php), implemented as a
class. I feed it with information about the body content, menu
structure and else. It stores all these in a structured array. Finally
I call a method named "draw()", that searches for available plugins
depending on the client's browser-caps and uses one of these to produce
a string, which draw() returns itself to its caller afterwards. That
caller finally echo's the string right before the closing tag and the
end of major script file – I used src/start.php for testing.

Each trial to break the execution before calling that draw method was
successful, tested with included snippet "echo 'test'; exit( 0 );" ...


Now comes some interesting point:
Placing the same at the first line inside the draw-method, I get "test"
twice without delay. One exit gets ignored, then scripting gets into
draw() a second time and this time the exit seems to be computed, too.
This double call might become visible by the second logfile-excerpt,
message-foo ...

Removing any additional echo’s and exit’s, the script runs for maximum
execution time and then produces the output, Xuefer posted – at
modification notifier in ext/session/session.c:OnUpdateSaveHandler. 

I included some debugging support by calling syslog in zend/zend_ini.c
and in session/session.c of PHP's source tree at several points of
code. Watching my syslog-file I detected, that my installed
session-class didn’t get called for writing and closing, but zend
engine shuts down script execution.


Well, after detecting one of my variables having values at second run,
I've never assigned myself anywhere, I used this to detect the second
call and return immediately from method draw() after flushing session
with a pair of "session_write_close(); @session_start();". Now there's
no execution delay, no strange error message, nothing but a f**king
workaround hack.


Best Regards
Thomas Urban

------------------------------------------------------------------------

The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
    http://bugs.php.net/21306

-- 
Edit this bug report at http://bugs.php.net/?id=21306&edit=1

Reply via email to