Opened 8 years ago

Closed 6 years ago

#12266 closed defect (fixed)

3^3^3^3 segfaults

Reported by: vbraun Owned by: jason, jkantor
Priority: major Milestone: sage-duplicate/invalid/wontfix
Component: c_lib Keywords:
Cc: Merged in:
Authors: Reviewers: Jeroen Demeyer
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Description

As reported on http://ask.sagemath.org/question/1031/segmentation-fault-when-evaluating-3333:

sage: 3^3^3^3 
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)

/home/vbraun/<ipython console> in <module>()

/home/vbraun/opt/sage-4.8.alpha6/local/lib/python2.6/site-packages/sage/rings/integer.so in sage.rings.integer.Integer.__pow__ (sage/rings/integer.c:12867)()

RuntimeError: Segmentation fault

Debugger shows that we call gmp_n_pow_ui on a non-int:

(gdb) bt
#0  0x00007fffed883c14 in __gmp_tmp_reentrant_alloc ()
   from /home/vbraun/opt/sage-4.8.alpha6/local/lib/libgmp.so.8
#1  0x00007fffed897754 in __gmpz_n_pow_ui ()
   from /home/vbraun/opt/sage-4.8.alpha6/local/lib/libgmp.so.8
#2  0x00007fffe75fbce7 in __pyx_pf_4sage_5rings_7integer_7Integer_36__pow__ (__pyx_v_self=0x3e8fe70, 
    __pyx_v_n=0x3e8fbd0, __pyx_v_modulus=<optimized out>) at sage/rings/integer.c:12881
#3  0x00007ffff7c85fe2 in ternary_op (v=0x3e8fe70, w=0x3e8fbd0, z=0x7ffff7fc92a0, op_slot=48, op_name=Unhandled dwarf expression opcode 0xfa

Change History (6)

comment:1 Changed 7 years ago by was

It is incorrect to say that this "segfaults". In fact, the relevant code is this from integer.pyx:

        sig_on()
        mpz_pow_ui(x.value, (<Integer>self).value, nn if nn > 0 else -nn)
        sig_off()

What happens is that MPIR can't allocate memory for the answer, this causes a signal, and Sage properly catches the signal. The Sage process does not crash the first time around. But things get left in a screwed up state, so that subsequence calls can totally crash Sage.

On 64-bit OS X I have to use this input to cause the problem:

a = 2^(2^60)

It would be nice if a MemoryError? is raised instead of a RuntimeError?, of course. I don't know how to put MPIR back in a clean state after this error occurs though. This on OS X:

sage: a = 2^(2^60)
python(64816) malloc: *** mmap(size=144115188075859968) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)

/Users/wstein/sage/install/sage-5.0.beta2/devel/sage-git/sage/<ipython console> in <module>()

/Users/wstein/sage/install/sage-5.0.beta2/local/lib/python2.7/site-packages/sage/rings/integer.so in sage.rings.integer.Integer.__pow__ (sage/rings/integer.c:12958)()

RuntimeError: Segmentation fault
sage: a = 2^(2^60)

------------------------------------------------------------------------
Unhandled SIGSEGV: A segmentation fault occurred in Sage.
This probably occurred because a *compiled* component of Sage has a bug
in it and is not properly wrapped with sig_on(), sig_off(). You might
want to run Sage under gdb with 'sage -gdb' to debug this.
Sage will now terminate.
------------------------------------------------------------------------
/Users/wstein/sage/install/sage-5.0.beta2/spkg/bin/sage: line 304: 64816 Segmentation fault: 11  sage-ipython "$@" -i
You have new mail in /var/mail/wstein
deep:sage wstein$ 

I don't know if MPIR even provides a way of properly dealing with this sort of thing.

comment:2 Changed 7 years ago by was

A remark from Bill Hart about what is going on:

Hi William,

It appears to eventually call __gmp_tmp_reentrant_alloc. Here is that function:

__gmp_tmp_reentrant_alloc (struct tmp_reentrant_t **markp, size_t size)
{
 char    *p;
 size_t  total_size;

#define P   ((struct tmp_reentrant_t *) p)

 total_size = size + HSIZ;
 p = (*__gmp_allocate_func) (total_size);
 P->size = total_size;
 P->next = *markp;
 *markp = P;
 return p + HSIZ;
}

As you can see, there is no state stored here. It merely calls
__gmp_allocate_func. Here is that latter function:

void *  (*__gmp_allocate_func) _PROTO ((size_t)) = __gmp_default_allocate;

void *
__gmp_default_allocate (size_t size)
{
 void *ret;
#ifdef DEBUG
 size_t req_size = size;
 size += 2 * BYTES_PER_MP_LIMB;
#endif
 ret = malloc (size);
 if (ret == 0)
   {
#if defined _MSC_VER && defined _WIN64
     fprintf (stderr, "GNU MP: Cannot allocate memory (size=%llu)\n", size);
#else
     fprintf (stderr, "GNU MP: Cannot allocate memory (size=%u)\n", size);
#endif
     abort ();
   }

#ifdef DEBUG
 {
   mp_ptr p = ret;
   p++;
   p[-1] = (0xdeadbeef << 31) + 0xdeafdeed;
   if (req_size % BYTES_PER_MP_LIMB == 0)
     p[req_size / BYTES_PER_MP_LIMB] = ~((0xdeadbeef << 31) + 0xdeafdeed);
   ret = p;
 }
#endif
 return ret;
}

As you can see, it is just a simple call to malloc, plus an abort if
malloc fails. So I don't think this is a problem in MPIR, unless MPIR
is being built in malloc-notreentrant mode (note that alloca or
malloc-reentrant is the default).

So I don't know what you mean by "properly dealing with this sort of
thing". Did you have something particular in mind?

comment:3 Changed 6 years ago by jdemeyer

  • Milestone changed from sage-5.11 to sage-5.12

comment:4 Changed 6 years ago by jdemeyer

  • Component changed from numerical to c_lib
  • Milestone changed from sage-6.1 to sage-duplicate/invalid/wontfix
  • Reviewers set to Jeroen Demeyer
  • Status changed from new to needs_review

Fixed by #15363.

comment:5 Changed 6 years ago by jdemeyer

  • Status changed from needs_review to positive_review

comment:6 Changed 6 years ago by vbraun

  • Resolution set to fixed
  • Status changed from positive_review to closed
Note: See TracTickets for help on using tickets.