# Buggy code
def _bare_run(self, cmd, in_data, sudoable=True, checkrc=True):
    """
    Starts the command and communicates with it until it ends.
    """

    # We don't use _shell.quote as this is run on the controller and independent from the shell plugin chosen
    display_cmd = list(map(shlex_quote, map(to_text, cmd)))
    display.vvv("SSH: EXEC {0}".format(" ".join(display_cmd)), host=self.host)

    # Start the given command. If we don't need to pipeline data, we can try
    # to use a pseudo-tty (ssh will have been invoked with -tt). If we are
    # pipelining data, or can't create a pty, we fall back to using plain
    # old pipes.

    p = None

    if isinstance(cmd, (text_type, binary_type)):
        cmd = to_bytes(cmd)
    else:
        cmd = list(map(to_bytes, cmd))

    if not in_data:
        try:
            # Make sure stdin is a proper pty to avoid tcgetattr errors
            master, slave = pty.openpty()
            if PY3 and self._play_context.password:
                # pylint: disable=unexpected-keyword-arg
                p = subprocess.Popen(
                    cmd,
                    stdin=slave,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                    pass_fds=self.sshpass_pipe,
                )
            else:
                p = subprocess.Popen(
                    cmd, stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE
                )
            stdin = os.fdopen(master, "wb", 0)
            os.close(slave)
        except (OSError, IOError):
            p = None

    if not p:
        if PY3 and self._play_context.password:
            # pylint: disable=unexpected-keyword-arg
            p = subprocess.Popen(
                cmd,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                pass_fds=self.sshpass_pipe,
            )
        else:
            p = subprocess.Popen(
                cmd,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
        stdin = p.stdin

    # If we are using SSH password authentication, write the password into
    # the pipe we opened in _build_command.

    if self._play_context.password:
        os.close(self.sshpass_pipe[0])
        try:
            os.write(
                self.sshpass_pipe[1], to_bytes(self._play_context.password) + b"\n"
            )
        except OSError as e:
            # Ignore broken pipe errors if the sshpass process has exited.
            if e.errno != errno.EPIPE or p.poll() is None:
                raise
        os.close(self.sshpass_pipe[1])

    #
    # SSH state machine
    #

    # Now we read and accumulate output from the running process until it
    # exits. Depending on the circumstances, we may also need to write an
    # escalation password and/or pipelined input to the process.

    states = [
        "awaiting_prompt",
        "awaiting_escalation",
        "ready_to_send",
        "awaiting_exit",
    ]

    # Are we requesting privilege escalation? Right now, we may be invoked
    # to execute sftp/scp with sudoable=True, but we can request escalation
    # only when using ssh. Otherwise we can send initial data straightaway.

    state = states.index("ready_to_send")
    if to_bytes(self.get_option("ssh_executable")) in cmd and sudoable:
        prompt = getattr(self.become, "prompt", None)
        if prompt:
            # We're requesting escalation with a password, so we have to
            # wait for a password prompt.
            state = states.index("awaiting_prompt")
            display.debug("Initial state: %s: %s" % (states[state], prompt))
        elif self._play_context.become and self._play_context.success_key:
            # We're requesting escalation without a password, so we have to
            # detect success/failure before sending any initial data.
            state = states.index("awaiting_escalation")
            display.debug(
                "Initial state: %s: %s"
                % (states[state], self._play_context.success_key)
            )

    # We store accumulated stdout and stderr output from the process here,
    # but strip any privilege escalation prompt/confirmation lines first.
    # Output is accumulated into tmp_*, complete lines are extracted into
    # an array, then checked and removed or copied to stdout or stderr. We
    # set any flags based on examining the output in self._flags.

    b_stdout = b_stderr = b""
    b_tmp_stdout = b_tmp_stderr = b""

    self._flags = dict(
        become_prompt=False,
        become_success=False,
        become_error=False,
        become_nopasswd_error=False,
    )

    # select timeout should be longer than the connect timeout, otherwise
    # they will race each other when we can't connect, and the connect
    # timeout usually fails
    timeout = 2 + self._play_context.timeout
    for fd in (p.stdout, p.stderr):
        fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)

    # TODO: bcoca would like to use SelectSelector() when open
    # filehandles is low, then switch to more efficient ones when higher.
    # select is faster when filehandles is low.
    selector = selectors.DefaultSelector()
    selector.register(p.stdout, selectors.EVENT_READ)
    selector.register(p.stderr, selectors.EVENT_READ)

    # If we can send initial data without waiting for anything, we do so
    # before we start polling
    if states[state] == "ready_to_send" and in_data:
        self._send_initial_data(stdin, in_data, p)
        state += 1

    try:
        while True:
            poll = p.poll()
            events = selector.select(timeout)

            # We pay attention to timeouts only while negotiating a prompt.

            if not events:
                # We timed out
                if state <= states.index("awaiting_escalation"):
                    # If the process has already exited, then it's not really a
                    # timeout; we'll let the normal error handling deal with it.
                    if poll is not None:
                        break
                    self._terminate_process(p)
                    raise AnsibleError(
                        "Timeout (%ds) waiting for privilege escalation prompt: %s"
                        % (timeout, to_native(b_stdout))
                    )

            # Read whatever output is available on stdout and stderr, and stop
            # listening to the pipe if it's been closed.

            for key, event in events:
                if key.fileobj == p.stdout:
                    b_chunk = p.stdout.read()
                    if b_chunk == b"":
                        # stdout has been closed, stop watching it
                        selector.unregister(p.stdout)
                        # When ssh has ControlMaster (+ControlPath/Persist) enabled, the
                        # first connection goes into the background and we never see EOF
                        # on stderr. If we see EOF on stdout, lower the select timeout
                        # to reduce the time wasted selecting on stderr if we observe
                        # that the process has not yet existed after this EOF. Otherwise
                        # we may spend a long timeout period waiting for an EOF that is
                        # not going to arrive until the persisted connection closes.
                        timeout = 1
                    b_tmp_stdout += b_chunk
                    display.debug(
                        "stdout chunk (state=%s):\n>>>%s<<<\n"
                        % (state, to_text(b_chunk))
                    )
                elif key.fileobj == p.stderr:
                    b_chunk = p.stderr.read()
                    if b_chunk == b"":
                        # stderr has been closed, stop watching it
                        selector.unregister(p.stderr)
                    b_tmp_stderr += b_chunk
                    display.debug(
                        "stderr chunk (state=%s):\n>>>%s<<<\n"
                        % (state, to_text(b_chunk))
                    )

            # We examine the output line-by-line until we have negotiated any
            # privilege escalation prompt and subsequent success/error message.
            # Afterwards, we can accumulate output without looking at it.

            if state < states.index("ready_to_send"):
                if b_tmp_stdout:
                    b_output, b_unprocessed = self._examine_output(
                        "stdout", states[state], b_tmp_stdout, sudoable
                    )
                    b_stdout += b_output
                    b_tmp_stdout = b_unprocessed

                if b_tmp_stderr:
                    b_output, b_unprocessed = self._examine_output(
                        "stderr", states[state], b_tmp_stderr, sudoable
                    )
                    b_stderr += b_output
                    b_tmp_stderr = b_unprocessed
            else:
                b_stdout += b_tmp_stdout
                b_stderr += b_tmp_stderr
                b_tmp_stdout = b_tmp_stderr = b""

            # If we see a privilege escalation prompt, we send the password.
            # (If we're expecting a prompt but the escalation succeeds, we
            # didn't need the password and can carry on regardless.)

            if states[state] == "awaiting_prompt":
                if self._flags["become_prompt"]:
                    display.debug("Sending become_password in response to prompt")
                    stdin.write(to_bytes(self._play_context.become_pass) + b"\n")
                    # On python3 stdin is a BufferedWriter, and we don't have a guarantee
                    # that the write will happen without a flush
                    stdin.flush()
                    self._flags["become_prompt"] = False
                    state += 1
                elif self._flags["become_success"]:
                    state += 1

            # We've requested escalation (with or without a password), now we
            # wait for an error message or a successful escalation.

            if states[state] == "awaiting_escalation":
                if self._flags["become_success"]:
                    display.vvv("Escalation succeeded")
                    self._flags["become_success"] = False
                    state += 1
                elif self._flags["become_error"]:
                    display.vvv("Escalation failed")
                    self._terminate_process(p)
                    self._flags["become_error"] = False
                    raise AnsibleError(
                        "Incorrect %s password" % self._play_context.become_method
                    )
                elif self._flags["become_nopasswd_error"]:
                    display.vvv("Escalation requires password")
                    self._terminate_process(p)
                    self._flags["become_nopasswd_error"] = False
                    raise AnsibleError(
                        "Missing %s password" % self._play_context.become_method
                    )
                elif self._flags["become_prompt"]:
                    # This shouldn't happen, because we should see the "Sorry,
                    # try again" message first.
                    display.vvv("Escalation prompt repeated")
                    self._terminate_process(p)
                    self._flags["become_prompt"] = False
                    raise AnsibleError(
                        "Incorrect %s password" % self._play_context.become_method
                    )

            # Once we're sure that the privilege escalation prompt, if any, has
            # been dealt with, we can send any initial data and start waiting
            # for output.

            if states[state] == "ready_to_send":
                if in_data:
                    self._send_initial_data(stdin, in_data, p)
                state += 1

            # Now we're awaiting_exit: has the child process exited? If it has,
            # and we've read all available output from it, we're done.

            if poll is not None:
                if not selector.get_map() or not events:
                    break
                # We should not see further writes to the stdout/stderr file
                # descriptors after the process has closed, set the select
                # timeout to gather any last writes we may have missed.
                timeout = 0
                continue

            # If the process has not yet exited, but we've already read EOF from
            # its stdout and stderr (and thus no longer watching any file
            # descriptors), we can just wait for it to exit.

            elif not selector.get_map():
                p.wait()
                break

            # Otherwise there may still be outstanding data to read.
    finally:
        selector.close()
        # close stdin after process is terminated and stdout/stderr are read
        # completely (see also issue #848)
        stdin.close()

    if C.HOST_KEY_CHECKING:
        if cmd[0] == b"sshpass" and p.returncode == 6:
            raise AnsibleError(
                "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support "
                "this.  Please add this host's fingerprint to your known_hosts file to manage this host."
            )

    controlpersisterror = (
        b"Bad configuration option: ControlPersist" in b_stderr
        or b"unknown configuration option: ControlPersist" in b_stderr
    )
    if p.returncode != 0 and controlpersisterror:
        raise AnsibleError(
            'using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" '
            "(or ssh_args in [ssh_connection] section of the config file) before running again"
        )

    # If we find a broken pipe because of ControlPersist timeout expiring (see #16731),
    # we raise a special exception so that we can retry a connection.
    controlpersist_broken_pipe = (
        b"mux_client_hello_exchange: write packet: Broken pipe" in b_stderr
    )
    if p.returncode == 255:
        additional = to_native(b_stderr)
        if controlpersist_broken_pipe:
            raise AnsibleControlPersistBrokenPipeError(
                "Data could not be sent because of ControlPersist broken pipe: %s"
                % additional
            )

        elif in_data and checkrc:
            raise AnsibleConnectionFailure(
                'Data could not be sent to remote host "%s". Make sure this host can be reached over ssh: %s'
                % (self.host, additional)
            )

    return (p.returncode, b_stdout, b_stderr)


