3-manifolds / SnapPy

SnapPy is a package for studying the topology and geometry of 3-manifolds, with a focus on hyperbolic structures. It is based on the SnapPea kernel written by Jeff Weeks.
https://snappy.computop.org/
84 stars 39 forks source link

Filling a closed triangulation aborts #6

Open unhyperbolic opened 4 years ago

unhyperbolic commented 4 years ago

Originally reported by Robert Haraway at https://bitbucket.org/t3m/snappy/issues/25/filling-a-closed-triangulation-aborts.

This is for SnapPy version 2.7, running on Python version 3.7.3 compiled with GCC 8.3.0. The bug is present without IPython. My operating system is Linux 4.19.0-6-amd64, running on Debian 10.

Filling a closed Triangulation crashes Python with an unhandled SIGABRT. Here is a code snippet illustrating the issue.

import snappy
M = snappy.Manifold('m129')
M.dehn_fill([(1,0),(1,0)])
X = M.filled_triangulation()
X.filled_triangulation()
The output from the Python console is as follows.

free(): double free detected in tcache 2
------------------------------------------------------------------------
/home/rch3/.local/lib/python3.7/site-packages/cypari/_pari.cpython-37m-x86_64-linux-gnu.so(+0x7e804)[0x7f191e4a4804]
/home/rch3/.local/lib/python3.7/site-packages/cypari/_pari.cpython-37m-x86_64-linux-gnu.so(+0x7e845)[0x7f191e4a4845]
/home/rch3/.local/lib/python3.7/site-packages/cypari/_pari.cpython-37m-x86_64-linux-gnu.so(+0x181f01)[0x7f191e5a7f01]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x12730)[0x7f1920fb7730]
/lib/x86_64-linux-gnu/libc.so.6(gsignal+0x10b)[0x7f1920a317bb]
/lib/x86_64-linux-gnu/libc.so.6(abort+0x121)[0x7f1920a1c535]
/lib/x86_64-linux-gnu/libc.so.6(+0x79508)[0x7f1920a73508]
/lib/x86_64-linux-gnu/libc.so.6(+0x7fc1a)[0x7f1920a79c1a]
/lib/x86_64-linux-gnu/libc.so.6(+0x816fd)[0x7f1920a7b6fd]
/home/rch3/.local/lib/python3.7/site-packages/snappy/SnapPy.cpython-37m-x86_64-linux-gnu.so(my_free+0x9)[0x7f19200106e9]
/home/rch3/.local/lib/python3.7/site-packages/snappy/SnapPy.cpython-37m-x86_64-linux-gnu.so(+0x1ab23c)[0x7f192001d23c]
/home/rch3/.local/lib/python3.7/site-packages/snappy/SnapPy.cpython-37m-x86_64-linux-gnu.so(peripheral_curves+0x180)[0x7f192001e320]
/home/rch3/.local/lib/python3.7/site-packages/snappy/SnapPy.cpython-37m-x86_64-linux-gnu.so(tidy_peripheral_curves+0x25)[0x7f1920030875]
/home/rch3/.local/lib/python3.7/site-packages/snappy/SnapPy.cpython-37m-x86_64-linux-gnu.so(basic_simplification+0xb8)[0x7f192005ec08]
/home/rch3/.local/lib/python3.7/site-packages/snappy/SnapPy.cpython-37m-x86_64-linux-gnu.so(fill_cusps+0x13d)[0x7f192004ddcd]
/home/rch3/.local/lib/python3.7/site-packages/snappy/SnapPy.cpython-37m-x86_64-linux-gnu.so(+0x12a14e)[0x7f191ff9c14e]
python3(_PyMethodDescr_FastCallKeywords+0x3c4)[0x4d7d74]
python3(_PyEval_EvalFrameDefault+0x4599)[0x552089]
python3(_PyEval_EvalCodeWithName+0x252)[0x54b7c2]
python3(PyEval_EvalCode+0x23)[0x54dae3]
python3[0x630af2]
python3[0x480b0e]
python3(PyRun_InteractiveLoopFlags+0xd4)[0x480c90]
python3(PyRun_AnyFileExFlags+0x53)[0x631a03]
python3[0x653f7e]
python3(_Py_UnixMain+0x2e)[0x6542de]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xeb)[0x7f1920a1e09b]
python3(_start+0x2a)[0x5dfe9a]
------------------------------------------------------------------------
Unhandled SIGABRT: An abort() occurred.
This probably occurred because a *compiled* module has a bug
in it and is not properly wrapped with sig_on(), sig_off().
Python will now terminate.
------------------------------------------------------------------------
Aborted

