gmp

From Lazarus wiki
Revision as of 18:58, 21 October 2009 by Befelemepeseveze (talk | contribs) (More hints on standard bindings - how to avoid unintentional heap corruption by variable assignment.)
Jump to navigationJump to search

An editor has declared this article to be a stub, meaning that it needs more information. Can you help out and add some? If you have some useful information, you can help the Free Pascal Wiki by clicking on the edit box on the left and expanding this page.

The current /trunk FPC version (2.5.1) and the /branches/fixes_2_4 (the upcoming 2.4 release) already include an initial version of a Free Pascal interface for the GNU Multiple Precision Arithmetic Library in packages/gmp.

To use the bindings in your projects (and be able to build them) you have to:

  • Include gmp in the uses clause of a program/unit source from which you will use the GMP types/functions.
  • Have the gmp library installed on your system
    • Most, if not all, *nix systems have GMP (libgmp) installed by default but it is still necessary to have the dev package (libgmpX-dev) installed also (needed in the link stage). This package is not included by default everywhere (eg. Ubuntu).
    • On Windows, you can get the mingw-dynamic package and rename it to gmp.dll.
    • On Mac OS X, gmp can be installed as documented on gmplib.org or using the package managers MacPorts or Fink.
  • Have the necessary knowledge of the GMP documentation.

Some gmp unit tests and usage examples for both the standard and extensions bindings can be found at the INSTALLATION_PREFIX/share/doc/fpc-x.y.z/gmp/examples folder.

Standard bindings & types

The standard bindings cover almost all of the GMP types and functions as they appear in the GMP documentation. The few exceptions are listed near the top of the gmp unit.

Naming conventions

The interfaced names of the FPC functions, types and parameters are identical to those in the GMP documentation with the minor deviations of the added underscore suffix to some of the (possibly) conflicting identifiers, eg. the original documentation C function "void mpz_init (mpz_t integer)" is declared here as: <delphi> { Initialize integer, and set its value to 0 } procedure mpz_init(out integer_: mpz_t); cdecl; external LIB name '__gmpz_init'; </delphi>

Memory issues

With the standard bindings you have direct access to the full power of the GMP without any overhead. On the same time, to avoid heap corruption and/or memory leaks, the programmer is the only one responsible for the proper initialization of GMP variables (mpz_t, mpf_t, ... types) before passing them to functions that expect them being already in such state. The same applies to finalization of (properly invoking *_clear on) those variables.

Take for granted to run into heap problems and/or program crashes by doing eg.:

  • Passing an uninitialized GMP variable to any GMP functions other than *_init.
  • Initializing an already initialized GMP variable without previously clearing it.
  • Clearing an already cleared one. This can easily happen eg. on a copy of a GMP variable, created by a simple assignment. GMP variables are true value types (declared as record types in gmp) and invoking a *_clear on any of the (assigned) copies creates dangling pointers in all of the other copies.

The last issue generalizes to the invocation of any function that modifies the address/size of memory owned by a GMP variable. The net result is thus to avoid existence of any memory image copy (as is the case for assignment of record variables) of any GMP variable. Instead of an assignment to another variable (equals shallow copying), which will be rightfully accepted by the compiler without any warning, use GMP functions like in the following example: <delphi> procedure DoSomething; var A, B: mpz_t; // multi precision (big) integers begin

 mpz_init_set_si(A, 123); // This allocates mem owned by A and initializes it to the given value
 B := A;                  // Wrong: B renders invalid as soon as the mem adr/size owned by A is altered in any way
 mpz_init_set(B, A);      // Only this is safe.
 try
   // Number crunching goes here
 finally
   mpz_clear(A);          // Release the mem owned by A and B
   mpz_clear(B);
 end;

end; </delphi>

As the interns of all GMP variables have a private pointer to a memory block allocated for that variable instance (effectively owned by the instance), the correct handling of them has the same methodology as the proper usage of New/Dispose or GetMem/FreeMem pairs, not limited to but including also the necessity of using try/finally constructs where an exception can occur between a *_init and the corresponding *_clear of any GMP variable as shown in the snippet above.

Extensions Bindings & Types

The possible issues with memory management, discussed in the standard bindings, is addressed by an extensions layer providing automated memory management for the GMP variables in the style of Object Pascal String type.

TODO

Naming conventions

TODO

Operators

TODO