Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion rclpy/rclpy/impl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,20 @@


def _import(name):
dll_dir_handles = []
try:
return importlib.import_module(name, package='rclpy')
# New in Python 3.8: on Windows we should call 'add_dll_directory()' for directories
# containing DLLs we depend on.
# https://docs.python.org/3/whatsnew/3.8.html#bpo-36085-whatsnew
if os.name == 'nt':
Comment thread
jacobperron marked this conversation as resolved.
Outdated
path_env = os.environ['PATH'].split(';')

@dirk-thomas dirk-thomas May 14, 2020

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a reason why Python chose to not use all paths in PATH. Maybe it would be better to not bypass this mechanism entirely but select specific paths only to be added, e.g. rclpy.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Message packages should probably contain their own logic to ensure their path is added too.

@jacobperron jacobperron May 14, 2020

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a reason why Python chose to not use all paths in PATH

What I gather from the issue[1] is that where DLLs are loaded from was not consistent before Python 3.8 (e.g. in general, you couldn't assume that PATH was ever searched for DLLs; it was using the process default ordering[2]), which has some security implications[3]. The change in Python 3.8 forces a consistent search order.

The reason to not include PATH in the search order is a little above my head, but I think it boils down to a minimizing the risk of a so-called DLL preloading attack. I agree we could try down-selecting to just what we need, though I'm not sure of a proper way to achieve this. Maybe using CMake variables that are exported by packages producing DLLs? Also, I guess there will be other DLLs installed on the system we rely on that should also be added (e.g. OpenSSL).


[1] https://bugs.python.org/issue36085
[2] https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order
[3] https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-security

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you're right. rosidl_generator_py needs a similar patch. Pretty much anywhere we use importlib.import_module.

for prefix_path in path_env:
if os.path.exists(prefix_path):
dll_dir_handles.append(os.add_dll_directory(prefix_path))

imported_module = importlib.import_module(name, package='rclpy')

return imported_module
except ImportError as e:
if e.path is not None and os.path.isfile(e.path):
e.msg += \
Expand All @@ -27,3 +39,6 @@ def _import(name):
(e.path, 'https://index.ros.org/doc/ros2/Troubleshooting/'
'#import-failing-even-with-library-present-on-the-system')
raise
finally:
for handle in dll_dir_handles:
handle.close()