The output from GDB is as follows.

(gdb) run more_bad.py 
Starting program: /usr/bin/python3 more_bad.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
double free or corruption (fasttop)

Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50  ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007ffff79bb535 in __GI_abort () at abort.c:79
#2  0x00007ffff7a12508 in __libc_message (action=action@entry=do_abort, 
    fmt=fmt@entry=0x7ffff7b1d28d "%s\n") at ../sysdeps/posix/libc_fatal.c:181
#3  0x00007ffff7a18c1a in malloc_printerr (
    str=str@entry=0x7ffff7b1efb0 "double free or corruption (fasttop)")
    at malloc.c:5341
#4  0x00007ffff7a1a5d7 in _int_free (av=0x7ffff7b54c40 <main_arena>, 
    p=0x1b398d0, have_lock=<optimized out>) at malloc.c:4258
#5  0x00007ffff72646e9 in my_free (ptr=<optimized out>)
    at kernel/kernel_code/my_malloc.c:191
#6  0x00007ffff727123c in simplify_perimeter (perimeter_anchor=<optimized out>)
    at kernel/kernel_code/peripheral_curves.c:822
#7  do_one_cusp (manifold=manifold@entry=0x1b4aaf0, cusp=cusp@entry=0x1b719c0)
    at kernel/kernel_code/peripheral_curves.c:518
#8  0x00007ffff7272320 in peripheral_curves (manifold=manifold@entry=0x1b4aaf0)
    at kernel/kernel_code/peripheral_curves.c:356
#9  0x00007ffff7284875 in tidy_peripheral_curves (
    manifold=manifold@entry=0x1b4aaf0)
    at kernel/kernel_code/tidy_peripheral_curves.c:63
#10 0x00007ffff72b2c08 in basic_simplification (manifold=0x1b4aaf0)
    at kernel/kernel_code/simplify_triangulation.c:281
#11 0x00007ffff72a1dcd in fill_cusps (manifold=0x1b65240, 
    fill_cusp=fill_cusp@entry=0x1272c90 "\340\020\264\001", 
--Type <RET> for more, q to quit, c to continue without paging--c
    new_name=new_name@entry=0x7ffff72e39fb "", fill_all_cusps=<optimized out>) at kernel/kernel_code/filling.c:149
