develooper Front page | perl.perl5.porters | Postings from July 2014

[perl #122112] refcnt: fd -1 < 0 with MIME::Lite

From:
Tony Cook via RT
Date:
July 17, 2014 01:40
Subject:
[perl #122112] refcnt: fd -1 < 0 with MIME::Lite
Message ID:
rt-4.0.18-3182-1405561202-105.122112-15-0@perl.org
On Tue Jul 08 03:02:17 2014, vsespb wrote:
> On Mon Jul 07 16:35:06 2014, tonyc wrote:
> > On Mon Jul 07 12:48:51 2014, vsespb wrote:
> > > So instead
> > >
> > > if (fd < 0) {
> > >       /* the handle has already been closed */
> > >       return -1;
> > > }
> > >
> > > Perl_my_pclose should continue and run wait4pid loop, but
> > > PerlIO_close
> > > should be skipped.
> >
> > Without the original fd we can't look up the pid to wait on.
> >
> 
> We need make function re-entrant. Can save PID for later user in
> global varibale.
> 
> > We can't re-order the close/wait to wait/close, since if we're
> > writing
> > to the child, it may be waiting for EOF (eg. a filter) before
> > exiting.
> >
> yes, right.
> 
> 
> Here is prototype. All tests pass and original problem fixed.
> 
...
> 
> but real patch should also keep relation between PID and FH and work
> even if my_close(FILE1) called but then my_close(FILE2) called from
> inside signal handler.

Another problem I can see with the current my_pclose() code - the second time we enter my_pclose() for our sample code, the PerlIO object has already been freed by PerlIO_close(), so we're accessing a freed object.  Because of the way PerlIO allocates memory, this isn't picked up by valgrind.

I can think of a few different possibilities to fix the problem:

a) implement a half-close operation for PerlIO that closes the handle but doesn't release the PerlIO object.  my_pclose() would half-close the object, perform the wait, then do the full close which releases the PerlIO object.  I'm not sure how much work this is.

b) keep a linked list (or other structure, but hopefully we don't have a lot of them) of closing-in-progress pipe PerlIO handles, my_pclose() checks if the handle is on the list. If it is, it bypasses the PerlIO_close(), if not, call PerlIO_close() and add an entry to the list with the PerlIO object pointer[1] and pid.  After the wait() loop is complete remove the entry from the list.  I think this might be the correct solution.  Locking may need to be an issue as the linked list needs to be visible cross-thread as some handles are visible cross-thread.  This is the multi-handle version of your solution.

c) implement something close to the vms/vms.c implementation of my_popen()/my_pclose() which keeps a fairly complex data structure for each pipe.  Overkill here I think.

Tony

[1] this is undefined behaviour, but less so than following the pointer, I expect

---
via perlbug:  queue: perl5 status: open
https://rt.perl.org/Ticket/Display.html?id=122112



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About