Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 195
FIX check the type of the entries in sys.modules#326
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
pierreglaser
merged 14 commits into
cloudpipe:master
from
pierreglaser:fix-faulty-module-interaction-pypyJan 28, 2020
Uh oh!
There was an error while loading. Please reload this page.
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
4093b02
FIX check the type of the entries in sys.modules
pierreglaser 35278d7
Merge branch 'master' into fix-faulty-module-interaction-pypy
pierreglaser 8348cff
add a test of a faulty module tricking whichmodule
pierreglaser f746c5d
also test faulty modules that are module instances
pierreglaser 5da8b99
missing import statement
pierreglaser 773f0d1
FIX hide func's __module__
pierreglaser 4e82270
Update tests/cloudpickle_test.py
pierreglaser 2ddf962
Update tests/cloudpickle_test.py
pierreglaser f416909
add more inline comments describing the issue
pierreglaser bbbdfab
MNT update changelog
pierreglaser 090a3b3
DOC more test comments
pierreglaser f1c0ac8
Merge branch 'master' into fix-faulty-module-interaction-pypy
pierreglaser 2d5e601
CLN typos
pierreglaser 12677e6
Merge branch 'fix-faulty-module-interaction-pypy' of https://github.c…
pierreglaser File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -42,7 +42,7 @@ | ||
| import cloudpickle | ||
| from cloudpickle.cloudpickle import _is_dynamic | ||
| from cloudpickle.cloudpickle import _make_empty_cell, cell_set | ||
| from cloudpickle.cloudpickle import _extract_class_dict | ||
| from cloudpickle.cloudpickle import _extract_class_dict, _whichmodule | ||
| from .testutils import subprocess_pickle_echo | ||
| from .testutils import assert_run_python_script | ||
| @@ -1048,35 +1048,94 @@ def __init__(self, x): | ||
| self.assertEqual(set(weakset), {depickled1, depickled2}) | ||
| def test_faulty_module(self): | ||
| for module_name in ['_missing_module', None]: | ||
| class FaultyModule(object): | ||
| def __getattr__(self, name): | ||
| # This throws an exception while looking up within | ||
| # pickle.whichmodule or getattr(module, name, None) | ||
| raise Exception() | ||
| def test_non_module_object_passing_whichmodule_test(self): | ||
| # https://github.com/cloudpipe/cloudpickle/pull/326: cloudpickle should | ||
| # not try to instrospect non-modules object when trying to discover the | ||
| # module of a function/class. This happenened because codecov injects | ||
| # tuples (and not modules) into sys.modules, but type-checks were not | ||
| # carried out on the entries of sys.modules, causing cloupdickle to | ||
| # then error in unexpected ways | ||
| def func(x): | ||
| return x ** 2 | ||
| # Trigger a loop during the execution of whichmodule(func) by | ||
| # explicitly setting the function's module to None | ||
| func.__module__ = None | ||
pierreglaser marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| class NonModuleObject(object): | ||
| def __getattr__(self, name): | ||
| # We whitelist func so that a _whichmodule(func, None) call returns | ||
| # the NonModuleObject instance if a type check on the entries | ||
| # of sys.modules is not carried out, but manipulating this | ||
| # instance thinking it really is a module later on in the | ||
| # pickling process of func errors out | ||
| if name == 'func': | ||
| return func | ||
| else: | ||
| raise AttributeError | ||
| non_module_object = NonModuleObject() | ||
| assert func(2) == 4 | ||
| assert func is non_module_object.func | ||
| # Any manipulation of non_module_object relying on attribute access | ||
| # will raise an Exception | ||
| with pytest.raises(AttributeError): | ||
| _is_dynamic(non_module_object) | ||
| try: | ||
| sys.modules['NonModuleObject'] = non_module_object | ||
| class Foo(object): | ||
| __module__ = module_name | ||
| func_module_name = _whichmodule(func, None) | ||
| assert func_module_name != 'NonModuleObject' | ||
| assert func_module_name is None | ||
| def foo(self): | ||
| depickled_func = pickle_depickle(func, protocol=self.protocol) | ||
| assert depickled_func(2) == 4 | ||
| finally: | ||
| sys.modules.pop('NonModuleObject') | ||
| def test_unrelated_faulty_module(self): | ||
| # Check that pickling a dynamically defined function or class does not | ||
| # fail when introspecting the currently loaded modules in sys.modules | ||
| # as long as those faulty modules are unrelated to the class or | ||
| # function we are currently pickling. | ||
| for base_class in (object, types.ModuleType): | ||
| for module_name in ['_missing_module', None]: | ||
| class FaultyModule(base_class): | ||
| def __getattr__(self, name): | ||
| # This throws an exception while looking up within | ||
| # pickle.whichmodule or getattr(module, name, None) | ||
| raise Exception() | ||
| class Foo(object): | ||
| __module__ = module_name | ||
| def foo(self): | ||
| return "it works!" | ||
| def foo(): | ||
| return "it works!" | ||
| def foo(): | ||
| return "it works!" | ||
| foo.__module__ = module_name | ||
| foo.__module__ = module_name | ||
| if base_class is types.ModuleType: # noqa | ||
| faulty_module = FaultyModule('_faulty_module') | ||
| else: | ||
| faulty_module = FaultyModule() | ||
| sys.modules["_faulty_module"] = faulty_module | ||
| sys.modules["_faulty_module"] = FaultyModule() | ||
| try: | ||
| # Test whichmodule in save_global. | ||
| self.assertEqual(pickle_depickle(Foo()).foo(), "it works!") | ||
| try: | ||
| # Test whichmodule in save_global. | ||
| self.assertEqual(pickle_depickle(Foo()).foo(), "it works!") | ||
| # Test whichmodule in save_function. | ||
| cloned = pickle_depickle(foo, protocol=self.protocol) | ||
| self.assertEqual(cloned(), "it works!") | ||
| finally: | ||
| sys.modules.pop("_faulty_module", None) | ||
| # Test whichmodule in save_function. | ||
| cloned = pickle_depickle(foo, protocol=self.protocol) | ||
| self.assertEqual(cloned(), "it works!") | ||
| finally: | ||
| sys.modules.pop("_faulty_module", None) | ||
| def test_dynamic_pytest_module(self): | ||
| # Test case for pull request https://github.com/cloudpipe/cloudpickle/pull/116 | ||
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.