# Buggy code
def _examine_output(self, source, state, b_chunk, sudoable):
    """
    Takes a string, extracts complete lines from it, tests to see if they
    are a prompt, error message, etc., and sets appropriate flags in self.
    Prompt and success lines are removed.

    Returns the processed (i.e. possibly-edited) output and the unprocessed
    remainder (to be processed with the next chunk) as strings.
    """

    output = []
    for b_line in b_chunk.splitlines(True):
        display_line = to_text(b_line).rstrip("\r\n")
        suppress_output = False

        # display.debug("Examining line (source=%s, state=%s): '%s'" % (source, state, display_line))
        if self.become.expect_prompt() and self.become.check_password_prompt(b_line):
            display.debug(
                "become_prompt: (source=%s, state=%s): '%s'"
                % (source, state, display_line)
            )
            self._flags["become_prompt"] = True
            suppress_output = True
        elif self.become.success and self.become.check_success(b_line):
            display.debug(
                "become_success: (source=%s, state=%s): '%s'"
                % (source, state, display_line)
            )
            self._flags["become_success"] = True
            suppress_output = True
        elif sudoable and self.become.check_incorrect_password(b_line):
            display.debug(
                "become_error: (source=%s, state=%s): '%s'"
                % (source, state, display_line)
            )
            self._flags["become_error"] = True
        elif sudoable and self.become.check_missing_password(b_line):
            display.debug(
                "become_nopasswd_error: (source=%s, state=%s): '%s'"
                % (source, state, display_line)
            )
            self._flags["become_nopasswd_error"] = True

        if not suppress_output:
            output.append(b_line)

    # The chunk we read was most likely a series of complete lines, but just
    # in case the last line was incomplete (and not a prompt, which we would
    # have removed from the output), we retain it to be processed with the
    # next chunk.

    remainder = b""
    if output and not output[-1].endswith(b"\n"):
        remainder = output[-1]
        output = output[:-1]

    return b"".join(output), remainder


# 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 _examine_output(self, source, state, b_chunk, sudoable):
    """
    Takes a string, extracts complete lines from it, tests to see if they
    are a prompt, error message, etc., and sets appropriate flags in self.
    Prompt and success lines are removed.

    Returns the processed (i.e. possibly-edited) output and the unprocessed
    remainder (to be processed with the next chunk) as strings.
    """

    output = []
    for b_line in b_chunk.splitlines(True):
        display_line = to_text(b_line).rstrip("\r\n")
        suppress_output = False

        # display.debug("Examining line (source=%s, state=%s): '%s'" % (source, state, display_line))
        if self.become.expect_prompt() and self.become.check_password_prompt(b_line):
            display.debug(
                "become_prompt: (source=%s, state=%s): '%s'"
                % (source, state, display_line)
            )
            self._flags["become_prompt"] = True
            suppress_output = True
        elif self.become.success and self.become.check_success(b_line):
            display.debug(
                "become_success: (source=%s, state=%s): '%s'"
                % (source, state, display_line)
            )
            self._flags["become_success"] = True
            suppress_output = True
        elif sudoable and self.become.check_incorrect_password(b_line):
            display.debug(
                "become_error: (source=%s, state=%s): '%s'"
                % (source, state, display_line)
            )
            self._flags["become_error"] = True
        elif sudoable and self.become.check_missing_password(b_line):
            display.debug(
                "become_nopasswd_error: (source=%s, state=%s): '%s'"
                % (source, state, display_line)
            )
            self._flags["become_nopasswd_error"] = True

        if not suppress_output:
            output.append(b_line)

    # The chunk we read was most likely a series of complete lines, but just
    # in case the last line was incomplete (and not a prompt, which we would
    # have removed from the output), we retain it to be processed with the
    # next chunk.

    remainder = b""
    if output and not output[-1].endswith(b"\n"):
        remainder = output[-1]
        output = output[:-1]

    return b"".join(output), remainder