Gossamer Forum
Home : Products : Gossamer Links : Development, Plugins and Globals :

[BUG] Race condition bug in GT::Template

Quote Reply
[BUG] Race condition bug in GT::Template
Alex, GT Staff, Perl experts,


It seems, there is a race condition in the GT::Template module (at least in the version used in LSQL v2.1.2).


I get such errors:
Quote:
Error Message : GT::Template (7325): Unable to run compiled template file '.../cgi-bin/lsql/admin/templates/default/compiled/link.html.compiled'.

Quote:
Error Message : Can't find string terminator "}" anywhere before EOF at .../cgi-bin/lsql/admin/templates/default/compiled/link.html.compiled line 156.


The problem happens at GT::Template::_compile_template, which does NOT use file LOCKing at all!

Code:
sub _compile_template {
# -------------------------------------------------------------------
# Loads the template parser and compiles the template and saves it
# to disk.
#
my ($self, $file, $full_compiled, $print) = @_;
$self->debug("Compiling template $file (into $full_compiled)")
if $self->{_debug};
require GT::Template::Parser;
my $parser = GT::Template::Parser->new(indent => $self->{indent},
begin => $self->{begin}, end => $self->{end});
$parser->debug_level($self->{_debug}) if $self->{_debug};

my ($code, $files) = $parser->parse(
$file,
{ root => $self->{root} },
($print and $print == 2)
);

local *FH;
my $tmpfile = $full_compiled . "." . time . "." . $$ . "."
. int(rand(10000)) . ".tmp";
# missing file locking here
open FH, ">$tmpfile" or return $self->fatal(CANTOPEN => $tmpfile, "$!");
my $localtime = localtime;
my $file_string = '[' . join(',', map {
my ($file, $path, $mtime, $size) = @$_;
for ($file, $path) { s/([\\'])/\\$1/g if defined }
"['$file'," . (defined $path ? "'$path'" : 'undef') . ",$mtime,$size]"
} @$files) . ']';

(my $escaped = $full_compiled) =~ s/(\W)/sprintf "_%x", ord($1)/ge;
print FH qq
|# This file is a compiled version of a template that can be run much faster
# than reparsing the file, yet accomplishes the same thing. You should not
# attempt to modify this file as any changes you make would be lost as soon as
# the original template file is modified.
# Editor: vim:syn=perl
# Generated: $localtime
local \$^W;
{
files => $file_string,
parser_version => $VERSION,
code => \\&GT::Template::parsed_template
};
sub GT::Template::parsed_template {
$$code
}|;
close FH;
unless (rename $tmpfile, $full_compiled) {
unlink $tmpfile;
return $self->fatal(RENAME => $tmpfile, $full_compiled, "$!");
}
chmod 0666, $full_compiled;
return;
}


I had no much time to analyze lockings used in LSQL. I know that there are file lockings (using directories) used, but it seems this GT::Template lacks implementation of locks.
At least the practice shows this. Did I miss some locking options I should use at GT::Template module implementation?

Best regards,
Webmaster33


Paid Support
from Webmaster33. Expert in Perl programming & Gossamer Threads applications. (click here for prices)
Webmaster33's products (upd.2004.09.26) | Private message | Contact me | Was my post helpful? Donate my help...
Quote Reply
Re: [webmaster33] [BUG] Race condition bug in GT::Template In reply to
Oh, I see it...
In LSQL v2.1.2 there was no temporary file used. So was compiling directly into compiled file. Thus there was a race condition in LSQL v2.1.2.

In LSQL v2.2.1, LSQL v3.0 and later there was a temporary file introduced, which is renamed to final compiled file. Since rename is atomic, the race condition is solved in LSQL v2.2.1 and above.


So the solution to my problem is, to upgrade to GT::Template used in LSQL v3.0.3, so the race condition will be gone... Cool


Sorry for the false bug alarm! Frown

Best regards,
Webmaster33


Paid Support
from Webmaster33. Expert in Perl programming & Gossamer Threads applications. (click here for prices)
Webmaster33's products (upd.2004.09.26) | Private message | Contact me | Was my post helpful? Donate my help...