[PATCH] mini-gmp: pass correct old_size to custom reallocate function

Niels Möller nisse at lysator.liu.se
Sat Mar 7 19:26:24 UTC 2020


minux <minux.ma at gmail.com> writes:

> Because we don't have separate docs for mini-gmp, and mini-gmp does
> provide mp_set_memory_functions, I think it's best if it can match
> gmp's behavior here to avoid confusions.

The differences are documented in mini-gmp/README (and your patch fixes
all but one of the documented differences).

> OK, patch updated. Now mini-gmp keeps track of old_size correctly and
> implements the behavior exactly as documented. And I have modified
> tests to ensure old_size is correct on realloc and free.
> I hope the added complexity is not too much.

Changes to mini-gmp.c look reasonable to me. Some detailed comments
below. 

> In fact, I think it makes the code of mpq_get_str slightly easier to
> read.

I'm not that familiar with the mpq functions. I hope Marco can comment.

> diff -r bcca14c8a090 mini-gmp/mini-gmp.c
> --- a/mini-gmp/mini-gmp.c	Thu Mar 05 00:43:26 2020 +0100
> +++ b/mini-gmp/mini-gmp.c	Sat Mar 07 13:04:26 2020 -0500
> @@ -352,7 +352,8 @@
>  }
>  
>  #define gmp_xalloc(size) ((*gmp_allocate_func)((size)))
> -#define gmp_free(p) ((*gmp_free_func) ((p), 0))
> +#define gmp_xfree(p, size) ((*gmp_free_func) ((p), (size)))
> +#define gmp_xrealloc(ptr, old_size, size) ((*gmp_reallocate_func)(ptr, old_size, size))
>  
>  static mp_ptr
>  gmp_xalloc_limbs (mp_size_t size)
> @@ -361,10 +362,17 @@
>  }
>  
>  static mp_ptr
> -gmp_xrealloc_limbs (mp_ptr old, mp_size_t size)
> +gmp_xrealloc_limbs (mp_ptr old, mp_size_t old_size, mp_size_t size)
>  {
> +  const size_t sl = sizeof (mp_limb_t);
>    assert (size > 0);
> -  return (mp_ptr) (*gmp_reallocate_func) (old, 0, size * sizeof (mp_limb_t));
> +  return (mp_ptr) gmp_xrealloc (old, old_size * sl, size * sl);
> +}

I'd prefer repeating sizeof (mp_limb_t), instead of the local sl
constant.

> @@ -956,11 +964,12 @@
>    mp_limb_t d, di;
>    mp_limb_t r;
>    mp_ptr tp = NULL;
> +  mp_size_t tps = 0;
>  
>    if (inv->shift > 0)
>      {
>        /* Shift, reusing qp area if possible. In-place shift if qp == np. */
> -      tp = qp ? qp : gmp_xalloc_limbs (nn);
> +      tp = qp ? qp : gmp_xalloc_limbs (tps = nn);

Please write the assignment tps = nn as a separate statement. Also, I
think name "tn" instead of "tps" would be more consistent with
surrounding code.

>        r = mpn_lshift (tp, np, nn, inv->shift);
>        np = tp;
>      }
> @@ -978,7 +987,7 @@
>  	qp[nn] = q;
>      }
>    if ((inv->shift > 0) && (tp != qp))
> -    gmp_free (tp);
> +    gmp_xfree_limbs (tp, tps);

Can the condition be simplified to just

  if (tps > 0)
    gmp_xfree_limbs (tp, tps);

?

> @@ -4143,7 +4152,7 @@
>  size_t
>  mpz_sizeinbase (const mpz_t u, int base)
>  {
> -  mp_size_t un;
> +  mp_size_t un, oun;
>    mp_srcptr up;
>    mp_ptr tp;
>    mp_bitcnt_t bits;
> @@ -4176,7 +4185,7 @@
>  	 10. */
>      }
>  
> -  tp = gmp_xalloc_limbs (un);
> +  tp = gmp_xalloc_limbs (oun = un);

I'd prefer 

  tn = un;

as a separate statement. And maybe clearer to leave un unchanged below, and
use tn as the loop variable?

>    mpn_copyi (tp, up, un);
>    mpn_div_qr_1_invert (&bi, base);
>  
> @@ -4189,7 +4198,7 @@
>      }
>    while (un > 0);
>  
> -  gmp_free (tp);
> +  gmp_xfree_limbs (tp, oun);
>    return ndigits;
>  }
>  
> @@ -4199,7 +4208,7 @@
>    unsigned bits;
>    const char *digits;
>    mp_size_t un;
> -  size_t i, sn;
> +  size_t i, sn, osn = 0;
>  
>    digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
>    if (base > 1)
> @@ -4220,15 +4229,15 @@
>  
>    sn = 1 + mpz_sizeinbase (u, base);
>    if (!sp)
> -    sp = (char *) gmp_xalloc (1 + sn);
> +    sp = (char *) gmp_xalloc (osn = 1 + sn);

I'd prefer

  if (!sp)
    {
      osn = 1 + sn;
      sp = (char *) gmp_xalloc (osn);
    }
  else
    osn = 0;

(and drop the zero initialization at the declaration above).

> +ret:
>    sp[sn] = '\0';
> +  if (osn) sp = gmp_xrealloc(sp, osn, sn + 1);
>    return sp;
>  }

Would it make sense to also check if realloc is needed?

  if (osn && osn != sn + 1)
    gmp_xrealloc(...);

> @@ -4305,7 +4316,7 @@
>        r->_mp_size = 0;
>        return -1;
>      }
> -  dp = (unsigned char *) gmp_xalloc (strlen (sp));
> +  dp = (unsigned char *) gmp_xalloc (dpn = strlen (sp));

  dpn = strlen (sp);

as a separate statement. And I'm not that fond of the name dpn. Maybe

  sn = strlen (sp);

and reorganize the loop as

  for (i = 0; i < sn; i++)
    {
      ...
      dp[i] = digit;
    }

> @@ -4382,7 +4393,7 @@
>    str = mpz_get_str (NULL, base, x);
>    len = strlen (str);
>    len = fwrite (str, 1, len, stream);
> -  gmp_free (str);
> +  gmp_xfree (str, len + 1);
>    return len;
>  }

This seems wrong in the case of i/o errors, where fwrite may return a
shorter item count.

> --- a/mini-gmp/tests/testutils.c	Thu Mar 05 00:43:26 2020 +0100
> +++ b/mini-gmp/tests/testutils.c	Sat Mar 07 13:04:26 2020 -0500
> @@ -84,31 +84,51 @@
>  static void *
>  tu_realloc (void *p, size_t old_size, size_t new_size)
>  {
> -  size_t *block = block_check (p);
> -  block = (size_t *) realloc (block, sizeof(size_t) + new_size + sizeof(block_end));
> +  size_t *old_block = block_check (p), *block;
> +  void *new;
> +  if (old_block[0] != old_size)
> +    {
> +      fprintf (stderr, "%s:%d: bad old_size: want %ld, got %ld.\n", __FILE__, __LINE__,
> +                 (long)old_block[0], (long)old_size);
> +      abort ();
> +    }
> +
> +  /* We do not use realloc here to test custom allocators where realloc
> +     requires old_size to be set to the length of data that needs to be
> +     copied from old to the newly allocated space. */

I think the above check of old_size should be enough for testing
mini-gmp. One can still use realloc for the actual allocation, no manual
memcpy.

Regards,
/Niels

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


More information about the gmp-devel mailing list