#12 0x00007ffff71f014e in __pyx_pf_6SnapPy_13Triangulation_86filled_triangulation (__pyx_v_cusps_to_fill=[], __pyx_v_self=0x7ffff1bfec48) at cython/SnapPy.c:33882
#13 __pyx_pw_6SnapPy_13Triangulation_87filled_triangulation (__pyx_v_self=<Triangulation at remote 0x7ffff1bfec48>, __pyx_args=<optimized out>, __pyx_kwds=<optimized out>) at cython/SnapPy.c:33308
#14 0x00000000004d7d74 in _PyMethodDef_RawFastCallKeywords (kwnames=<optimized out>, nargs=<optimized out>, args=<optimized out>, self=<Triangulation at remote 0x7ffff1bfec48>, method=0x7ffff7522f60 <__pyx_methods_6SnapPy_Triangulation+1248>) at ../Objects/call.c:690
#15 _PyMethodDescr_FastCallKeywords (descrobj=<method_descriptor at remote 0x7ffff7567d80>, args=0x7ffff764eb68, nargs=<optimized out>, kwnames=<optimized out>) at ../Objects/descrobject.c:288
#16 0x0000000000552089 in call_function (kwnames=0x0, oparg=1, pp_stack=0x7fffffffe240) at ../Python/ceval.c:4593
#17 _PyEval_EvalFrameDefault (f=<optimized out>, throwflag=<optimized out>) at ../Python/ceval.c:3110
#18 0x000000000054b7c2 in PyEval_EvalFrameEx (throwflag=0, f=Frame 0x7ffff764e9f8, for file more_bad.py, line 1, in <module> ()) at ../Python/ceval.c:547
#19 _PyEval_EvalCodeWithName (_co=<optimized out>, globals=<optimized out>, locals=<optimized out>, args=<optimized out>, argcount=<optimized out>, kwnames=0x0, kwargs=0x0, kwcount=<optimized out>, kwstep=2, defs=0x0, defcount=0, kwdefs=0x0, closure=0x0, name=0x0, qualname=0x0) at ../Python/ceval.c:3930
#20 0x000000000054dae3 in PyEval_EvalCodeEx (closure=0x0, kwdefs=0x0, defcount=0, defs=0x0, kwcount=0, kws=0x0, argcount=0, args=0x0, locals=<optimized out>, globals=<optimized out>, _co=<optimized out>) at ../Python/ceval.c:3959
#21 PyEval_EvalCode (co=<optimized out>, globals=<optimized out>, locals=<optimized out>) at ../Python/ceval.c:524
#22 0x0000000000630af2 in run_mod (mod=<optimized out>, filename=<optimized out>, globals={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <SourceFileLoader(name='__main__', path='more_bad.py') at remote 0x7ffff75e5198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff76a5c28>, '__file__': 'more_bad.py', '__cached__': None, 'snappy': <module at remote 0x7ffff75b0c28>, 'M': <Manifold at remote 0x7ffff1bfea48>, 'X': <Triangulation at remote 0x7ffff1bfec48>}, locals={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <SourceFileLoader(name='__main__', path='more_bad.py') at remote 0x7ffff75e5198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff76a5c28>, '__file__': 'more_bad.py', '__cached__': None, 'snappy': <module at remote 0x7ffff75b0c28>, 'M': <Manifold at remote 0x7ffff1bfea48>, 'X': <Triangulation at remote 0x7ffff1bfec48>}, flags=<optimized out>, arena=<optimized out>) at ../Python/pythonrun.c:1035
#23 0x0000000000630ba7 in PyRun_FileExFlags (fp=0x92dd90, filename_str=<optimized out>, start=<optimized out>, globals={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <SourceFileLoader(name='__main__', path='more_bad.py') at remote 0x7ffff75e5198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff76a5c28>, '__file__': 'more_bad.py', '__cached__': None, 'snappy': <module at remote 0x7ffff75b0c28>, 'M': <Manifold at remote 0x7ffff1bfea48>, 'X': <Triangulation at remote 0x7ffff1bfec48>}, locals={'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <SourceFileLoader(name='__main__', path='more_bad.py') at remote 0x7ffff75e5198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff76a5c28>, '__file__': 'more_bad.py', '__cached__': None, 'snappy': <module at remote 0x7ffff75b0c28>, 'M': <Manifold at remote 0x7ffff1bfea48>, 'X': <Triangulation at remote 0x7ffff1bfec48>}, closeit=1, flags=0x7fffffffe4dc) at ../Python/pythonrun.c:988
#24 0x000000000063180f in PyRun_SimpleFileExFlags (fp=0x92dd90, filename=<optimized out>, closeit=1, flags=0x7fffffffe4dc) at ../Python/pythonrun.c:429
#25 0x0000000000653f7e in pymain_run_file (p_cf=0x7fffffffe4dc, filename=<optimized out>, fp=0x92dd90) at ../Modules/main.c:427
#26 pymain_run_filename (cf=0x7fffffffe4dc, pymain=0x7fffffffe5b0) at ../Modules/main.c:1627
#27 pymain_run_python (pymain=0x7fffffffe5b0) at ../Modules/main.c:2877
#28 pymain_main (pymain=<optimized out>, pymain=<optimized out>) at ../Modules/main.c:3038
#29 0x00000000006542de in _Py_UnixMain (argc=<optimized out>, argv=<optimized out>) at ../Modules/main.c:3073
#30 0x00007ffff79bd09b in __libc_start_main (main=0x4bc7b0 <main>, argc=2, argv=0x7fffffffe6f8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe6e8) at ../csu/libc-start.c:308
#31 0x00000000005dfe9a in _start () at ../Modules/main.c:725
unhyperbolic commented 4 years ago

Comment originally from Marc Culler on bitbucket:

I think the real problem here is that the manifold in question is S^3. The crash occurs when SnapPea is trying to cancel segments of the peripheral curve which look like

--o--->---o---<---o--.

In this case, the entire curve collapses to a point. The crash occurs when the last two edges of the curve are cancelled.

I think the thing to do here might be for SnapPy to call fill_peripheral_curves_as_needed, instead of fill_peripheral_curves but the current version of fill_peripheral_curves_as_needed does not do the right thing for this example. And the function is called other places (e.g. when splitting along an incompressible surface) so some care is needed.

NathanDunfield commented 1 year ago

Confirming that this issue persists in SnapPy 3.1.1.