X

The leading edge of scripting languages and Oracle Database brought to you by the Data Access Development team

  • php |
    Tuesday, August 14, 2012

Using the PHP CLI Webserver to Identify and Test Memory Issues in PHP

By: Christopher Jones | Senior Principal Product Manager

The PHP 5.4 CLI webserver is being used more and more to identify and resolve PHP bugs. Following on from the CLI webserver tests that Xinchen Hui (aka "laruence") instigated for the PHP 5.4 release, Anatoliy Belsky (aka "weltling") begain adding CLI webserver tests for the APC package, which is currently undergoing some much needed fixups for PHP 5.4.

Rasmus Lerdorf has also been running some of the PHP command line tests through the CLI web server to identify crashes and memory corruption issues that the existing one-test-per-process tests can't identify. Even today a fix for a session issue was merged by Laruence. The symptom would have been a random crash that would have been very hard to reproduce and explain to the PHP developers.

Rasmus mentioned on IRC how he ran the tests: simply renaming the ".phpt" test files as ".php", and invoking them through the CLI webserver. The SKIPIF sections get executed, but that doesn't affect the desired outcome of testing multiple HTTP requests with different input scripts.

Below are some quick shell scripts I put together to automate testing the OCI8 extension with valgrind.

There are three scripts. The first creates a copy of all OCI8 tests with names changed to ".php":

    #!/bin/sh
# NAME: setup_tests.sh
# PURPOSE: Copy .phpt files as .php
# Assumes a clean PHP-5.4 branch with no tests/*.diff files
SD=$HOME/php-5.4/ext/oci8/tests
cd /tmp && rm -rf tests && mkdir tests
for F in $(echo $SD/*)
do
if [ "${F##*.}" = "phpt" ]; then
# sym link with a .php file extension instead of .phpt
N=$(basename $F .phpt).php
else
# sym link the unchanged filename
N=$(basename $F)
fi
ln -s $F tests/$N
done

The second script starts the PHP CLI webserver:

    #!/bin/sh
# NAME: start_ws.sh
# PURPOSE: Start the CLI webserver
PHP="$HOME/phpbuild/php54/sapi/cli/php"
PHPOPTS="-d max_execution_time=600 -d log_errors=Off"
PORT=4444
VALGRIND=valgrind
VALGRINDOPTS=" --tool=memcheck --suppressions=$HOME/.valgrind_supp"
USE_ZEND_ALLOC=0 $VALGRIND $VALGRINDOPTS $PHP $PHPOPTS \
-t /tmp/tests -S localhost:$PORT

Here I'm running valgrind to check for memory issues. I set the execution time large, because several of the OCI8 tests take time, especially with valgrind.

The third script invokes all PHP tests sequentially:

    #!/bin/sh
# NAME: wg_all.sh
# PURPOSE: Load all .php scripts sequentially
PORT=4444
cd /tmp/tests
for F in *.php
do
wget -O /tmp/L.php_cli_test http://localhost:$PORT/$F
done

You can change this script to call subsets of your own scripts, or repeatedly call scripts to check memory usage and cleanup code.

To use the scripts, start the webserver and wait for it to initialize:

    $ ./start_ws.sh 
==14170== Memcheck, a memory error detector
==14170== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==14170== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==14170== Command: php -d max_execution_time=600 -d log_errors=Off -t /tmp/tests -S localhost:4444
==14170==
PHP 5.4.5-dev Development Server started at Tue Aug 14 14:53:34 2012
Listening on http://localhost:4444
Document root is /tmp/tests
Press Ctrl-C to quit.

This sits, waiting to handle requests.

In a second terminal run wg_all.sh to initiate requests:

    $ ./wg_all.sh
--2012-08-14 14:38:41-- http://localhost:4444/tests/array_bind_001.php
Resolving localhost... 127.0.0.1
Connecting to localhost|127.0.0.1|:4444... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `/tmp/L.php_cli_test'
[ <=> ] 707 --.-K/s in 0.003s
2012-08-14 14:38:44 (231 KB/s) - `/tmp/L.php_cli_test' saved [707]
. . .

You could suppress this output by adding the option "-o /tmp/L.wg_output" to wg_all.sh. I didn't add it because, although I'm ignoring output, I like to see that the tests are really returning something.

The first terminal running the CLI web server shows each requested script:

    [Tue Aug 14 14:35:06 2012] 127.0.0.1:34006 [200]: /tests/array_bind_001.php
[Tue Aug 14 14:35:06 2012] 127.0.0.1:34008 [200]: /tests/array_bind_002.php
[Tue Aug 14 14:35:07 2012] 127.0.0.1:34010 [200]: /tests/array_bind_003.php
[Tue Aug 14 14:35:07 2012] 127.0.0.1:34013 [200]: /tests/array_bind_004.php
[Tue Aug 14 14:35:07 2012] 127.0.0.1:34015 [200]: /tests/array_bind_005.php
[Tue Aug 14 14:35:07 2012] 127.0.0.1:34017 [200]: /tests/array_bind_006.php
[Tue Aug 14 14:35:07 2012] 127.0.0.1:34019 [200]: /tests/array_bind_007.php
[Tue Aug 14 14:35:08 2012] 127.0.0.1:34021 [200]: /tests/array_bind_008.php
. . .

This is the output stream to monitor for valgrind issues.

You can remove the wget "-O /tmp/L.php_cli_test" option if you want to see the returned output from each test, e.g. to check that the tests are connecting to the database correctly.

Removing the php "-d log_errors=Off" option will show you errors in the CLI web server output. Many tests deliberately create errors, but issues with .phpt SKIPIF sections will be more obvious.

You can customize these scripts for your applications and help discover reproducible PHP bugs. With valid test cases, the PHP development team has a much better chance of resolving any problems.

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha