ros / ros_comm

ROS communications-related packages, including core client libraries (roscpp, rospy, roslisp) and graph introspection tools (rostopic, rosnode, rosservice, rosparam).
http://wiki.ros.org/ros_comm
752 stars 911 forks source link

Rosbag throws TypeError 'Handlers' object not callable when SIGINT or SIGTERM handler are signal.SIG_IGN or signal.SIG_DFL #2235

Closed ynager closed 1 day ago

ynager commented 2 years ago

Issue:

When using e.g. rosbag record in a process with no signal handler installed, or signal handlers of type SIG_IGN, SIG_DFL, rosbag_main.py will throw TypeError: 'Handlers' object is not callable :

Traceback (most recent call last):
  File "/opt/ros/noetic/bin/rosbag", line 35, in <module>
    rosbag.rosbagmain()
  File "/opt/ros/noetic/lib/python3/dist-packages/rosbag/rosbag_main.py", line 1032, in rosbagmain
    cmds[cmd](argv[2:])
  File "/opt/ros/noetic/lib/python3/dist-packages/rosbag/rosbag_main.py", line 161, in record_cmd
    process.wait()
  File "/usr/lib/python3.6/subprocess.py", line 1477, in wait
    (pid, sts) = self._try_wait(0)
  File "/usr/lib/python3.6/subprocess.py", line 1424, in _try_wait
    (pid, sts) = os.waitpid(self.pid, wait_flags)
  File "/opt/ros/noetic/lib/python3/dist-packages/rosbag/rosbag_main.py", line 155, in <lambda>
    lambda signum, frame: _send_process_sigint(signum, frame, old_handler, process)
  File "/opt/ros/noetic/lib/python3/dist-packages/rosbag/rosbag_main.py", line 78, in _send_process_sigint
    old_handler(signum, frame)
TypeError: 'Handlers' object is not callable

Explanation:

The following snippets in rosbag_main.py assume that old_handler is callable, and therefore throw the error if this is not the case.

https://github.com/ros/ros_comm/blob/3f8eca4a1f13996b33c03a5c4ee3a69fb0db3668/tools/rosbag/src/rosbag/rosbag_main.py#L69-L72 https://github.com/ros/ros_comm/blob/3f8eca4a1f13996b33c03a5c4ee3a69fb0db3668/tools/rosbag/src/rosbag/rosbag_main.py#L75-L78

old_handler is set by calling signal.signal(), which returns either a callable function or a non-callable special value of either signal.SIG_IGN, signal.SIG_DFL or None. However, only for the case where the handler is None is protected.

https://python.readthedocs.io/en/latest/library/signal.html#signal.signal

Minimal example

Running this script and then killing the spawned python3 process with kill -s INT [PID] will throw the error. The ampersand will make the process inherit SIG_IGN settings for SIGINT and SIGQUIT.

 #!/bin/bash
rosbag record -a &

Possible solution

To avoid calling a non-callable object, replace lines https://github.com/ros/ros_comm/blob/3f8eca4a1f13996b33c03a5c4ee3a69fb0db3668/tools/rosbag/src/rosbag/rosbag_main.py#L71 https://github.com/ros/ros_comm/blob/3f8eca4a1f13996b33c03a5c4ee3a69fb0db3668/tools/rosbag/src/rosbag/rosbag_main.py#L77

with
if callable(old_handler):

Similar issue in python-socketio: https://github.com/miguelgrinberg/python-socketio/issues/517