# Traceback (UnicodeDecodeError)
TASK [stat] *************************************************************************************************************************************************************
task path: /home/jenkins/playbook.yml:3
Friday 14 June 2019  10:36:17 +0200 (0:00:00.170)       0:00:00.170 ***********
Using module file /jenkins/test/ansible/lib/python2.6/site-packages/ansible/modules/files/stat.py
<server> ESTABLISH SSH CONNECTION FOR USER: myuser
<server> SSH: EXEC ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no -o Port=22 -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=myuser -o ConnectTimeout=20 server '/bin/sh -c '"'"'/usr/bin/python &amp;&amp; sleep 0'"'"''
<server> (1, '\n{"msg": "Permission denied", "failed": true, "exception": "  File \\"/tmp/ansible_Vvkdbf/ansible_module_stat.py\\", line 476, in main\\n    st = os.lstat(b_path)\\n", "invocation": {"module_args": {"checksum_algorithm": "sha1", "get_checksum": true, "follow": false, "path": "/home/anotheruser/lvi", "get_md5": null, "get_mime": true, "get_attributes": true}}}\n', "ATTENTION:\nQuiconque acc\xc3\xa9derait ou tenterait d'acc\xc3\xa9der \xc3\xa0 ce syst\xc3\xa8me.\n\n")
The full traceback is:
Traceback (most recent call last):
File "/jenkins/test/ansible/lib/python2.6/site-packages/ansible/executor/task_executor.py", line 139, in run
res = self._execute()
File "/jenkins/test/ansible/lib/python2.6/site-packages/ansible/executor/task_executor.py", line 584, in _execute
result = self._handler.run(task_vars=variables)
File "/jenkins/test/ansible/lib/python2.6/site-packages/ansible/plugins/action/normal.py", line 46, in run
result = merge_hash(result, self._execute_module(task_vars=task_vars, wrap_async=wrap_async))
File "/jenkins/test/ansible/lib/python2.6/site-packages/ansible/plugins/action/__init__.py", line 853, in _execute_module
res = self._low_level_execute_command(cmd, sudoable=sudoable, in_data=in_data)
File "/jenkins/test/ansible/lib/python2.6/site-packages/ansible/plugins/action/__init__.py", line 960, in _low_level_execute_command
rc, stdout, stderr = self._connection.exec_command(cmd, in_data=in_data, sudoable=sudoable)
File "/jenkins/test/ansible/lib/python2.6/site-packages/ansible/plugins/connection/ssh.py", line 1080, in exec_command
(returncode, stdout, stderr) = self._run(cmd, in_data, sudoable=sudoable)
File "/jenkins/test/ansible/lib/python2.6/site-packages/ansible/plugins/connection/ssh.py", line 354, in wrapped
_handle_error(remaining_retries, cmd[0], return_tuple, self._play_context.no_log, self.host)
File "/jenkins/test/ansible/lib/python2.6/site-packages/ansible/plugins/connection/ssh.py", line 307, in _handle_error
display.vvv(msg, host=host)
File "/jenkins/test/ansible/lib/python2.6/site-packages/ansible/utils/display.py", line 183, in vvv
return self.verbose(msg, host=host, caplevel=2)
File "/jenkins/test/ansible/lib/python2.6/site-packages/ansible/utils/display.py", line 206, in verbose
self.display("<%s> %s" % (host, msg), color=C.COLOR_VERBOSE, screen_only=True)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 63: ordinal not in range(128)

