SIGSEGV when Python exits due to near null deref
Opened by iankronquist (open)

### Describe the bug



When I run the following python script using datasets I get a segfault.
```python
from datasets import load_dataset
from tqdm import tqdm
progress_bar = tqdm(total=(1000), unit='cols', desc='cols ')
progress_bar.update(1)
```

```
% lldb -- python3 crashmin.py 
(lldb) target create "python3"
Current executable set to '/Users/ian/bug/venv/bin/python3' (arm64).
(lldb) settings set -- target.run-args  "crashmin.py"
(lldb) r
Process 8095 launched: '/Users/ian/bug/venv/bin/python3' (arm64)
Process 8095 stopped
* thread #2, stop reason = exec
    frame #0: 0x0000000100014b30 dyld`_dyld_start
dyld`_dyld_start:
->  0x100014b30 <+0>: mov    x0, sp
    0x100014b34 <+4>: and    sp, x0, #0xfffffffffffffff0
    0x100014b38 <+8>: mov    x29, #0x0 ; =0 
Target 0: (Python) stopped.
(lldb) c
Process 8095 resuming
cols :   0% 0/1000 [00:00<?, ?cols/s]Process 8095 stopped
* thread #2, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x10)
    frame #0: 0x0000000101783454 _datetime.cpython-313-darwin.so`delta_new + 188
_datetime.cpython-313-darwin.so`delta_new:
->  0x101783454 <+188>: ldr    x3, [x20, #0x10]
    0x101783458 <+192>: adrp   x0, 10
    0x10178345c <+196>: add    x0, x0, #0x6fc ; "seconds"
Target 0: (Python) stopped.
(lldb) bt
* thread #2, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x10)
  * frame #0: 0x0000000101783454 _datetime.cpython-313-darwin.so`delta_new + 188
    frame #1: 0x0000000100704b60 Python`type_call + 96
    frame #2: 0x000000010067ba34 Python`_PyObject_MakeTpCall + 120
    frame #3: 0x00000001007aae3c Python`_PyEval_EvalFrameDefault + 30236
    frame #4: 0x000000010067c900 Python`PyObject_CallOneArg + 112
    frame #5: 0x000000010070f0a0 Python`slot_tp_finalize + 116
    frame #6: 0x000000010070c3b4 Python`subtype_dealloc + 788
    frame #7: 0x00000001006c378c Python`insertdict + 756
    frame #8: 0x00000001006db2b0 Python`_PyModule_ClearDict + 660
    frame #9: 0x000000010080a9a8 Python`finalize_modules + 1772
    frame #10: 0x0000000100809a44 Python`_Py_Finalize + 264
    frame #11: 0x0000000100837630 Python`Py_RunMain + 252
    frame #12: 0x0000000100837ef8 Python`pymain_main + 304
    frame #13: 0x0000000100837f98 Python`Py_BytesMain + 40
    frame #14: 0x000000019cfcc274 dyld`start + 2840
(lldb) register read x20
     x20 = 0x0000000000000000
(lldb) 
```

### Steps to reproduce the bug

Run the script above, and observe the segfault.

### Expected behavior

No segfault

### Environment info
```
% pip freeze datasets | grep -i datasets
datasets==4.2.0
(venv) 0 ~/bug 14:58:06 
% pip freeze tqdm | grep -i tqdm
tqdm==4.67.1
(venv) 0 ~/bug 14:58:16 
% python --version
Python 3.13.7
```

Comments:
The issue seems to come from `dill` which is a `datasets` dependency, e.g. this segfaults:

```python
import dill
from tqdm import tqdm
progress_bar = tqdm(total=(1000), unit='cols', desc='cols ')
progress_bar.update(1)
```

`tqdm` seems to segfault when `dill` is imported. I only found this about segfault but it's maybe not related https://github.com/tqdm/tqdm/issues/1678 ?

After more investigation it seems to be because of it imports `__main__`. This segfaults:

```python
import __main__
from tqdm import tqdm
progress_bar = tqdm(total=(1000), unit='cols', desc='cols ')
progress_bar.update(1)
```

I opened an issue at https://github.com/tqdm/tqdm/issues/1687

Here is a workaround. You can run your code as long as the progress bar is closed before exiting.

```python
from datasets import load_dataset
from tqdm import tqdm

progress_bar = tqdm(total=(1000), unit='cols', desc='cols ')
progress_bar.update(1)
progress_bar.close()  # avoids the segfault
```

https://github.com/tqdm/tqdm/issues/1687#issuecomment-3392457094