shoup at cs.nyu.edu
Thu Dec 18 19:49:59 UTC 2014
These are some very good ideas.
But just to make clear what my own (rather narrow) goals are:
to be able to compile GMP in such a way that the mpn-level
routines do not call abort (except perhaps for asserts that
indicate an internal bug), but rather, throw a C++ exception.
As I understand it, this is what Marc Glisse is working on.
For my own project (NTL), I don't use mpz or C++ wrappers,
so I'm not too worried about that stuff. However, I would
presume that even for GMP, the mpn-level would be the logical first
step on the road to better error handling.
A larger question to ponder is this: should the GMP project even
attempt to provide a better error handling mechanism within
the C-language...that is, maybe one should only consider doing
this as a C++ build of GMP. There are a number of pros and cons
here. The main "pro" for doing this only for C++ is that, from an engineering
perspective, it is probably a lot easier to retrofit the library
with a minimum of effort and bugs. Since you would be providing
brand new functionality with this, backward compatibility is not an issue.
Just to be clear: I'm not talking about C++ wrappers here, I'm talking about
compiling all of GMP with a C++ compiler.
I know, there are lots of "cons", too...but it seems to me that
if you want to provide error handling in a pure-C setting, I don't see
how to do that without making all GMP functions return error codes.
And that would require all new interfaces.
As far as NTL is concerned, I wouldn't mind this so much:
I could easily adapt my code to test a return code and throw an exception
On Dec 17, 2014, at 5:04 PM, Niels Möller wrote:
> tg at gmplib.org (Torbjörn Granlund) writes:
>> The error handler function would then use the knowledge of the
>> allocation functions to clean up the memory state, and probably longjump
>> to to deallocate stack.
> We've discussed such hacks for memory allocation before (but now I can't
> find the relevant posts...). To recap the idea:
> The "protected" code should take some input mpz variables and some
> output mpz_variables. The input variables are read only. All computation
> takes place in newly allocated temporaries, not touching the output
> variables. Only after the computation is complete and successful,
> results are assigned to the output variables using mpz_swap (which can
> never result in an allocation failure).
> Then needs a wrapper around the protected code, first adding a
> checkpoint in the allocation data structures, and a setjmp buffer. At
> any allocation failure during the computation, the allocation function
> should deallocate all live storage allocated after the checkpoint, and
> longjmp out, and the wrapper can then return some failure indication or
> raise a C++ exception or whatever. The same mechanism could clean up
> allocation after other types of failures.
> Does anyone know of any implementation of this?
> I think one step forward might be to think about what GMP interfaces
> would make it easier to implement that type of checkpointing.
> Hmm. Maybe the key is to distinguish temporary allocations from more
> long-lived objects. That's the real point of the interface rules for the
> "protected" code above does: It ensures that *all* allocations are for
> Then, if we make allocation and exception handling pointers
> thread-local, and provide a way to push new pointers on top of the
> current ones, the longjmp recovery hack could be implemented locally for
> internal gmp-calls in a library, without affecting other uses of gmp in
> the same executable.
> Questions are: How do we make this reasonably cheap, both in terms of
> execution time, and code verbosity? And can we design the mechanism so
> that the C++ wrapper (as well as wrappers for high-level languages) use
> the mechanism to convert failures into proper exceptions?
>> I am not too fond of these global pointers. It would be better design
>> to refer the memory handling and error handling functions from each GMP
>> user variable, akin to object oriented languages' vtables. Except that
>> this would make these small structures 3 times larger.
> I don't think it's a good idea to put this in the mpz variables. There's
> the size. And it doesn't help with temporary allocations in mpn. And
> there's the head-ache of what to do with an mpz_swap where the two
> mpz objects use different allocators.
>> There are real scenarios where one would want different sets of
>> allocation functions. E.g., many libraries use GMP. Some of them have
>> their orn error reporting mechanisms, and memory handles.
> An alternative approach in a library is to not touch the gmp allocation
> functions, but let the application's main function install an
> appropriate allocator. (But with the current interfaces, that makes it
> difficult for libraries to use longjmp-recovery-trick from the
> allocation function).
>> We have another problem with the GMP structures. On 64-bit machines,
>> the 32-bit _mp_size field is starting to hurt for some applications, and
>> with that also the _mp_alloc field.
>> We might therefore consider changing these structures in an incompatible
>> way. We culd then sneak in a field for choosing 'handler functions'.
>> Perhaps like this:
>> signed long _mp_size : 46;
>> unsigned long _mp_alloc : 14; // 8-bit mantissa, 6-bit exponent
>> unsigned long _mp_handler: 4;
>> mp_limb_t _mp_d; // 64
>> The trickery with field sizes keeps the structure at 128 bits. There
>> will be a cost for it, though.
> I'm very skeptic to the _mp_handler, I think the exception handler must
> be associated with a frame on the call stack in some way.
> On the other hand, we have discussed earlier to use more bits for
> _mp_size, at the expense of _mp_alloc, by reducing the granularity of
> the latter. I think that is a pretty good idea.
> Niels Möller. PGP-encrypted email is preferred. Keyid C0B98E26.
> Internet email is subject to wholesale government surveillance.
More information about the gmp-devel