182 lines
4.5 KiB
C
182 lines
4.5 KiB
C
/*
|
|
|
|
Copyright 2013-2015, 2018 Free Software Foundation, Inc.
|
|
|
|
This file is part of the GNU MP Library test suite.
|
|
|
|
The GNU MP Library test suite is free software; you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 3 of the License,
|
|
or (at your option) any later version.
|
|
|
|
The GNU MP Library test suite is distributed in the hope that it will be
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
|
|
|
|
#include "testutils.h"
|
|
|
|
/* Include it here, so we we could tweak, e.g., how MPZ_REALLOC
|
|
works. */
|
|
#include "../mini-gmp.c"
|
|
#include "../mini-mpq.c"
|
|
|
|
static size_t total_alloc = 0;
|
|
|
|
/* Custom memory allocation to track memory usage, and add a small red
|
|
zone.
|
|
|
|
About alignment: In general, getting a block from malloc, and
|
|
incrementing it by sizeof(size_t), like we do here, might give a
|
|
pointer which is not properly aligned for all types. But the
|
|
largest type we allocate space for is unsigned long (mp_limb_t),
|
|
which shouldn't have stricter alignment requirements than
|
|
size_t. */
|
|
|
|
static unsigned char block_end[8] =
|
|
{ 0x7c, 0x37, 0xd6, 0x12, 0xa8, 0x6c, 0x01, 0xd1 };
|
|
|
|
static void *
|
|
block_init (size_t *block, size_t size)
|
|
{
|
|
char *p;
|
|
*block++ = size;
|
|
|
|
p = (char *) block;
|
|
memcpy (p + size, block_end, sizeof(block_end));
|
|
|
|
total_alloc += size;
|
|
return p;
|
|
}
|
|
|
|
/* Check small redzone, return pointer to malloced block. */
|
|
static size_t *
|
|
block_check (void *p)
|
|
{
|
|
size_t *block = (size_t *) p - 1;
|
|
size_t size = block[0];
|
|
|
|
if (memcmp ((char *)p + size, block_end, sizeof(block_end)) != 0)
|
|
{
|
|
fprintf (stderr, "red zone overwritten.\n");
|
|
abort ();
|
|
}
|
|
total_alloc -= size;
|
|
return block;
|
|
}
|
|
|
|
static void *
|
|
tu_alloc (size_t size)
|
|
{
|
|
size_t *block = (size_t *) malloc (sizeof(size_t) + size + sizeof(block_end));
|
|
if (!block)
|
|
{
|
|
fprintf (stderr, "Virtual memory exhausted.\n");
|
|
abort ();
|
|
}
|
|
|
|
return block_init (block, size);
|
|
}
|
|
|
|
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));
|
|
if (!block)
|
|
{
|
|
fprintf (stderr, "Virtual memory exhausted.\n");
|
|
abort ();
|
|
}
|
|
|
|
return block_init (block, new_size);
|
|
}
|
|
|
|
static void
|
|
tu_free (void *p, size_t old_size)
|
|
{
|
|
free (block_check (p));
|
|
}
|
|
|
|
/* Free memory allocated via mini-gmp allocation function. */
|
|
void
|
|
testfree (void *p)
|
|
{
|
|
void (*freefunc) (void *, size_t);
|
|
mp_get_memory_functions (NULL, NULL, &freefunc);
|
|
|
|
freefunc (p, 0);
|
|
}
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
hex_random_init ();
|
|
|
|
mp_set_memory_functions (tu_alloc, tu_realloc, tu_free);
|
|
|
|
/* Currently, t-comb seems to be the only program accepting any
|
|
arguments. It might make sense to parse common arguments here. */
|
|
testmain (argc, argv);
|
|
|
|
if (total_alloc != 0)
|
|
{
|
|
fprintf (stderr, "Memory leaked: %lu bytes.\n",
|
|
(unsigned long) total_alloc);
|
|
abort ();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
testhalves (int count, void (*tested_fun) (int))
|
|
{
|
|
void (*freefunc) (void *, size_t);
|
|
void *(*reallocfunc) (void *, size_t, size_t);
|
|
void *(*allocfunc) (size_t);
|
|
size_t initial_alloc;
|
|
|
|
mp_get_memory_functions (&allocfunc, &reallocfunc, &freefunc);
|
|
initial_alloc = total_alloc;
|
|
(*tested_fun) (count / 2);
|
|
if (initial_alloc != total_alloc)
|
|
{
|
|
fprintf (stderr, "First half, memory leaked: %lu bytes.\n",
|
|
(unsigned long) total_alloc - initial_alloc);
|
|
abort ();
|
|
}
|
|
mp_set_memory_functions (NULL, NULL, NULL);
|
|
(*tested_fun) (count / 2);
|
|
mp_set_memory_functions (allocfunc, reallocfunc, freefunc);
|
|
}
|
|
|
|
void
|
|
dump (const char *label, const mpz_t x)
|
|
{
|
|
char *buf = mpz_get_str (NULL, 16, x);
|
|
fprintf (stderr, "%s: %s\n", label, buf);
|
|
testfree (buf);
|
|
}
|
|
|
|
void
|
|
mpz_set_str_or_abort (mpz_ptr z, const char *str, int base)
|
|
{
|
|
if (mpz_set_str (z, str, base) != 0)
|
|
{
|
|
fprintf (stderr, "ERROR: mpz_set_str failed\n");
|
|
fprintf (stderr, " str = \"%s\"\n", str);
|
|
fprintf (stderr, " base = %d\n", base);
|
|
abort();
|
|
}
|
|
}
|
|
|
|
int
|
|
mpz_lucas_mod (mpz_t V, mpz_t Qk, long Q,
|
|
mp_bitcnt_t b0, const mpz_t n)
|
|
{
|
|
return gmp_lucas_mod (V, Qk, Q, b0, n);
|
|
}
|