fatal: [server]: FAILED! => {
"msg": "Unexpected failure during module execution.",
"stdout": ""
}

# Fixed code
def _bare_run(self, cmd, in_data, sudoable=True, checkrc=True):
    """
    Starts the command and communicates with it until it ends.
    """

    # We don't use _shell.quote as this is run on the controller and independent from the shell plugin chosen
    display_cmd = " ".join(shlex_quote(to_text(c)) for c in cmd)
    display.vvv("SSH: EXEC {0}".format(display_cmd), host=self.host)

    # Start the given command. If we don't need to pipeline data, we can try
    # to use a pseudo-tty (ssh will have been invoked with -tt). If we are
    # pipelining data, or can't create a pty, we fall back to using plain
    # old pipes.

    p = None

    if isinstance(cmd, (text_type, binary_type)):
        cmd = to_bytes(cmd)
    else:
        cmd = list(map(to_bytes, cmd))

    if not in_data:
        try:
            # Make sure stdin is a proper pty to avoid tcgetattr errors
            master, slave = pty.openpty()
            if PY3 and self._play_context.password:
                # pylint: disable=unexpected-keyword-arg
                p = subprocess.Popen(
                    cmd,
                    stdin=slave,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                    pass_fds=self.sshpass_pipe,
                )
            else:
                p = subprocess.Popen(
                    cmd, stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE
                )
            stdin = os.fdopen(master, "wb", 0)
            os.close(slave)
        except (OSError, IOError):
            p = None

    if not p:
        if PY3 and self._play_context.password:
            # pylint: disable=unexpected-keyword-arg
            p = subprocess.Popen(
                cmd,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                pass_fds=self.sshpass_pipe,
            )
        else:
            p = subprocess.Popen(
                cmd,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
        stdin = p.stdin

    # If we are using SSH password authentication, write the password into
    # the pipe we opened in _build_command.

    if self._play_context.password:
        os.close(self.sshpass_pipe[0])
        try:
            os.write(
                self.sshpass_pipe[1], to_bytes(self._play_context.password) + b"\n"
            )
        except OSError as e:
            # Ignore broken pipe errors if the sshpass process has exited.
            if e.errno != errno.EPIPE or p.poll() is None:
                raise
        os.close(self.sshpass_pipe[1])

    #
    # SSH state machine
    #

    # Now we read and accumulate output from the running process until it
    # exits. Depending on the circumstances, we may also need to write an
    # escalation password and/or pipelined input to the process.

    states = [
        "awaiting_prompt",
        "awaiting_escalation",
        "ready_to_send",
        "awaiting_exit",
    ]

    # Are we requesting privilege escalation? Right now, we may be invoked
    # to execute sftp/scp with sudoable=True, but we can request escalation
    # only when using ssh. Otherwise we can send initial data straightaway.

    state = states.index("ready_to_send")
    if to_bytes(self.get_option("ssh_executable")) in cmd and sudoable:
        prompt = getattr(self.become, "prompt", None)
        if prompt:
            # We're requesting escalation with a password, so we have to
            # wait for a password prompt.
            state = states.index("awaiting_prompt")
            display.debug("Initial state: %s: %s" % (states[state], to_text(prompt)))
        elif self._play_context.become and self.become.success:
            # We're requesting escalation without a password, so we have to
            # detect success/failure before sending any initial data.
            state = states.index("awaiting_escalation")
            display.debug(
                "Initial state: %s: %s" % (states[state], to_text(self.become.success))
            )

    # We store accumulated stdout and stderr output from the process here,
    # but strip any privilege escalation prompt/confirmation lines first.
    # Output is accumulated into tmp_*, complete lines are extracted into
    # an array, then checked and removed or copied to stdout or stderr. We
    # set any flags based on examining the output in self._flags.

    b_stdout = b_stderr = b""
    b_tmp_stdout = b_tmp_stderr = b""

    self._flags = dict(
        become_prompt=False,
        become_success=False,
        become_error=False,
        become_nopasswd_error=False,
    )

    # select timeout should be longer than the connect timeout, otherwise
    # they will race each other when we can't connect, and the connect
    # timeout usually fails
    timeout = 2 + self._play_context.timeout
    for fd in (p.stdout, p.stderr):
        fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)

    # TODO: bcoca would like to use SelectSelector() when open
    # filehandles is low, then switch to more efficient ones when higher.
    # select is faster when filehandles is low.
    selector = selectors.DefaultSelector()
    selector.register(p.stdout, selectors.EVENT_READ)
    selector.register(p.stderr, selectors.EVENT_READ)

    # If we can send initial data without waiting for anything, we do so
    # before we start polling
    if states[state] == "ready_to_send" and in_data:
        self._send_initial_data(stdin, in_data, p)
        state += 1

    try:
        while True:
            poll = p.poll()
            events = selector.select(timeout)

            # We pay attention to timeouts only while negotiating a prompt.

            if not events:
                # We timed out
                if state <= states.index("awaiting_escalation"):
                    # If the process has already exited, then it's not really a
                    # timeout; we'll let the normal error handling deal with it.
                    if poll is not None:
                        break
                    self._terminate_process(p)
                    raise AnsibleError(
                        "Timeout (%ds) waiting for privilege escalation prompt: %s"
                        % (timeout, to_native(b_stdout))
                    )

            # Read whatever output is available on stdout and stderr, and stop
            # listening to the pipe if it's been closed.

            for key, event in events:
                if key.fileobj == p.stdout:
                    b_chunk = p.stdout.read()
                    if b_chunk == b"":
                        # stdout has been closed, stop watching it
                        selector.unregister(p.stdout)
                        # When ssh has ControlMaster (+ControlPath/Persist) enabled, the
                        # first connection goes into the background and we never see EOF
                        # on stderr. If we see EOF on stdout, lower the select timeout
                        # to reduce the time wasted selecting on stderr if we observe
                        # that the process has not yet existed after this EOF. Otherwise
                        # we may spend a long timeout period waiting for an EOF that is
                        # not going to arrive until the persisted connection closes.
                        timeout = 1
                    b_tmp_stdout += b_chunk
                    display.debug(
                        "stdout chunk (state=%s):\n>>>%s<<<\n"
                        % (state, to_text(b_chunk))
                    )
                elif key.fileobj == p.stderr:
                    b_chunk = p.stderr.read()
                    if b_chunk == b"":
                        # stderr has been closed, stop watching it
                        selector.unregister(p.stderr)
                    b_tmp_stderr += b_chunk
                    display.debug(
                        "stderr chunk (state=%s):\n>>>%s<<<\n"
                        % (state, to_text(b_chunk))
                    )

            # We examine the output line-by-line until we have negotiated any
            # privilege escalation prompt and subsequent success/error message.
            # Afterwards, we can accumulate output without looking at it.

            if state < states.index("ready_to_send"):
                if b_tmp_stdout:
                    b_output, b_unprocessed = self._examine_output(
                        "stdout", states[state], b_tmp_stdout, sudoable
                    )
                    b_stdout += b_output
                    b_tmp_stdout = b_unprocessed

                if b_tmp_stderr:
                    b_output, b_unprocessed = self._examine_output(
                        "stderr", states[state], b_tmp_stderr, sudoable
                    )
                    b_stderr += b_output
                    b_tmp_stderr = b_unprocessed
            else:
                b_stdout += b_tmp_stdout
                b_stderr += b_tmp_stderr
                b_tmp_stdout = b_tmp_stderr = b""

            # If we see a privilege escalation prompt, we send the password.
            # (If we're expecting a prompt but the escalation succeeds, we
            # didn't need the password and can carry on regardless.)

            if states[state] == "awaiting_prompt":
                if self._flags["become_prompt"]:
                    display.debug("Sending become_password in response to prompt")
                    stdin.write(to_bytes(self._play_context.become_pass) + b"\n")
                    # On python3 stdin is a BufferedWriter, and we don't have a guarantee
                    # that the write will happen without a flush
                    stdin.flush()
                    self._flags["become_prompt"] = False
                    state += 1
                elif self._flags["become_success"]:
                    state += 1

            # We've requested escalation (with or without a password), now we
            # wait for an error message or a successful escalation.

            if states[state] == "awaiting_escalation":
                if self._flags["become_success"]:
                    display.vvv("Escalation succeeded")
                    self._flags["become_success"] = False
                    state += 1
                elif self._flags["become_error"]:
                    display.vvv("Escalation failed")
                    self._terminate_process(p)
                    self._flags["become_error"] = False
                    raise AnsibleError(
                        "Incorrect %s password" % self._play_context.become_method
                    )
                elif self._flags["become_nopasswd_error"]:
                    display.vvv("Escalation requires password")
                    self._terminate_process(p)
                    self._flags["become_nopasswd_error"] = False
                    raise AnsibleError(
                        "Missing %s password" % self._play_context.become_method
                    )
                elif self._flags["become_prompt"]:
                    # This shouldn't happen, because we should see the "Sorry,
                    # try again" message first.
                    display.vvv("Escalation prompt repeated")
                    self._terminate_process(p)
                    self._flags["become_prompt"] = False
                    raise AnsibleError(
                        "Incorrect %s password" % self._play_context.become_method
                    )

            # Once we're sure that the privilege escalation prompt, if any, has
            # been dealt with, we can send any initial data and start waiting
            # for output.

            if states[state] == "ready_to_send":
                if in_data:
                    self._send_initial_data(stdin, in_data, p)
                state += 1

            # Now we're awaiting_exit: has the child process exited? If it has,
            # and we've read all available output from it, we're done.

            if poll is not None:
                if not selector.get_map() or not events:
                    break
                # We should not see further writes to the stdout/stderr file
                # descriptors after the process has closed, set the select
                # timeout to gather any last writes we may have missed.
                timeout = 0
                continue

            # If the process has not yet exited, but we've already read EOF from
            # its stdout and stderr (and thus no longer watching any file
            # descriptors), we can just wait for it to exit.

            elif not selector.get_map():
                p.wait()
                break

            # Otherwise there may still be outstanding data to read.
    finally:
        selector.close()
        # close stdin after process is terminated and stdout/stderr are read
        # completely (see also issue #848)
        stdin.close()

    if C.HOST_KEY_CHECKING:
        if cmd[0] == b"sshpass" and p.returncode == 6:
            raise AnsibleError(
                "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support "
                "this.  Please add this host's fingerprint to your known_hosts file to manage this host."
            )

    controlpersisterror = (
        b"Bad configuration option: ControlPersist" in b_stderr
        or b"unknown configuration option: ControlPersist" in b_stderr
    )
    if p.returncode != 0 and controlpersisterror:
        raise AnsibleError(
            'using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" '
            "(or ssh_args in [ssh_connection] section of the config file) before running again"
        )

    # If we find a broken pipe because of ControlPersist timeout expiring (see #16731),
    # we raise a special exception so that we can retry a connection.
    controlpersist_broken_pipe = (
        b"mux_client_hello_exchange: write packet: Broken pipe" in b_stderr
    )
    if p.returncode == 255:
        additional = to_native(b_stderr)
        if controlpersist_broken_pipe:
            raise AnsibleControlPersistBrokenPipeError(
                "Data could not be sent because of ControlPersist broken pipe: %s"
                % additional
            )

        elif in_data and checkrc:
            raise AnsibleConnectionFailure(
                'Data could not be sent to remote host "%s". Make sure this host can be reached over ssh: %s'
                % (self.host, additional)
            )

    return (p.returncode, b_stdout, b_stderr)