longjmp()

Niels Möller nisse at lysator.liu.se
Thu Mar 6 20:22:38 UTC 2014


David Warme <David at Warme.net> writes:

> I am posting this to gmp-devel (instead of gmp-discuss) because it
> concerns very arcane GMP implementation details.
> Another possibility is that blocks allocated using the TMP_DECL,
> TMP_MARK, and TMP_FREE mechanisms (if too large for alloca())
> would not (automatically) be freed when calling longjmp().

Right, the tricky thing is to do the cleanup which deallocates precisely
the right blocks. I think I've written about this once before, not too
many months ago, but I can't find it now (possibly it was some
guile-related discussion). I think the following would be a safe way to
trap memory allocation from any gmp function. As an example, I consider
only a single gmp function, mpz_mul:

int 
safe_mpz_mul (mpz_t r, const mpz_t a, const mpz_t b)
{
  mpz_t t;

  ... set a mark in the memory allocation machinery ...

  if (setjmp (buf)) /* buf here is some global belonging to allocation
                       machinery */
    {
      /* Error case */
      ... deallocate everything allocated later than the above mark ...
      /* This work could be done by the memory allocation failure code,
	 before calling longjmp. I put it here to illustrate which case
	 it belongs to. */ 
      return FAIL;
    }
  else
    { 
      /* The normal case, which might longjmp out in the middle of
         some operation due to allocation failure. */
      mpz_init (t);
      mpz_mul (t, a, b);
    }
  mpz_swap (r, t); /* Safe, because no allocation is involved. */
  mpz_clear (t);   /* Deallocation, also safe. */

  return SUCCESS;
}

The idea here is that in the code block "protected" by the setjmp, the
mpz_t variables are partitioned into two sets:

1. Variables which are allocated outside of the block. They can be used
   *only* as read-only inputs to mpz functions. This guarantees that
   they will not be reallocated, and they will therefore be untouched by
   the deallocation cleanup done in the failure case. Note that this set
   includes the ultimate result parameter, r. Hence the little dance
   with mpz_swap before returning.

2. Variables which are allocated (mpz_init) within that block. Those can
   be modified using any mpz functions, and reallocated as many times as
   are needed. In the failure case, they will be completely deallocated.

And the dealloaction on failure must deallocate not only the storage for
variables in the second set, but also all temporary storage allocated
before the allocation failure. Which should work fine, with an
appropriate implementation of the "... set mark..." thing.

> Yet another could be the need to "pop" some sort of (thread local?)
> activation stack of the TMP_MARK entries using
> __gmp_tmp_reentrant_free().  GMP 5.1.3 does not seem to implement
> any method for creating/maintaining such an activation stack of
> TMP_MARK entries, however.

There are a couple of different implementations, and I don't know them
all. I'm not aware of any pointer to the top of such a stack. If there
is some pointer like that, it clearly has to be saved at setjmp and
reset at longjmp.

And this *is* arcane, so if you try this scheme out, please let us know
how it works out.

Regards,
/Niels

-- 
Niels Möller. PGP-encrypted email is preferred. Keyid C0B98E26.
Internet email is subject to wholesale government surveillance.


More information about the gmp-devel mailing list