I'm used to use dedicated or at least virtual servers for projects, but currently, I'm working on two projects which are using simple webspace instead without SSH access. A cgi-bin directory is all you need for Perl, but what happens, if a script dies without an error message?
I stumbled into this problem when the asset page of a MovableType installation didn't show up any longer. The server replied a 500 internal server error and the Apache error.log file stated Premature end of script headers for the called mt.cgi.
Using Perl in CGI mode has some advantages: All scripts are called as simple executable files making debugging more easy than stuff running in a mod_php environment, even without SSH access to the server.
I started by uploading a small bash script into the cgi-bin folder:
#!/bin/bashecho "Content-type: text/html"echo ""echo "<pre>"./mt.cgi 2>&1The script should output a simple HTTP header and switch the browser to preformatted mode. Any output from the script - including header lines - is shown in the web browser this way. The last line also redirects standard error (STDERR) messages to the browser. It didn't help, because I didn't get any output. I added some more lines to check if my debugger script is working like it should - and it did. There wasn't any output from mt.cgi and also no error message.
Next try: strace is a great tool for debugging:
#!/bin/bashecho "Content-type: text/html"echo ""echo "<pre>"strace -o mt.trace ./mt.cgiBut it turned out, that strace hasn't been installed on this server.
I started searching the net and finally found Devel::CallTrace which outputs every single subroutine call and it doesn't require any external libraries and depends on Perl core modules only. I added a Devel directory to MT's extlib and uploaded CallTrace.pm from CPAN into this directory. The final debug script was:
#!/bin/bashecho "Content-type: text/html"echo ""echo "<pre>"perl -Iextlib -d:CallTrace ./mt.cgiecho $?The Perl interpreter is being started with two (additional) arguments: -Iextlib to search the extlib directory for modules and -d:CallTrace to start the Perl debugger and load the Devel::CallTrace module. The last line prints the exit status of mt.cgi. I found out, that the whole Perl process was dying in a SIGSEGV, a so-called Segmentation fault just after calling GD::Image::newFromJpeg.
GD is the only image library installed on this server which is being used by MovableType to create thumbnails. The GD lib tried to load an asset image and failed. It didn't output an error and exit but simple ran into the SIGSEGV (which is usually related to bad style).
Looking at the assets in the MovableType database and the upload directory, I noticed a 4 MB JPEG photo which had been compressed to a smaller file size using JPEG compression but still was more than 4000 x 3000 pixels. I tried to load the file into GD using an oneliner on my laptop:
perl -MGD -le '$x = GD::Image::newFromJpeg("image.jpg"); system "ps u $$";'Measuring a scripts size using a system call isn't accurate or great style, but it's perfectly ok for me when testing around. Without any MT stuff, GD took more than 200 MB VSZ to load the image. Adding an ulimit -a to the debug script reported a limit of 128 MB virtual memory (which is VSZ in the ps list).
It looks like GD is segfaulting when trying to load an image bigger than the allowed maximum memory.