You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@perl.apache.org by Stas Bekman <st...@stason.org> on 2005/04/20 06:02:50 UTC
[mp2] cloning and $r
Using the CLONE_SKIP approach, we now have a new problem. The following
sequence gives us a segfault:
% t/TEST -maxclients 1 t/modperl/io_with_closed_stds.t t/apr/pool.t
#0 0xb7b79efb in modperl_wbucket_flush (wb=0x120, add_flush_bucket=0)
at modperl_filter.c:236
236 if (wb->outcnt) {
(gdb) bt
#0 0xb7b79efb in modperl_wbucket_flush (wb=0x120, add_flush_bucket=0)
at modperl_filter.c:236
#1 0xb7b79348 in PerlIOApache_flush (my_perl=0x825b228, f=0x92e8158)
at modperl_io_apache.c:173
#2 0xb7b20208 in Perl_PerlIO_flush (my_perl=0x825b228, f=0x92e8158) at
perlio.c:1604
#3 0xb7b20295 in Perl_PerlIO_flush (my_perl=0x825b228, f=0x92e8158) at
perlio.c:1628
#4 0xb7fe7a68 in Perl_ithread_create (my_perl=0x825b228, obj=0x0,
classname=0x93aa620 "threads", init_function=0x9232c70, params=0x9232d84)
at threads.xs:415
[...]
(gdb) p *wb
Cannot access memory at address 0x120
(gdb) p wb
$1 = (modperl_wbucket_t *) 0x120
(gdb) up
#1 0xb7b79348 in PerlIOApache_flush (my_perl=0x825b228, f=0x92e8158)
at modperl_io_apache.c:173
173 MP_TRACE_STR_TRUNC(rcfg->wbucket->pool,
(gdb) p *rcfg
$3 = {pnotes = 0x8950ad8, global_request_obj = 0x8950af0, flags = 16 '\020',
status = 155424024, wbucket = 0x120, handlers_per_dir = {0x21, 0xb7cc3838,
0xb7cc3838, 0x866c9b0, 0x866ca30, 0x866b578, 0x866cb50, 0x866b410,
0x21, 0x10,
0x0}, handlers_per_srv = {0x0, 0x0, 0x0}, perl_globals = {end = {av =
0x10,
key = 143993632}, env = {gv = 0x121, tmphv = 0x8951058, orighv =
0xc}, inc = {
gv = 0x3, tmpav = 0x3, origav = 0x8666fd0}, defout = {gv = 0x100020,
flags = -27 'å'}, rs = {sv = 0x8952c7a,
As you can see rcfg is totally bogus.
I'm not sure whether it's the previous test that shows that more things
need to be cleaned up at the end of request, or may be we have no choice
but to clone $r. Using atomatic cloning of $r may work, as long as threads
won't try to access any of $r's records, since a race condition is
possible. We can't really prevent it.
Quite a fun game...
The interesting thing is that the second test that fails is 'SetHandler
modperl', so it doesn't override STDOUT. Therefore it's clear that the
first test which is 'SetHandler perl-script' and overriding STDOUT,
doesn't bring things back to the clean state after its run. I should
probably investigate this possibility first.
--
__________________________________________________________________
Stas Bekman JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/ mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org http://ticketmaster.com
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org
Re: [mp2] cloning and $r
Posted by Stas Bekman <st...@stason.org>.
Stas Bekman wrote:
> Using the CLONE_SKIP approach, we now have a new problem. The following
> sequence gives us a segfault:
>
> % t/TEST -maxclients 1 t/modperl/io_with_closed_stds.t t/apr/pool.t
>
> #0 0xb7b79efb in modperl_wbucket_flush (wb=0x120, add_flush_bucket=0)
> at modperl_filter.c:236
> 236 if (wb->outcnt) {
> (gdb) bt
> #0 0xb7b79efb in modperl_wbucket_flush (wb=0x120, add_flush_bucket=0)
> at modperl_filter.c:236
> #1 0xb7b79348 in PerlIOApache_flush (my_perl=0x825b228, f=0x92e8158)
> at modperl_io_apache.c:173
> #2 0xb7b20208 in Perl_PerlIO_flush (my_perl=0x825b228, f=0x92e8158) at
> perlio.c:1604
> #3 0xb7b20295 in Perl_PerlIO_flush (my_perl=0x825b228, f=0x92e8158) at
> perlio.c:1628
> #4 0xb7fe7a68 in Perl_ithread_create (my_perl=0x825b228, obj=0x0,
> classname=0x93aa620 "threads", init_function=0x9232c70,
> params=0x9232d84)
> at threads.xs:415
> [...]
> (gdb) p *wb
> Cannot access memory at address 0x120
> (gdb) p wb
> $1 = (modperl_wbucket_t *) 0x120
> (gdb) up
> #1 0xb7b79348 in PerlIOApache_flush (my_perl=0x825b228, f=0x92e8158)
> at modperl_io_apache.c:173
> 173 MP_TRACE_STR_TRUNC(rcfg->wbucket->pool,
> (gdb) p *rcfg
> $3 = {pnotes = 0x8950ad8, global_request_obj = 0x8950af0, flags = 16
> '\020',
> status = 155424024, wbucket = 0x120, handlers_per_dir = {0x21,
> 0xb7cc3838,
> 0xb7cc3838, 0x866c9b0, 0x866ca30, 0x866b578, 0x866cb50, 0x866b410,
> 0x21, 0x10,
> 0x0}, handlers_per_srv = {0x0, 0x0, 0x0}, perl_globals = {end = {av
> = 0x10,
> key = 143993632}, env = {gv = 0x121, tmphv = 0x8951058, orighv =
> 0xc}, inc = {
> gv = 0x3, tmpav = 0x3, origav = 0x8666fd0}, defout = {gv = 0x100020,
> flags = -27 'å'}, rs = {sv = 0x8952c7a,
>
> As you can see rcfg is totally bogus.
>
> I'm not sure whether it's the previous test that shows that more things
> need to be cleaned up at the end of request, or may be we have no choice
> but to clone $r. Using atomatic cloning of $r may work, as long as
> threads won't try to access any of $r's records, since a race condition
> is possible. We can't really prevent it.
>
> Quite a fun game...
>
> The interesting thing is that the second test that fails is 'SetHandler
> modperl', so it doesn't override STDOUT. Therefore it's clear that the
> first test which is 'SetHandler perl-script' and overriding STDOUT,
> doesn't bring things back to the clean state after its run. I should
> probably investigate this possibility first.
OK, I've figure it out: it was Test::Builder who was dupping STDOUT which
was open to use PerlIO::Apache layer, so essentially it was stashing the
raw pointer to r. On the following request, anything that tries to reopen
STDOUT will need to flush it first, and it'll try to flush a bogus r,
which doesn't exist anymore.
So, I've bandaided this with calling $Test->reset early at the server
startup, where STDOUT is not yet overriden, now we get:
# XXX: May be this should go into Apache::Test, so other mod_perl test
# suites won't suffer from the same problems.
use Test::Builder;
my $Test = Test::Builder->new;
# under mod_perl we don't want Test::Builder to run the END block
$Test->no_ending(1);
# setup T-B's STD handlers early so that it won't mess up with PerlIO
# layers (which is a death under threads)
$Test->reset;
The problem is that it's clear that our code is very fragile, we can't
verify whether r is valid or not before using it, if we only have a C
pointer. Many times the invalid r still have most of its fields valid, so
checking for specific fields is not an option. So any closure will cause a
crash, any dupped IO layer will cause a crash. Unfortunately I can't quite
see how can we protect against this. Ideas?
May be instead of passing $r which has a pointer to r, we should create an
intermediate pointer, _r which will point to r.
request_rec ** = &r;
So Perl will never see r. At the end of each request we can:
_r = NULL;
so any closure or dupped IO layer who holds a ghost of $r from the
previous request will show a clear NULL for which we can check and
gracefully die, rather than segfault?
Does it look like a working solution? Will this introduce a significant
overhead?
--
__________________________________________________________________
Stas Bekman JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/ mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org http://ticketmaster.com
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org