Peter Bruin on Fri, 11 Sep 2015 16:17:20 +0200


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Trying to allocate too much memory is not handled gracefully


Bonjour,

When one tries to allocate an impossible amount of memory using
allocatemem() or default(parisizemax), GP does not always handle this
gracefully.

1) allocatemem(s) causes GP to crash for values of s >= 2^63 (on a
   64-bit system, with parisizemax set to 0):

gp> allocatemem(2^63)
  ***   Warning: not enough memory, new stack 4611686018427387904
  ***   Warning: not enough memory, new stack 2305843009213693952
  .........
  ***   Warning: not enough memory, new stack 140737488355328
  ***   Warning: not enough memory, new stack 70368744177664
  ***   Warning: new stack size = 9223372036854775808 (8796093022208.000 Mbytes).
Segmentation fault

This is due to a "minss" that should be a "minuu".  While debugging
this, I noticed in addition that when the requested size s needs to be
halved, it may no longer be aligned as it should.  Finally, when s is
extremely close to 2^64, it is not halved but set to the minimum
possible stack size due to an overflow.

2) default(parisizemax, s) prints the requested value s instead of the
   value that was actually allocated:

gp> default(parisizemax,2^63-1)  \\ maximum value of this default
  ***   Warning: not enough memory, new stack 4611686018427387904
  ***   Warning: not enough memory, new stack 2305843009213693952
  .........
  ***   Warning: not enough memory, new stack 140737488355328
  ***   Warning: not enough memory, new stack 70368744177664
  ***   Warning: new maximum stack size = 9223372036854775807 (8796093022208.000 Mbytes).

The attached patch is one possible way to fix these bugs.  It fixes the
output of default(parisizemax), and it seems to make allocatemem(s) work
as expected for all s <= 2^64 - 1.

A somewhat related problem is that allocatemem(s) causes GP to crash
when s is very small, but I have not looked into this.

Thanks,

Peter


diff --git a/src/language/init.c b/src/language/init.c
index d85a58e..8ab4210 100644
--- a/src/language/init.c
+++ b/src/language/init.c
@@ -650,7 +650,7 @@ fix_size(size_t a)
 {
   size_t ps = PARI_STACK_ALIGN;
   size_t b = a & ~(ps - 1); /* Align */
-  if (b < a) b += ps;
+  if (b < a && b < ~(ps - 1)) b += ps;
   if (b < MIN_STACK) b = MIN_STACK;
   return b;
 }
@@ -659,15 +659,16 @@ static void
 pari_mainstack_alloc(struct pari_mainstack *st, size_t rsize, size_t vsize)
 {
   size_t sizemax = vsize ? vsize: rsize, s = fix_size(sizemax);
-  for (;; s>>=1)
+  for (;;)
   {
-    if (s < MIN_STACK) pari_err(e_MEM); /* no way out. Die */
     st->vbot = (pari_sp)pari_mainstack_malloc(s);
     if (st->vbot) break;
-    pari_warn(warnstack, s>>1);
+    if (s == MIN_STACK) pari_err(e_MEM); /* no way out. Die */
+    s = fix_size(s >> 1);
+    pari_warn(warnstack, s);
   }
   st->vsize = vsize ? s: 0;
-  st->rsize = minss(rsize, s);
+  st->rsize = minuu(rsize, s);
   st->size = st->rsize;
   st->top = st->vbot+s;
   st->bot = st->top - st->size;
@@ -721,7 +722,8 @@ parivstack_resize(ulong newsize)
   if (newsize == pari_mainstack->vsize) return;
   evalstate_reset();
   paristack_setsize(pari_mainstack->rsize, newsize);
-  s = newsize ? newsize : pari_mainstack->rsize;
+  s = pari_mainstack->vsize;
+  if (!s) s = pari_mainstack->rsize;
   pari_warn(warner,"new maximum stack size = %lu (%.3f Mbytes)", s, s/1048576.);
   pari_init_errcatch();
   cb_pari_err_recover(-1);