Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
26 changes: 22 additions & 4 deletions python/tvm/contrib/mxcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import re
import os
import shlex
import subprocess
import warnings
from typing import Tuple
Expand All @@ -31,6 +32,26 @@
from . import utils


def _format_mxcc_error(cmd, compiler_output, code):
"""Format an mxcc failure with enough context for reproduction."""
command_text = shlex.join([str(part) for part in cmd])
if isinstance(compiler_output, bytes):
compiler_text = compiler_output.decode("utf-8", errors="replace")
else:
compiler_text = py_str(compiler_output)
return "\n".join(
[
"MACA compilation failed.",
"Command:",
command_text,
"Compiler output:",
compiler_text,
"Source:",
code,
]
)
Comment on lines +35 to +52

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

在编译失败时,如果编译器输出(compiler_output)包含非 UTF-8 字符(例如在某些本地化环境下,或者输出中包含二进制垃圾字符),调用 py_str(compiler_output) 会抛出 UnicodeDecodeError,从而掩盖了真正的编译错误。此外,如果 cmd 中包含 pathlib.Path 等非字符串对象,shlex.join 会抛出 TypeError

建议对 compiler_output 进行安全的解码(使用 errors="replace"),并将 cmd 中的所有元素转换为字符串,以提高错误处理的鲁棒性。

def _format_mxcc_error(cmd, compiler_output, code):
    """Format an mxcc failure with enough context for reproduction."""
    if isinstance(compiler_output, bytes):
        out_str = compiler_output.decode("utf-8", errors="replace")
    else:
        out_str = str(compiler_output)
    return "\n".join(
        [
            "MACA compilation failed.",
            "Command:",
            shlex.join(str(x) for x in cmd),
            "Compiler output:",
            out_str,
            "Source:",
            code,
        ]
    )



def compile_maca(
code, target_format="mcbin", arch=None, options=None, path_target=None
): # pylint: disable=unused-argument
Expand Down Expand Up @@ -108,10 +129,7 @@ def compile_maca(
(out, _) = proc.communicate()

if proc.returncode != 0:
msg = code
msg += "\nCompilation error:\n"
msg += py_str(out)
raise RuntimeError(msg)
raise RuntimeError(_format_mxcc_error(cmd, out, code))

with open(file_target, "rb") as f:
data = bytearray(f.read())
Expand Down
21 changes: 21 additions & 0 deletions tests/python/contrib/test_mxcc_error_message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from pathlib import Path

from tvm.contrib import mxcc


def test_error_message_includes_reproducible_command():
cmd = ["mxcc", "-device-obj", "-o", Path("/tmp/out.mcbin"), "/tmp/in.maca"]
source = 'extern "C" __global__ void broken() {}'
message = mxcc._format_mxcc_error(cmd, b"syntax error", source)

assert "MACA compilation failed." in message
assert "mxcc -device-obj -o /tmp/out.mcbin /tmp/in.maca" in message
assert "syntax error" in message
assert source in message


def test_error_message_replaces_non_utf8_output():
message = mxcc._format_mxcc_error(["mxcc"], b"\xff", "__kernel")

assert "Compiler output:" in message
assert "\ufffd" in message