I'm not familiar with the implementation but may be something like: allocate
the memory, then free it and then allocate again? will that work?
The bottom line is that the same application behaves differently under winFU
and non-winFU perl versions. So if I'm a non-winFU developer and have a user
reporting a problem with my application on winFU, I should be able to
reproduce this problem on non-winFU platform. Please notice that this has
nothing to do with OS-specifics, like file system, signals or what not, but
just memory allocation/freeing implemented purely by Perl itself. How do we
make perl behave identically, so that if my program works on unix it will work
on winFU just the same (minus the perlport.pod issues).
If you think that there is no way to make winFU perl memory allocation behave
like non-winFU perl, give us an option to make non-winFU perl behave like
winFU perl, so we can debug our perl programs w/o needing to buy heaps of sw,
install and learn winFU, just to be able to resolve problems for the
unfortunate users of winFU. How hard would it be to emulate memory pools per
thread for non-winFU perl? I'm talking about a compile time option of course.
__________________________________________________________________
Stas Bekman JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/ mod_perl Guide ---> http://perl.apache.org
mailto:st...@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org http://ticketmaster.com
Well, that's just it. Perl tries to provide the same interface on
OS's that are _radically_ different underneath. And that involves
different approaches to memory allocation because the underlying OS
"invites" you to do things differently. And Perl fails in this
respect. What was found is no more and no less than a bug. That
should be fixed. Hopefully for 5.8.4 (if I'm to believe the
ActiveState people).
The same application _should_ behave the same. If there is a problem
on one platform and not on another, then there is a problem in the
interface with the OS on that platform. Please don't ask for Win32
bugs to happen on non Win32 systems as well. ;-)
>If you think that there is no way to make winFU perl memory
>allocation behave like non-winFU perl, give us an option to make
>non-winFU perl behave like winFU perl, so we can debug our perl
>programs w/o needing to buy heaps of sw, install and learn winFU,
>just to be able to resolve problems for the unfortunate users of
>winFU. How hard would it be to emulate memory pools per thread for
>non-winFU perl? I'm talking about a compile time option of course.
Im thinking added complexity and an open invitation to more bugs here.
It's like testing with Class::MockObject: in the end you only know
for sure that it works with Class::MockObject.
Liz
If it's screaming you're interested in, run it under valgrind ;-)
With --leak-check=yes, you should get a fairly comprehensice overview
of what was allocated and "lost".
>>Im thinking added complexity and an open invitation to more bugs here.
>>It's like testing with Class::MockObject: in the end you only know
>>for sure that it works with Class::MockObject.
>Any solution that will let me solve the problem for winFU users is welcome.
True. But I think that only a real winFU user will be able to fix
this in the "real" environment in the long run.
Liz
A bug? I don't think so. As I move around the context definitions as I flip
threads, things get fixed. But I'm really guessing and ask Steve to test it
for me, which is not very productive. And even if this gets fixed in 5.8.4,
what are we going to do with users running on previous perl versions?
> The same application _should_ behave the same. If there is a problem on
> one platform and not on another, then there is a problem in the
> interface with the OS on that platform. Please don't ask for Win32 bugs
> to happen on non Win32 systems as well. ;-)
this is not necessarily correct, Liz. The issue with contexts/alloc/free can
get tricky. It's possible that the application doesn't fail immediately on
unix but it may fail in the middle of some important task, because the freed
memory just happened not to be overrun by some other allocation. I actually
find it a goodness that winFU perl implementation screams when it finds
inconsistencies, I wish it was screaming much earlier and not during
perl_destruct, when it's not very helpful. What I'm asking for is to have an
optional feature on non-winFU perl which will scream the same way, plus doing
it when things get allocated and not freed.
>> If you think that there is no way to make winFU perl memory allocation
>> behave like non-winFU perl, give us an option to make non-winFU perl
>> behave like winFU perl, so we can debug our perl programs w/o needing
>> to buy heaps of sw, install and learn winFU, just to be able to
>> resolve problems for the unfortunate users of winFU. How hard would it
>> be to emulate memory pools per thread for non-winFU perl? I'm talking
>> about a compile time option of course.
>
>
> Im thinking added complexity and an open invitation to more bugs here.
>
> It's like testing with Class::MockObject: in the end you only know for
> sure that it works with Class::MockObject.
Any solution that will let me solve the problem for winFU users is welcome.
It's not quite doable when perl is embedded inside apache. I've tried several
times and it almost killed my machine.
>>> Im thinking added complexity and an open invitation to more bugs here.
>>> It's like testing with Class::MockObject: in the end you only know
>>> for sure that it works with Class::MockObject.
>>
>> Any solution that will let me solve the problem for winFU users is
>> welcome.
>
> True. But I think that only a real winFU user will be able to fix this
> in the "real" environment in the long run.
I think winFU perl can handle this issue better. I hope Jan will be able to
comment on my suggestion, on doing this pool testing during the memory
allocation and not during perl_destruct.
What's winfu?
Also, does anyone know exactly what is meant when windows generates these
errors? Is it that threads under windows OSes have a separate malloc pool
for each thread, so that if one thread does a malloc and then another
thread tries to free that address, you get the error?
> ithreads when the interpreter context is wrong and a memory from the wrong
> pool is allocated. This is all dandy, but it doesn't make it any easy to
> find the place where the problem is, as it complains at the perl_destruct
> stage. What would it take to make windows implementation complain about the
> wrong pool when the variable is asking to allocate the memory, or
> immediately after it, so the trace will pinpoint the place with a problem.
>
> I'm not familiar with the implementation but may be something like:
> allocate the memory, then free it and then allocate again? will that work?
I don't see how a scheme like that could possibly work. The only approach
that I can think of is that under certain Perl builds (say ithreads +
DEBUGGING), malloc/free are wrapped with functions that record the
thread id (or something) at the start of each allocated block, and then
throw a wobby if free is called and the tids don't match. This is
roughly what I hacked together the last time I fixed such a bug (not
being a windows hacker). Of course this doesn't provide for earlier
detection, it just makes detection available across all platforms.
The downside is that each malloc will use an extra 4+ bytes.
--
Monto Blanco... scorchio!
> I don't see how a scheme like that could possibly work. The only approach
> that I can think of is that under certain Perl builds (say ithreads +
> DEBUGGING), malloc/free are wrapped with functions that record the
> thread id (or something) at the start of each allocated block, and then
> throw a wobby if free is called and the tids don't match. This is
> roughly what I hacked together the last time I fixed such a bug (not
> being a windows hacker). Of course this doesn't provide for earlier
> detection, it just makes detection available across all platforms.
>
> The downside is that each malloc will use an extra 4+ bytes.
So can't be on by default; should probably be an independent #define option
I think I can see two "extra" things that would be useful - the thread ID
(as you observe) and a pointer to create a linked list of memory blocks
allocated under this thread. This way the implementation can free all the
ithread's memory on ithread exit, which (as I understand it) is equivalent
to what happens on Windows, but with the benefit that on x86/Linux while
running under valgrind one will get access errors as soon as another
ithread attempts to use the now-freed memory.
I'm not sure of the best way to tweak the layers of obfuscation, er,
indirection on perl's malloc() use to achieve this. Had someone kind
at ActiveState volunteer to suggest an interface, or am I misremembering?
I'm happy to actually implement the guts, if spoon fed the interface
interception stuff. (Foolish me for volunteering)
Nicholas Clark
>On Tue, Jan 20, 2004 at 06:57:14PM -0800, Stas Bekman wrote:
>> So we get these 'free to wrong pool' errors on winfu, usually under
>
>What's winfu?
I'm assuming Stas means something like "windows knowledge", just like
patch-fu or kung-fu.
>Also, does anyone know exactly what is meant when windows generates these
>errors? Is it that threads under windows OSes have a separate malloc pool
>for each thread, so that if one thread does a malloc and then another
>thread tries to free that address, you get the error?
Yes, that is exactly what happens. Each thread maintains its own heap
that can easily be discarded once the interpreter terminates. This
helps with memory leaks in persistent interpreters: you just discard and
reallocate the Perl interpreter. With a global heap you would have to
create a new process to clean up after any memory leaks.
>> ithreads when the interpreter context is wrong and a memory from the wrong
>> pool is allocated. This is all dandy, but it doesn't make it any easy to
>> find the place where the problem is, as it complains at the perl_destruct
>> stage. What would it take to make windows implementation complain about the
>> wrong pool when the variable is asking to allocate the memory, or
>> immediately after it, so the trace will pinpoint the place with a problem.
>>
>> I'm not familiar with the implementation but may be something like:
>> allocate the memory, then free it and then allocate again? will that work?
>
>I don't see how a scheme like that could possibly work. The only approach
>that I can think of is that under certain Perl builds (say ithreads +
>DEBUGGING), malloc/free are wrapped with functions that record the
>thread id (or something) at the start of each allocated block, and then
>throw a wobby if free is called and the tids don't match. This is
>roughly what I hacked together the last time I fixed such a bug (not
>being a windows hacker). Of course this doesn't provide for earlier
>detection, it just makes detection available across all platforms.
This is pretty much what happens on Windows. I'll now (today) hack up a
patch for util.c that will do the same on Unix.
Unfortunately you can't do early detection because you don't know which
THX is active during the call to free().
>The downside is that each malloc will use an extra 4+ bytes.
It will only be enabled by an additional preprocessor symbol, e.g.
-DTRACK_MEMPOOL
Cheers,
-Jan
>I think winFU perl can handle this issue better. I hope Jan will be able to
>comment on my suggestion, on doing this pool testing during the memory
>allocation and not during perl_destruct.
I have attached a patch (relative to Perl 5.8.3) that should reproduce
the "free to wrong pool" errors on Unix too if you build Perl with both
-DPERL_IMPLICIT_CONTEXT and -DPERL_TRACK_MEMPOOL.
Unfortunately there is no THX macro that expands to "PerlInterpreter*",
so I had to violate the encapsulation a little bit. If this gets
applied to core Perl, then we should probably add a macro for that.
Note that the error checking happens during freeing (or reallocating)
of the memory. Most often this happens at perl_destruct() time, but
not necessarily.
You may want to change the croak("panic: ..."); parts to something that
creates an access violation at that point. The Windows code in
win32/vmem.h does this:
int *nowhere = NULL;
*nowhere = 0;
to make sure Perl stops right there. :)
Here is a test program I used to check that the attached patch catches
the wrong free:
/* --------------------------------------------------------------- */
#include <EXTERN.h>
#include <perl.h>
int main()
{
char *argv[] = {"perl", "-e", "warn", NULL};
int argc = 3;
PerlInterpreter *my_perl1 = perl_alloc();
PerlInterpreter *my_perl2;
SV *sv;
perl_construct(my_perl1);
perl_parse(my_perl1, NULL, argc, argv, 0);
perl_run(my_perl1);
sv = Perl_newSVpv(my_perl1, "foo", 3);
warn(SvPVX(sv));
my_perl2 = perl_alloc();
perl_construct(my_perl2);
perl_parse(my_perl2, NULL, argc, argv, 0);
perl_run(my_perl2);
Perl_sv_free(my_perl2, sv);
perl_destruct(my_perl2);
perl_free(my_perl2);
Perl_set_context(my_perl1);
perl_destruct(my_perl1);
perl_free(my_perl1);
return 0;
}
/* --------------------------------------------------------------- */
Running it should produce this output:
Warning: something's wrong at -e line 1.
foo.
Warning: something's wrong at -e line 1.
panic: free from wrong pool.
Cheers,
-Jan
diff -u util.c.orig util.c
--- util.c.orig Mon Jan 19 19:45:59 2004
+++ util.c Wed Jan 21 15:49:31 2004
@@ -60,6 +60,9 @@
my_exit(1);
}
#endif /* HAS_64K_LIMIT */
+#if defined(PERL_IMPLICIT_CONTEXT) && defined(PERL_TRACK_MEMPOOL)
+ size += sizeof(aTHX);
+#endif
#ifdef DEBUGGING
if ((long)size < 0)
Perl_croak_nocontext("panic: malloc");
@@ -67,8 +70,13 @@
ptr = (Malloc_t)PerlMem_malloc(size?size:1); /* malloc(0) is NASTY on our system */
PERL_ALLOC_CHECK(ptr);
DEBUG_m(PerlIO_printf(Perl_debug_log, "0x%"UVxf": (%05ld) malloc %ld bytes\n",PTR2UV(ptr),(long)PL_an++,(long)size));
- if (ptr != Nullch)
+ if (ptr != Nullch) {
+#if defined(PERL_IMPLICIT_CONTEXT) && defined(PERL_TRACK_MEMPOOL)
+ *(PerlInterpreter**)ptr = aTHX;
+ ptr = (Malloc_t)((char*)ptr+sizeof(aTHX));
+#endif
return ptr;
+ }
else if (PL_nomemok)
return Nullch;
else {
@@ -104,6 +112,12 @@
if (!where)
return safesysmalloc(size);
+#if defined(PERL_IMPLICIT_CONTEXT) && defined(PERL_TRACK_MEMPOOL)
+ where = (Malloc_t)((char*)where-sizeof(aTHX));
+ size += sizeof(aTHX);
+ if (*(PerlInterpreter**)where != aTHX)
+ Perl_croak_nocontext("panic: realloc from wrong pool");
+#endif
#ifdef DEBUGGING
if ((long)size < 0)
Perl_croak_nocontext("panic: realloc");
@@ -114,8 +128,12 @@
DEBUG_m(PerlIO_printf(Perl_debug_log, "0x%"UVxf": (%05ld) rfree\n",PTR2UV(where),(long)PL_an++));
DEBUG_m(PerlIO_printf(Perl_debug_log, "0x%"UVxf": (%05ld) realloc %ld bytes\n",PTR2UV(ptr),(long)PL_an++,(long)size));
- if (ptr != Nullch)
+ if (ptr != Nullch) {
+#if defined(PERL_IMPLICIT_CONTEXT) && defined(PERL_TRACK_MEMPOOL)
+ ptr = (Malloc_t)((char*)ptr+sizeof(aTHX));
+#endif
return ptr;
+ }
else if (PL_nomemok)
return Nullch;
else {
@@ -131,11 +149,16 @@
Free_t
Perl_safesysfree(Malloc_t where)
{
-#ifdef PERL_IMPLICIT_SYS
+#if defined(PERL_IMPLICIT_CONTEXT) || defined(PERL_TRACK_MEMPOOL)
dTHX;
#endif
DEBUG_m( PerlIO_printf(Perl_debug_log, "0x%"UVxf": (%05ld) free\n",PTR2UV(where),(long)PL_an++));
if (where) {
+#if defined(PERL_IMPLICIT_CONTEXT) && defined(PERL_TRACK_MEMPOOL)
+ where = (Malloc_t)((char*)where-sizeof(aTHX));
+ if (*(PerlInterpreter**)where != aTHX)
+ Perl_croak_nocontext("panic: free from wrong pool");
+#endif
/*SUPPRESS 701*/
PerlMem_free(where);
}
@@ -161,11 +184,18 @@
Perl_croak_nocontext("panic: calloc");
#endif
size *= count;
+#if defined(PERL_IMPLICIT_CONTEXT) && defined(PERL_TRACK_MEMPOOL)
+ size += sizeof(aTHX);
+#endif
ptr = (Malloc_t)PerlMem_malloc(size?size:1); /* malloc(0) is NASTY on our system */
PERL_ALLOC_CHECK(ptr);
DEBUG_m(PerlIO_printf(Perl_debug_log, "0x%"UVxf": (%05ld) calloc %ld x %ld bytes\n",PTR2UV(ptr),(long)PL_an++,(long)count,(long)size));
if (ptr != Nullch) {
memset((void*)ptr, 0, size);
+#if defined(PERL_IMPLICIT_CONTEXT) && defined(PERL_TRACK_MEMPOOL)
+ *(PerlInterpreter**)ptr = aTHX;
+ ptr = (Malloc_t)((char*)ptr+sizeof(aTHX));
+#endif
return ptr;
}
else if (PL_nomemok)
>I think I can see two "extra" things that would be useful - the thread ID
You need to store the Perl "context", not the thread ID because multiple
interpreters can live on the same thread. If you interleave access to
them, you can end up with this problem too.
>(as you observe) and a pointer to create a linked list of memory blocks
>allocated under this thread. This way the implementation can free all the
>ithread's memory on ithread exit, which (as I understand it) is equivalent
>to what happens on Windows, but with the benefit that on x86/Linux while
>running under valgrind one will get access errors as soon as another
>ithread attempts to use the now-freed memory.
The freeing of memory at perl_destruct() time is not specific to
Windows, it happens on all platforms, depending on the value of
PL_destruct_level.
The difference on Windows is that all interpreter memory is allocated
from a "local" heap, which is discarded once perl_destruct finishes. So
if another thread allocates memory on it, it may get released to the OS
prematurely. Each interpreter must only hang on to memory allocated
from its own heap.
>I'm not sure of the best way to tweak the layers of obfuscation, er,
>indirection on perl's malloc() use to achieve this. Had someone kind
>at ActiveState volunteer to suggest an interface, or am I misremembering?
I volunteered (and still do) to fix the integer overflow problem for
Perl memory allocation. I still haven't done this, and it is a separate
problem.
>I'm happy to actually implement the guts, if spoon fed the interface
>interception stuff. (Foolish me for volunteering)
I think the patch I just submitted to Stas should allow him to reproduce
the "free to wrong pool" on Linux as well. I'll leave it to him to add
whatever additional diagnostics he needs to figure out where the
corresponding allocation happened. :)
Cheers,
-Jan
By winFU, I meant win[XP|95|NT|etc]. I'm used to people saying winFU when they
want to refer to 'any MS Windows OS'. I think it was Doug MacEachern from whom
I've heard it first.
> It will only be enabled by an additional preprocessor symbol, e.g.
>
> -DTRACK_MEMPOOL
It's -DPERL_TRACK_MEMPOOL according to your patch, sent in later. I'm going to
try it now. Thanks Jan.
All I can say: Jan Rocks!
Once I had Jan's patch inside perl, I've immediately reproduced the problems
that windows users had with modperl2 and shortly after that, we had them
fixed. This is after more than 4 months of mostly unsuccessful guesswork and
many wasted hours.
Thanks to this patch I was also able to reproduce the problem with Storable
2.09 to which I've posted a patch a few days ago.
So what does it take to integrate Jan's patch into the core?
I think it should not be optional with -DPERL_TRACK_MEMPOOL, but be there with
-DDEBUGGING. Since it shows real problems which just happen not to show
themselves right away on the current implementation on unix. As more people
start using ithreads (and with modperl 2.0 many will do that soon) we will see
more problems reported on unix, and they will be very hard to reproduce w/o
this alerting feature provided by perl on windows and now ported to unix by Jan.
My only remaining wish is for someone to figure out how to alert on these
wrong context usage problems when they happen and not during the destruct, to
make the debugging so much easier. I understand that this is probably not so
doable. :( At the moment when this kind of problem happens you really have to
guess where the cause is. The best scenario is when you code and test
incrementally and then you know that when you added something new and it
started to fail you hopefully know where the problem is. or may be not, as the
new code could trigger a problem elsewhere.
p.s. to build with Jan's patch, configure perl with something like:
./Configure -des -Dprefix=/whereever/perl-with-jan-patch \
-Dusethreads -Doptimize='-g' -Duseshrplib -Dusedevel \
-Accflags="-DPERL_IMPLICIT_CONTEXT -DPERL_TRACK_MEMPOOL"
to build Jan's test script (assuming that you save it in pool.c) do:
% gcc -o pool pool.c `perl-with-jan-patch -MExtUtils::Embed -e ccopts -e
ldopts` -Wall -g
then run:
% ./pool
Hmmm.... I always thought the generic term was Win32? As opposed to
Win16 (Windows 3.X and lower) who nobody van remember anymore
(fortunately)... ;-)
Liz
Aren't we going to see win64 soon?
Exactly. And that's going to have its own set of problems. And
including WinFU in that, would be confusing... ;-)
Liz
>My only remaining wish is for someone to figure out how to alert on these
>wrong context usage problems when they happen and not during the destruct, to
>make the debugging so much easier. I understand that this is probably not so
>doable. :(
It is probably impossible to add comprehensive checks for this, but we
_could_ incrementally add checks for all usage patterns that have at
least once triggered the problem.
I've tried to create the support necessary to do this. It is more work
than I thought it would be and I'm running out of time now. I've attached
a patch that will catch all cases where you reallocate the PVX via sv_grow()
from the wrong pool.
One problem is that Perl always uses an arena to allocate SVs, even when
you compile with -DPURIFY. To be able to check the owner of an SV we need
to allocate them individually from the heap. There are also a couple of SVs
that are not SV*s, but structs directly embedded in a bigger struct
(PL_sv_yes etc, PERL_DEBUG_PAD). If we add ownership checks, these SVs
must never go through that code. A better solution would be to allocate
*all* SVs from the heap.
The attached patch still fails various core regressions tests and is not
very clean, but it catches this bug:
/* ---------------------------------------------------- */
#include <EXTERN.h>
#include <perl.h>
void foo(pTHX_ SV *sv) {
/* stringification will allocate a PVX from the wrong pool */
warn(SvPV_nolen(sv));
}
int main()
{
char *argv[] = {"perl", "-e", "warn", NULL};
int argc = 3;
PerlInterpreter *my_perl1 = perl_alloc();
PerlInterpreter *my_perl2;
SV *sv;
perl_construct(my_perl1);
perl_parse(my_perl1, NULL, argc, argv, 0);
perl_run(my_perl1);
sv = Perl_newSViv(my_perl1, 42);
/* make sure sv_2pv() won't upgrade the SV itself. Otherwise we
* won't even reach the part where the PVX is updated.
*/
Perl_sv_upgrade(my_perl1, sv, SVt_PVNV);
my_perl2 = perl_alloc();
perl_construct(my_perl2);
perl_parse(my_perl2, NULL, argc, argv, 0);
perl_run(my_perl2);
foo(my_perl2, sv);
Perl_set_context(my_perl1);
perl_destruct(my_perl1);
perl_free(my_perl1);
Perl_set_context(my_perl2);
perl_destruct(my_perl2);
perl_free(my_perl2);
return 0;
}
/* ---------------------------------------------------- */
I won't have time to work on this anytime soon, so if you think this will
help finding mod_perl problems, please run with it and turn it into a
proper patch. :) Also add checks that would catch all the mod_perl
problems related to this that you have already found and fixed. :)
Note that you have to compile with -DPURIFY if you want to insert
CHECK_MEMPOOL() calls on SV bodies (XIV, XNV etc) and not just on
the SVs or PVXs.
Cheers,
-Jan
The patch requires installation of my earlier "free to wrong pool" patch.
I would also recommend to change the Perl_croak_nocontext() calls in that
previous patch to the method used in CHECK_MEMPOOL() below.
diff -u perl.h.orig perl.h
--- perl.h.orig Mon Jan 19 19:45:50 2004
+++ perl.h Thu Jan 22 10:43:52 2004
@@ -122,6 +122,18 @@
# define pTHX_2 3
# define pTHX_3 4
# define pTHX_4 5
+# if defined(PERL_TRACK_MEMPOOL)
+# define CHECK_MEMPOOL(p) \
+ if (*(PerlInterpreter**)((char*)p-sizeof(aTHX)) != aTHX) { \
+ int *nowhere = NULL; \
+ Perl_warn(aTHX_ "panic: modifying memory from wrong pool"); \
+ *nowhere = 0; \
+ }
+# endif
+#endif
+
+#ifndef CHECK_MEMPOOL
+# define CHECK_MEMPOOL(p)
#endif
#define STATIC static
diff -u perl.c.orig perl.c
--- perl.c.orig Mon Jan 19 19:45:50 2004
+++ perl.c Thu Jan 22 11:14:52 2004
@@ -155,6 +155,23 @@
=cut
*/
+#if defined(PERL_IMPLICIT_SYS) && defined(PERL_TRACK_MEMPOOL)
+STATIC void
+S_sv_initpv(pTHX_ SV *sv, const char *ptr)
+{
+ STRLEN len = strlen(ptr);
+ sv_upgrade(sv, SVt_PV);
+ New(703, SvPVX(sv), len+1, char);
+ Move(ptr, SvPVX(sv), len+1, char);
+ SvCUR(sv) = len;
+ SvLEN(sv) = len+1;
+ SvPOK_only_UTF8(sv);
+}
+# define sv_initpv(sv, ptr) S_sv_initpv(aTHX_ sv, ptr)
+#else
+# define sv_initpv(sv, ptr) sv_setpv(sv, ptr)
+#endif
+
void
perl_construct(pTHXx)
{
@@ -210,12 +227,12 @@
SvREADONLY_on(&PL_sv_undef);
SvREFCNT(&PL_sv_undef) = (~(U32)0)/2;
- sv_setpv(&PL_sv_no,PL_No);
+ sv_initpv(&PL_sv_no,PL_No);
SvNV(&PL_sv_no);
SvREADONLY_on(&PL_sv_no);
SvREFCNT(&PL_sv_no) = (~(U32)0)/2;
- sv_setpv(&PL_sv_yes,PL_Yes);
+ sv_initpv(&PL_sv_yes,PL_Yes);
SvNV(&PL_sv_yes);
SvREADONLY_on(&PL_sv_yes);
SvREFCNT(&PL_sv_yes) = (~(U32)0)/2;
@@ -276,9 +293,9 @@
PL_fdpid = newAV(); /* for remembering popen pids by fd */
PL_modglobal = newHV(); /* pointers to per-interpreter module globals */
PL_errors = newSVpvn("",0);
- sv_setpvn(PERL_DEBUG_PAD(0), "", 0); /* For regex debugging. */
- sv_setpvn(PERL_DEBUG_PAD(1), "", 0); /* ext/re needs these */
- sv_setpvn(PERL_DEBUG_PAD(2), "", 0); /* even without DEBUGGING. */
+ sv_initpv(PERL_DEBUG_PAD(0), ""); /* For regex debugging. */
+ sv_initpv(PERL_DEBUG_PAD(1), ""); /* ext/re needs these */
+ sv_initpv(PERL_DEBUG_PAD(2), ""); /* even without DEBUGGING. */
#ifdef USE_ITHREADS
PL_regex_padav = newAV();
av_push(PL_regex_padav,(SV*)newAV()); /* First entry is an array of empty elements */
diff -u sv.c.orig sv.c
--- sv.c.orig Mon Jan 19 19:45:53 2004
+++ sv.c Thu Jan 22 11:18:24 2004
@@ -170,6 +170,21 @@
} STMT_END
+#if defined(PERL_IMPLICIT_CONTEXT) && defined(PERL_TRACK_MEMPOOL)
+STATIC SV*
+S_new_SV()
+{
+ SV* sv = safemalloc(sizeof(SV));
+ SvANY(sv) = 0;
+ SvREFCNT(sv) = 1;
+ SvFLAGS(sv) = 0;
+ return sv;
+}
+
+# define new_SV(p) (p)=S_new_SV()
+# define del_SV(p) safefree((char*)p)
+#else
+
/* new_SV(): return a new, empty SV head */
#ifdef DEBUG_LEAKING_SCALARS
@@ -253,6 +268,7 @@
#endif /* DEBUGGING */
+#endif
/*
=head1 SV Manipulation Functions
@@ -1633,6 +1649,7 @@
SvFAKE_off(sv);
SvREADONLY_off(sv);
}
+ CHECK_MEMPOOL(sv);
New(703, s, newlen, char);
if (SvPVX(sv) && SvCUR(sv)) {
Move(SvPVX(sv), s, (newlen < SvCUR(sv)) ? newlen : SvCUR(sv), char);
@@ -10603,6 +10620,23 @@
proto_perl->IProc);
}
+#if defined(PERL_IMPLICIT_SYS) && defined(PERL_TRACK_MEMPOOL)
+STATIC void
+S_sv_initpv(pTHX_ SV *sv, const char *ptr)
+{
+ STRLEN len = strlen(ptr);
+ sv_upgrade(sv, SVt_PV);
+ New(703, SvPVX(sv), len+1, char);
+ Move(ptr, SvPVX(sv), len+1, char);
+ SvCUR(sv) = len;
+ SvLEN(sv) = len+1;
+ SvPOK_only_UTF8(sv);
+}
+# define sv_initpv(sv, ptr) S_sv_initpv(aTHX_ sv, ptr)
+#else
+# define sv_initpv(sv, ptr) sv_setpv(sv, ptr)
+#endif
+
PerlInterpreter *
perl_clone_using(PerlInterpreter *proto_perl, UV flags,
struct IPerlMem* ipM, struct IPerlMem* ipMS,
@@ -10818,9 +10852,9 @@
#endif
PL_encoding = sv_dup(proto_perl->Iencoding, param);
- sv_setpvn(PERL_DEBUG_PAD(0), "", 0); /* For regex debugging. */
- sv_setpvn(PERL_DEBUG_PAD(1), "", 0); /* ext/re needs these */
- sv_setpvn(PERL_DEBUG_PAD(2), "", 0); /* even without DEBUGGING. */
+ sv_initpv(PERL_DEBUG_PAD(0), ""); /* For regex debugging. */
+ sv_initpv(PERL_DEBUG_PAD(1), ""); /* ext/re needs these */
+ sv_initpv(PERL_DEBUG_PAD(2), ""); /* even without DEBUGGING. */
/* Clone the regex array */
PL_regex_padav = newAV();
% bench /home/stas/perl/5.8.3-ithread/bin/perl5.8.3
/home/stas/perl/5.8.3-ithread-pool/bin/perl5.8.3
A) perl-5.008003
path = /home/stas/perl/5.8.3-ithread/bin/perl5.8.3
cc = cc
optimize = -g
ccflags = -D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS
-DDEBUGGING -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE
-D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm
usemymalloc = n
B) perl-5.008003
path = /home/stas/perl/5.8.3-ithread-pool/bin/perl5.8.3
cc = cc
optimize = -g
ccflags = -D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS
-DPERL_IMPLICIT_CONTEXT -DPERL_TRACK_MEMPOOL -DDEBUGGING -fno-strict-aliasing
-I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
-I/usr/include/gdbm
usemymalloc = n
A B
---- ----
arith/mixed 100 114
arith/trig 100 102
array/copy 100 124
array/foreach 100 110
array/index 100 147
array/pop 100 104
array/shift 100 107
array/sort-num 100 94
array/sort 100 98
call/0arg 100 104
call/1arg 100 98
call/2arg 100 103
call/9arg 100 95
call/empty 100 100
call/fib 100 98
call/method 100 121
call/wantarray 100 108
hash/copy 100 102
hash/each 100 106
hash/foreach-sort 100 112
hash/foreach 100 113
hash/get 100 106
hash/set 100 106
loop/for-c 100 114
loop/for-range-const 100 130
loop/for-range 100 123
loop/getline 100 105
loop/while-my 100 152
loop/while 100 97
re/const 100 103
re/w 100 103
startup/fewmod 100 99
startup/lotsofsub 100 87
startup/noprog 100 101
string/base64 100 105
string/htmlparser 100 111
string/index-const 100 153
string/index-var 100 113
string/ipol 100 125
string/tr 100 101
AVERAGE 100 110
For this patch to go "mainstream", one of things it would need to handle
is alignment constraints. For example on SPARC in 32-bit mode, pointers
are 4 bytes, doubles are 8 bytes, and doubles must be be aligned on an
8-byte boundary. The Solaris malloc() will always return addresses aligned
on an 8-byte boundary; adding sizeof(aTHX) and returning it would hand the
application a pointer which can't hold arbitrary data. Eg the following
gives a bus fault on SPARC:
char *p = (char *)malloc(sizeof(void*) + sizeof(double));
if (!p) exit(0);
p+=sizeof(void *);
*((double *)p) = 1.1;
--
To collect all the latest movies, simply place an unprotected ftp server
on the Internet, and wait for the disk to fill....
> I won't have time to work on this anytime soon, so if you think this will
> help finding mod_perl problems, please run with it and turn it into a
> proper patch. :) Also add checks that would catch all the mod_perl
> problems related to this that you have already found and fixed. :)
>
> Note that you have to compile with -DPURIFY if you want to insert
> CHECK_MEMPOOL() calls on SV bodies (XIV, XNV etc) and not just on
> the SVs or PVXs.
>
> Cheers,
> -Jan
>
> The patch requires installation of my earlier "free to wrong pool" patch.
> I would also recommend to change the Perl_croak_nocontext() calls in that
> previous patch to the method used in CHECK_MEMPOOL() below.
unfortunately I can't even build perl with this patch (I didn't use -DPURIFY),
but:
./Configure -des -Dprefix=/home/stas/perl/5.8.3-ithread-pool \
-Dusethreads -Doptimize='-g' -Duseshrplib -Dusedevel \
-Accflags="-DPERL_IMPLICIT_CONTEXT -DPERL_TRACK_MEMPOOL"
It fails to build miniperl:
% make
....
LD_LIBRARY_PATH=/home/stas/perl.org/perl-5.8.3
/home/stas/perl.org/perl-5.8.3/preload
/home/stas/perl.org/perl-5.8.3/libperl.so cc -L/usr/local/lib -o miniperl \
miniperlmain.o opmini.o libperl.so -lnsl -ldl -lm -lcrypt -lutil
-lpthread -lc
panic: modifying memory from wrong pool.
make: *** [miniperl] Segmentation fault
the preloaded libperl.so causes that, e.g I get the same with just calling cc:
env LD_LIBRARY_PATH=/home/stas/perl.org/perl-5.8.3
/home/stas/perl.org/perl-5.8.3/preload
/home/stas/perl.org/perl-5.8.3/libperl.so cc
panic: modifying memory from wrong pool.
Segmentation fault (core dumped)
>Jan Dubois wrote:
>
>> I won't have time to work on this anytime soon, so if you think this will
>> help finding mod_perl problems, please run with it and turn it into a
>> proper patch. :) Also add checks that would catch all the mod_perl
>> problems related to this that you have already found and fixed. :)
>>
>> Note that you have to compile with -DPURIFY if you want to insert
>> CHECK_MEMPOOL() calls on SV bodies (XIV, XNV etc) and not just on
>> the SVs or PVXs.
>>
>> Cheers,
>> -Jan
>>
>> The patch requires installation of my earlier "free to wrong pool" patch.
>> I would also recommend to change the Perl_croak_nocontext() calls in that
>> previous patch to the method used in CHECK_MEMPOOL() below.
>
>unfortunately I can't even build perl with this patch (I didn't use -DPURIFY),
>but:
Weird, it worked for me on Windows...
I looked at the patch again and noticed at least 2 problems:
1) add a check for PERL_IMPLICIT_CONTEXT here:
| diff -u perl.h.orig perl.h
| --- perl.h.orig Mon Jan 19 19:45:50 2004
| +++ perl.h Thu Jan 22 10:43:52 2004
| @@ -122,6 +122,18 @@
| # define pTHX_2 3
| # define pTHX_3 4
| # define pTHX_4 5
| +# if defined(PERL_TRACK_MEMPOOL)
should be:
# if defined(PERL_TRACK_MEMPOOL) && defined(PERL_IMPLICIT_CONTEXT)
| +# define CHECK_MEMPOOL(p) \
| +
2) the patch contained a few "defined(PERL_IMPLICIT_SYS)" checks. They
should have been testing PERL_IMPLICIT_CONTEXT instead.
Cheers,
-Jan
Thanks, Jan. Plus one more:
3) this part:
diff -u sv.c.orig sv.c
--- sv.c.orig Mon Jan 19 19:45:53 2004
+++ sv.c Thu Jan 22 11:18:24 2004
@@ -170,6 +170,21 @@
} STMT_END
[...]
+#if defined(PERL_IMPLICIT_CONTEXT) && defined(PERL_TRACK_MEMPOOL)
+STATIC void
+S_sv_initpv(pTHX_ SV *sv, const char *ptr)
+{
+ STRLEN len = strlen(ptr);
+ sv_upgrade(sv, SVt_PV);
+ New(703, SvPVX(sv), len+1, char);
+ Move(ptr, SvPVX(sv), len+1, char);
+ SvCUR(sv) = len;
+ SvLEN(sv) = len+1;
+ SvPOK_only_UTF8(sv);
+}
+# define sv_initpv(sv, ptr) S_sv_initpv(aTHX_ sv, ptr)
+#else
+# define sv_initpv(sv, ptr) sv_setpv(sv, ptr)
+#endif
+
needs to be moved one function up, before perl_clone definition. before I did
that I was getting undefined symbol sv_initpv.
But 'make test' hangs in the closure.t test. Did all tests pass for you, Jan?
On Sat, 24 Jan 2004 17:31:57 -0800, Stas Bekman <st...@stason.org> wrote:
>Thanks, Jan. Plus one more:
>
>3) this part:
[...]
>needs to be moved one function up, before perl_clone definition. before I did
>that I was getting undefined symbol sv_initpv.
Yes, I see, it needs to be outside the #ifdef PERL_IMPLICIT_SYS, which
is only defined on Windows. Sorry about that.
>But 'make test' hangs in the closure.t test. Did all tests pass for you, Jan?
No, they don't:
| The attached patch still fails various core regressions tests and is not
| very clean, but it catches this bug:
That's what I meant by "I'm running out of time" as I can tell how much
effort may be needed to get this working somewhat cleanly.
I'm not sure if this is really worth the effort. If you only add the
part that allocates and frees SVs from the heap instead of using the
arena, then you should already catch all cases where an SV is upgraded
because the Safefree() of the old any pointer will already trigger an
error. That may be enough to catch most problems immediately.
Cheers,
-Jan
Oops, sorry about that.
> That's what I meant by "I'm running out of time" as I can tell how much
> effort may be needed to get this working somewhat cleanly.
I understand.
> I'm not sure if this is really worth the effort. If you only add the
> part that allocates and frees SVs from the heap instead of using the
> arena, then you should already catch all cases where an SV is upgraded
> because the Safefree() of the old any pointer will already trigger an
> error. That may be enough to catch most problems immediately.
I haven't really had chance to look at what your patches do yet. I have just
used your first patch and it worked great. I need to take time to grok the
change. I guess we could try and see first how can we get that part it in,
taking into account Dave Mitchell's comments about the alignment constraints.
IIRC There's no official guarantee in C about which type is largest, or
which type has what alignment constraints.
I spot
/* MEM_ALIGNBYTES:
* This symbol contains the number of bytes required to align a
* double, or a long double when applicable. Usual values are 2,
* 4 and 8. The default is eight, for safety.
*/
in config.h, but as it's
#if defined(USE_CROSS_COMPILE) || defined(MULTIARCH)
# define MEM_ALIGNBYTES 8
#else
#define MEM_ALIGNBYTES 4
#endif
I don't think that it's correct. (What's the long double alignment constraint
on Solaris?)
Would something like sizeof() a union of the thread data, a long double
and a pointer be good enough to get the alignment constraint on practically
every system?
Nicholas Clark
I think you'd want more something like:
struct {
aTHX base,
union { long double d, void *p, .... } first
}
and make the increment the difference in address between base and first.
--
Please note that ash-trays are provided for the use of smokers,
whereas the floor is provided for the use of all patrons.
-- Bill Royston