-
Notifications
You must be signed in to change notification settings - Fork 559
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Safefree() in a win32 “subprocess” blows up the process #17407
Comments
It's not a bug, it was implemented that way on purpose. The whole point of the "Free to wrong pool" error is to tell you that a wrong thread is freeing the memory. Whether it makes sense or not is a different question. Personally, I'm not familiar enough with that code to have an opinion. |
@xenu So are all XSUBs then on the hook to detect when they’re in a pseudo-subprocess and forgo Safefree(), then? I thought the notion of Safefree() was to abstract away details like that … |
I don't think that the people who wrote this still around. I have also been bitten by this, and resorted to using PerlMemShared_malloc and friends, but it's quite unhelpful. I had assumed it's because perl is using My second guess is that it prevents memory leaks from pseudo-fork processes to affect the other "processes", but in that case it's really not worth the hassle IMO. You could try to compile perl with this patch, and see if anything breaks (I suspect not)
|
BTW, note that this behavior is not specific to Windows. Unix perls built with |
I believe AmigaOS port has pseudoprocesses too, but their implementation is completely separate from the Windows one and I have no idea how it works. |
I think this needs documentation rather than a code change. I had thought this was documented, but I don't see anything. In general if you want memory that isn't tied to the current thread you should be using safesysmalloc()/safesysrealloc()/safesysfree(). |
But is there any reason for this behavior? Because quite frankly I've only seen it get in the way of things. |
@tonycoz These functions are undocumented … should they be added to perlapi/perlclib? |
it has bitten me before too (which is why most of Imager avoids the perl headers, since malloc() is redefined to PerlMem_malloc() on Win32). I guess it depends on why it was added, if we do look at removing it I think it needs to be discussed on the list rather than just in this ticket, so whoever added it has an opportunity to defend it. |
Yes. |
On Sun, Jan 05, 2020 at 06:58:56PM -0800, Tony Cook wrote:
I guess it depends on why it was added, if we do look at removing it I
think it needs to be discussed on the list rather than just in this
ticket, so whoever added it has an opportunity to defend it.
My recollection is that (at the time, at least: 2005), Windows would give a
"free to wrong pool" error if memory malloc()ed by one thread was free()d
by another thread. Jan DuBois then added a mechanism (by default only
enabled on DEBUGGING+PERL_IMPLICIT_CONTEXT builds) that on *all* platforms
recorded thread info with each allocation, and croaked if freed in a
different thread - thus helping non-Windows coders like myself from
introducing bugs that tested fine on Linux.
The thread where it was introduced is here:
http://nntp.perl.org/group/perl.perl5.porters/106649
malloc() on Linux appears thread-safe and includes mechanisms to reduce lock
contention. I don't know about other OSes.
…--
Justice is when you get what you deserve.
Law is when you get what you pay for.
|
TBH that sounds to me like a case of " No, it is not a compiler error. It is never a compiler error." I really don't believe that |
This is produced by perl, not the underlying malloc() implementation, see https://github.com/Perl/perl5/blob/blead/win32/vmem.h#L199 Both shared and "system" memory end up being allocated/freed with malloc()/free(), with shared memory having a VMem object and each thread having their own VMem objects. I suspect the intent was to allow fork emulation to clean up all of the (perl) allocated memory from a child thread, but I'm only guessing here. This comes with a fair amount of overhead on Win32, even on non-debug builds, each memory block has a next and prev pointers for the double-linked list (8-16 bytes), and extra locking (which the underlying malloc() also presumably already does.) I'm inclined to remove this, but I'd rather not do it blindly. |
Yep, libperl is "supposed" to support being unloaded without leaking. "supposed" to is because I've never heard of anyone embedding perl on win32 but i didnt google it. There are 3 memory pools in Next Win32 Perl memory "design requirement". There are or were dumptrucks worth of CPAN XS code, 100s of modules, that are perl thread-unaware/my_perl ptr unaware/OS thread pool unaware. Perl 5.0 5.6 5.8 era, specifically where perl thread was a concept and 5.005 threads or whatever it was called. Even in 5.10-5.12 era, fresh CPAN modules get written, pass their C func ptr "callback" to a foreign C lib, usually Microsoft or OS vendor DLL. And then their C func starts being called from "thread pools". It doesnt crash on his single thread linux perl (crashes instant multi thread Linux perl), so that module author is clueless about threads and perl. module author on his bug tracker often is shocked to hear about "threads" and perl. There are devs who wrote large 30 screenfull long XS libs, and had no clue about my_perl ptr or threads for months or years until a Win32 user came by. 4th design requirement, WinOS has 12 different incompatible msvcrts/"libc"s. with upto 12 incompatible memory pools worst case. Its always UB to pass malloc blocks from "one pool" as defined by upstream official API docs. to free those malloc blocks with the free() fnc of another same proc same Vm space pool. Even I use a decompiler on my own system and see what malloc backends are technical/engineering identical on my system. Any random monthly OS security update can replace a malloc backend at random in any DLL. OS vendor privilege because it was API doced as not allowed to pass ptrs between memory pools. Perl's Vmem.h is overengineered, bloated by wrapping 16 byte headers on each mem block. Win NT solved the problem 30 years ago with https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapcreate API. Anyone, any dll, has their own private "copy paste" safe/well engineered/not hand made malloc pool any time they want. Now everyone has the API features to do perfect clean leak free DLL runtime unloading. https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapdestroy BOOM Now your code is leak free even if that dev is incompetent and the process linear grows 10 MB a minute until OOM and that dev is apathetic or unaware. Just centally nuke your malloc pool on a timer. Perl really really needs to use the raw native MS malloc apis and stop this nonsense of in-house less than perfect feature emulation of Heap* native MS APIs. Vmem.h is from Sarathy era, and probably "Win32S" (~WINE) for Win16 was missing Heap*() APIs. I just checked my Kernel32.dll from Win95. I have the full WinNt Heap*() API available in Win95. I truly don't know why native HeapAlloc(), wasn't NOT used by Sarathy. So Win32 PL's terrible malloc design is 50% "assert" -DDEBUGGING code accidentally left on forever. 25% power struggle inside P5P over Hungarian notation variables 25% billable hours to your employer Note Vmem.h is almost completely re implemented with lower case POSIX variables at https://github.com/Perl/perl5/blob/blead/util.c#L189C3-L189C26 IDK who code came first, but thats clearly an ego battle inside p5p jkjk Now, I finally I did benchmark Perl and UCRT/MSVCRT bloat vs native Win32 OS malloc. Confirms what I've known for years. I'm shocked. Perl's Win32 malloc func call/FRONTEND is 2.8X SLOWER than the OS's front end. Win32 QueryPerfCounter was used.
|
Description
Safefree() in a win32 “subprocess” misbehaves when memory was first allocated in “parent”.
Steps to Reproduce
On Win32: Clone https://github.com/FGasper/p5-win32-safefree-bug, then
perl Makefile.PL && gmake && perl -Mblib t\detect_memory_leaks.t
.Expected behavior
The test should finish, as it does in Linux. Instead it fails with “Free to wrong pool …”.
Perl configuration
Strawberry 5.30.1 64-bit …
The text was updated successfully, but these errors were encountered: