We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`atexit.register` does not work
### What I did
```python3
from pwn import *
atexit.register(print, "hello world")
exit()
```
### What I expected to see
```python3 test.py
hello world
```
### What I saw
Nothing

I noticed this because `asm()`, which adds an `atexit` handler to remove the `/tmp/pwn-asm-XXXXXX` folder, does not in fact remove it, meaning multiple script runs leads to many similar folders.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pwnlib/atexit.py`
Content:
```
1 """
2 Replacement for the Python standard library's atexit.py.
3 
4 Whereas the standard :mod:`atexit` module only defines :func:`atexit.register`,
5 this replacement module also defines :func:`unregister`.
6 
7 This module also fixes a the issue that exceptions raised by an exit handler is
8 printed twice when the standard :mod:`atexit` is used.
9 """
10 from __future__ import absolute_import
11 from __future__ import division
12 
13 import sys
14 import threading
15 import traceback
16 
17 from pwnlib.context import context
18 
19 __all__ = ['register', 'unregister']
20 
21 _lock = threading.Lock()
22 _ident = 0
23 _handlers = {}
24 
25 def register(func, *args, **kwargs):
26     """register(func, *args, **kwargs)
27 
28     Registers a function to be called on program termination.  The function will
29     be called with positional arguments `args` and keyword arguments `kwargs`,
30     i.e. ``func(*args, **kwargs)``.  The current `context` is recorded and will
31     be the one used when the handler is run.
32 
33     E.g. to suppress logging output from an exit-handler one could write::
34 
35       with context.local(log_level = 'error'):
36         atexit.register(handler)
37 
38     An identifier is returned which can be used to unregister the exit-handler.
39 
40     This function can be used as a decorator::
41 
42       @atexit.register
43       def handler():
44         ...
45 
46     Notice however that this will bind ``handler`` to the identifier and not the
47     actual exit-handler.  The exit-handler can then be unregistered with::
48 
49       atexit.unregister(handler)
50 
51     This function is thread safe.
52 
53     """
54     global _ident
55     with _lock:
56         ident = _ident
57         _ident += 1
58     _handlers[ident] = (func, args, kwargs, vars(context))
59     return ident
60 
61 def unregister(ident):
62     """unregister(ident)
63 
64     Remove the exit-handler identified by `ident` from the list of registered
65     handlers.  If `ident` isn't registered this is a no-op.
66     """
67     if ident in _handlers:
68         del _handlers[ident]
69 
70 def _run_handlers():
71     """_run_handlers()
72 
73     Run registered exit-handlers.  They run in the reverse order of which they
74     were registered.
75 
76     If a handler raises an exception, it will be printed but nothing else
77     happens, i.e. other handlers will be run and `sys.excepthook` will not be
78     called for that reason.
79     """
80     context.clear()
81     for _ident, (func, args, kwargs, ctx) in \
82         sorted(_handlers.items(), reverse = True):
83         try:
84             with context.local(**ctx):
85                 func(*args, **kwargs)
86         except SystemExit:
87             pass
88         except Exception:
89             # extract the current exception and rewind the traceback to where it
90             # originated
91             typ, val, tb = sys.exc_info()
92             traceback.print_exception(typ, val, tb.tb_next)
93 
94 # if there's already an exitfunc registered be sure to run that too
95 if hasattr(sys, "exitfunc"):
96     register(sys.exitfunc)
97 
98 sys.exitfunc = _run_handlers
99
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pwnlib/atexit.py b/pwnlib/atexit.py
--- a/pwnlib/atexit.py
+++ b/pwnlib/atexit.py
@@ -13,6 +13,7 @@
 import sys
 import threading
 import traceback
+import atexit as std_atexit
 
 from pwnlib.context import context
 
@@ -95,4 +96,8 @@
 if hasattr(sys, "exitfunc"):
     register(sys.exitfunc)
 
-sys.exitfunc = _run_handlers
+if sys.version_info[0] < 3:
+    sys.exitfunc = _run_handlers
+else:
+    std_atexit.register(_run_handlers)
+

{"golden_diff": "diff --git a/pwnlib/atexit.py b/pwnlib/atexit.py\n--- a/pwnlib/atexit.py\n+++ b/pwnlib/atexit.py\n@@ -13,6 +13,7 @@\n import sys\n import threading\n import traceback\n+import atexit as std_atexit\n \n from pwnlib.context import context\n \n@@ -95,4 +96,8 @@\n if hasattr(sys, \"exitfunc\"):\n     register(sys.exitfunc)\n \n-sys.exitfunc = _run_handlers\n+if sys.version_info[0] < 3:\n+    sys.exitfunc = _run_handlers\n+else:\n+    std_atexit.register(_run_handlers)\n+\n", "issue": "`atexit.register` does not work\n### What I did\r\n```python3\r\nfrom pwn import *\r\natexit.register(print, \"hello world\")\r\nexit()\r\n```\r\n### What I expected to see\r\n```python3 test.py\r\nhello world\r\n```\r\n### What I saw\r\nNothing\r\n\r\nI noticed this because `asm()`, which adds an `atexit` handler to remove the `/tmp/pwn-asm-XXXXXX` folder, does not in fact remove it, meaning multiple script runs leads to many similar folders.\n", "before_files": [{"content": "\"\"\"\nReplacement for the Python standard library's atexit.py.\n\nWhereas the standard :mod:`atexit` module only defines :func:`atexit.register`,\nthis replacement module also defines :func:`unregister`.\n\nThis module also fixes a the issue that exceptions raised by an exit handler is\nprinted twice when the standard :mod:`atexit` is used.\n\"\"\"\nfrom __future__ import absolute_import\nfrom __future__ import division\n\nimport sys\nimport threading\nimport traceback\n\nfrom pwnlib.context import context\n\n__all__ = ['register', 'unregister']\n\n_lock = threading.Lock()\n_ident = 0\n_handlers = {}\n\ndef register(func, *args, **kwargs):\n    \"\"\"register(func, *args, **kwargs)\n\n    Registers a function to be called on program termination.  The function will\n    be called with positional arguments `args` and keyword arguments `kwargs`,\n    i.e. ``func(*args, **kwargs)``.  The current `context` is recorded and will\n    be the one used when the handler is run.\n\n    E.g. to suppress logging output from an exit-handler one could write::\n\n      with context.local(log_level = 'error'):\n        atexit.register(handler)\n\n    An identifier is returned which can be used to unregister the exit-handler.\n\n    This function can be used as a decorator::\n\n      @atexit.register\n      def handler():\n        ...\n\n    Notice however that this will bind ``handler`` to the identifier and not the\n    actual exit-handler.  The exit-handler can then be unregistered with::\n\n      atexit.unregister(handler)\n\n    This function is thread safe.\n\n    \"\"\"\n    global _ident\n    with _lock:\n        ident = _ident\n        _ident += 1\n    _handlers[ident] = (func, args, kwargs, vars(context))\n    return ident\n\ndef unregister(ident):\n    \"\"\"unregister(ident)\n\n    Remove the exit-handler identified by `ident` from the list of registered\n    handlers.  If `ident` isn't registered this is a no-op.\n    \"\"\"\n    if ident in _handlers:\n        del _handlers[ident]\n\ndef _run_handlers():\n    \"\"\"_run_handlers()\n\n    Run registered exit-handlers.  They run in the reverse order of which they\n    were registered.\n\n    If a handler raises an exception, it will be printed but nothing else\n    happens, i.e. other handlers will be run and `sys.excepthook` will not be\n    called for that reason.\n    \"\"\"\n    context.clear()\n    for _ident, (func, args, kwargs, ctx) in \\\n        sorted(_handlers.items(), reverse = True):\n        try:\n            with context.local(**ctx):\n                func(*args, **kwargs)\n        except SystemExit:\n            pass\n        except Exception:\n            # extract the current exception and rewind the traceback to where it\n            # originated\n            typ, val, tb = sys.exc_info()\n            traceback.print_exception(typ, val, tb.tb_next)\n\n# if there's already an exitfunc registered be sure to run that too\nif hasattr(sys, \"exitfunc\"):\n    register(sys.exitfunc)\n\nsys.exitfunc = _run_handlers\n", "path": "pwnlib/atexit.py"}], "after_files": [{"content": "\"\"\"\nReplacement for the Python standard library's atexit.py.\n\nWhereas the standard :mod:`atexit` module only defines :func:`atexit.register`,\nthis replacement module also defines :func:`unregister`.\n\nThis module also fixes a the issue that exceptions raised by an exit handler is\nprinted twice when the standard :mod:`atexit` is used.\n\"\"\"\nfrom __future__ import absolute_import\nfrom __future__ import division\n\nimport sys\nimport threading\nimport traceback\nimport atexit as std_atexit\n\nfrom pwnlib.context import context\n\n__all__ = ['register', 'unregister']\n\n_lock = threading.Lock()\n_ident = 0\n_handlers = {}\n\ndef register(func, *args, **kwargs):\n    \"\"\"register(func, *args, **kwargs)\n\n    Registers a function to be called on program termination.  The function will\n    be called with positional arguments `args` and keyword arguments `kwargs`,\n    i.e. ``func(*args, **kwargs)``.  The current `context` is recorded and will\n    be the one used when the handler is run.\n\n    E.g. to suppress logging output from an exit-handler one could write::\n\n      with context.local(log_level = 'error'):\n        atexit.register(handler)\n\n    An identifier is returned which can be used to unregister the exit-handler.\n\n    This function can be used as a decorator::\n\n      @atexit.register\n      def handler():\n        ...\n\n    Notice however that this will bind ``handler`` to the identifier and not the\n    actual exit-handler.  The exit-handler can then be unregistered with::\n\n      atexit.unregister(handler)\n\n    This function is thread safe.\n\n    \"\"\"\n    global _ident\n    with _lock:\n        ident = _ident\n        _ident += 1\n    _handlers[ident] = (func, args, kwargs, vars(context))\n    return ident\n\ndef unregister(ident):\n    \"\"\"unregister(ident)\n\n    Remove the exit-handler identified by `ident` from the list of registered\n    handlers.  If `ident` isn't registered this is a no-op.\n    \"\"\"\n    if ident in _handlers:\n        del _handlers[ident]\n\ndef _run_handlers():\n    \"\"\"_run_handlers()\n\n    Run registered exit-handlers.  They run in the reverse order of which they\n    were registered.\n\n    If a handler raises an exception, it will be printed but nothing else\n    happens, i.e. other handlers will be run and `sys.excepthook` will not be\n    called for that reason.\n    \"\"\"\n    context.clear()\n    for _ident, (func, args, kwargs, ctx) in \\\n        sorted(_handlers.items(), reverse = True):\n        try:\n            with context.local(**ctx):\n                func(*args, **kwargs)\n        except SystemExit:\n            pass\n        except Exception:\n            # extract the current exception and rewind the traceback to where it\n            # originated\n            typ, val, tb = sys.exc_info()\n            traceback.print_exception(typ, val, tb.tb_next)\n\n# if there's already an exitfunc registered be sure to run that too\nif hasattr(sys, \"exitfunc\"):\n    register(sys.exitfunc)\n\nif sys.version_info[0] < 3:\n    sys.exitfunc = _run_handlers\nelse:\n    std_atexit.register(_run_handlers)\n\n", "path": "pwnlib/atexit.py"}]}