diff options
author | Banjamin Freeman <befreeman@users.noreply.github.com> | 2018-05-14 16:46:52 -0400 |
---|---|---|
committer | Claudiu Popa <pcmanticore@gmail.com> | 2018-05-14 16:46:52 -0400 |
commit | 56e8ec2ddcfd62a6b15baab1efa70ed3311a9a21 (patch) | |
tree | 8d64824e19dc9e0de8559bafded5ae381df39a8a /pylint/checkers/stdlib.py | |
parent | 75a68fb5be105e138ca9527b0fc5c7e02b1a15e5 (diff) | |
download | pylint-git-56e8ec2ddcfd62a6b15baab1efa70ed3311a9a21.tar.gz |
Warn when using subprocess.Popen preexec_fn kwarg (#2087)
Close #1195
Diffstat (limited to 'pylint/checkers/stdlib.py')
-rw-r--r-- | pylint/checkers/stdlib.py | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/pylint/checkers/stdlib.py b/pylint/checkers/stdlib.py index c8e071a22..77bc936c7 100644 --- a/pylint/checkers/stdlib.py +++ b/pylint/checkers/stdlib.py @@ -34,6 +34,7 @@ THREADING_THREAD = 'threading.Thread' COPY_COPY = 'copy.copy' OS_ENVIRON = 'os._Environ' ENV_GETTERS = {'os.getenv'} +SUBPROCESS_POPEN = 'subprocess.Popen' if sys.version_info >= (3, 0): OPEN_MODULE = '_io' @@ -120,6 +121,14 @@ class StdlibChecker(BaseChecker): 'Env manipulation functions return None or str values. ' 'Supplying anything different as a default may cause bugs. ' 'See https://docs.python.org/3/library/os.html#os.getenv. '), + 'W1509': ('Using preexec_fn keyword which may be unsafe in the presence ' + 'of threads', + 'subprocess-popen-preexec-fn', + 'The preexec_fn parameter is not safe to use in the presence ' + 'of threads in your application. The child process could ' + 'deadlock before exec is called. If you must use it, keep it ' + 'trivial! Minimize the number of libraries you call into.' + 'https://docs.python.org/3/library/subprocess.html#popen-constructor'), } @@ -202,6 +211,12 @@ class StdlibChecker(BaseChecker): if not node.kwargs and not node.keywords and len(node.args) <= 1: self.add_message('bad-thread-instantiation', node=node) + def _check_for_preexec_fn_in_Popen(self, node): + if node.keywords: + for keyword in node.keywords: + if keyword.arg == 'preexec_fn': + self.add_message('subprocess-popen-preexec-fn', node=node) + def _check_shallow_copy_environ(self, node): arg = utils.get_argument_from_call(node, position=0) for inferred in arg.inferred(): @@ -215,7 +230,8 @@ class StdlibChecker(BaseChecker): 'bad-thread-instantiation', 'shallow-copy-environ', 'invalid-envvar-value', - 'invalid-envvar-default') + 'invalid-envvar-default', + 'subprocess-popen-preexec-fn') def visit_call(self, node): """Visit a Call node.""" try: @@ -227,9 +243,11 @@ class StdlibChecker(BaseChecker): self._check_open_mode(node) elif inferred.root().name == UNITTEST_CASE: self._check_redundant_assert(node, inferred) - elif (isinstance(inferred, astroid.ClassDef) - and inferred.qname() == THREADING_THREAD): - self._check_bad_thread_instantiation(node) + elif isinstance(inferred, astroid.ClassDef): + if inferred.qname() == THREADING_THREAD: + self._check_bad_thread_instantiation(node) + elif inferred.qname() == SUBPROCESS_POPEN: + self._check_for_preexec_fn_in_Popen(node) elif isinstance(inferred, astroid.FunctionDef): name = inferred.qname() if name == COPY_COPY: |