We have some C code we wrote years ago that embeds some functionality from the Triangle library into Yorick. Reviewing that code today, I noticed two things that are probably very bad:

1. Our "glue" code calls malloc and free directly for the data passed in and out of triangle. (But only for things that are temporary for the lifetime of that function call; the result it returns correctly uses ypush_l.)2. The Triangle code has functions trimalloc and trifree that likewise call malloc and free directly; it uses these functions internally.

The comments in yapi.h suggest this is very bad because Yorick doesn't know about those mallocs and thus it can lead to memory leaks. It suggests using ypush_scratch, which I discovered wraps around p_malloc. I also found references to p_free. I couldn't find where either one was defined though.

The Triangle library suggests that you can implement your own trimalloc and trifree if you have advanced memory handling needs. That would seem to be the case here.

My question is, should I use ypush_scratch or should I use p_malloc+p_free? It doesn't seem like you are supposed to directly free the memory created by ypush_scratch, which makes that seem problematic for use here. So I was leaning towards using p_malloc and p_free in place of malloc and free, but I wasn't sure if that would introduce any problems.

(Apologies if this is a fairly dumb question, I'm not that well versed with C coding.)

The only thing you may want to guard against is some bozo hitting control-C during your Triangle routine, after your malloc and before your free. I tried to write yorick so that, as nearly as possible, it could be asynchronously interrupted at any point and recover without leaking memory or otherwise damaging the interpreter. Of course, this is not really possible; the best I can do is to make the "critical sections" where an asynchronous interrupt will do serious damage a very small fraction of the code. I try to store any state information required to recover from asynchronous interrupt on the interpreted stack via ypush_scratch or some equivalent -- ypush_scratch is a sort of yorick-package equivalent of the (non-portable) system alloca function: it gets you working space without you having to worry about explicitly freeing it when you are done. (Although you have to be careful to call ypush_l or whatever you use to create the return value after any ypush_scratch calls.)

There is no difference between malloc/free and p_malloc/p_free as far as memory leaks are concerned; ypsuh_scratch is what you want.

However, there are innumerable third party libraries (and even libc and libm, possibly) which call malloc/free to get working space internally inside complicated API functions. The big ones yorick uses are all the graphics libraries like X11 or OpenGL. All such libraries are very fragile when it comes to asynchrous interrupts, which can permanently damage the library for all future calls, if the interrupt happens at a time that its internal state information is inconsistent. So your Triangle package is just as safe or safer than any of those -- which is just fine for everyday usage. Unless you have some other reason you want to rewrite your code, I wouldn't recommend switching working malloc/free-based code to new ypush_scratch-based code, which you will then need to debug.

To handle the fact that so many third party libraries are fragile with respect to asynchronous interrupts, I added one additional feature to yorick (somewhere in the 1.6 branch, I think): When you hit control-C or otherwise send SIGINT to asynchronously interrupt yorick, it does not interrupt immediately. Instead it sets a flag p_signalling (see play.h) and a one second timer, then continues execution from the point of the interrupt, so that the interrupted code continues executing. If yorick ever gets control back (for example, if the SIGINT is delivered while your Triangle function is executing, when your function returns and interpreted the interpreted code that called it resumes), it notices p_signalling is set, cancels the timer, and handles the interrupt safely. Thus, it is only functions which run for longer than one second (wall time) that are at any risk at all of suffering an asynchronous longjump out of the middle of them, which would leak memory if it happened between the malloc and free. So as long as a single call to your Triangle function can never take longer than one wall second to execute, it is completely safe for it to use malloc/free. If there is some circumstance in which a single call could take more than one wall second, then you would be safer to use ypush_scratch to get temporary working space.

All of this may sound a bit paranoid, and I'm sure I've taken it to meaningless levels of "safety" in many places. The truth is, there are many ways yorick can be damaged by bizarre sequences of interruptions and other events. Nevertheless, you want to spend a little time thinking about what happens when your code just stops executing at any random point, the stack resets, and yorick attempts to keep running. How much state information is implicit inside of your subroutine (by where the program counter is, as well as any automatic variables)? What happens if that state information is unexpectedly lost through nothing your function does, but by just stopping in the middle and losing it all?

Mon Feb 25, 2013 7:48 pm

dnagle

Yorick Master

Joined: Wed Jun 01, 2005 11:34 amPosts: 112

Re: ypush_scratch, p_malloc, p_free

Thanks for the explanations. I'll leave our Triangle code as is then, but this will be helpful to know for future work.

Who is online

Users browsing this forum: No registered users and 1 guest

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum