catch build files that cannot be opened in utf8 mode and emit useful error

Previously, if a junked meson.build or native.ini was used we got a
lengthy traceback ending in UnicodeDecodeError.

Fixes: #13154
Fixes: #13156
pull/13158/head
Eli Schwartz 7 months ago committed by Jussi Pakkanen
parent 4f3a3e2efe
commit e5f32b7414
  1. 4
      mesonbuild/ast/interpreter.py
  2. 20
      mesonbuild/coredata.py
  3. 4
      mesonbuild/interpreter/interpreter.py
  4. 11
      mesonbuild/interpreterbase/interpreterbase.py
  5. 6
      mesonbuild/optinterpreter.py

@ -189,9 +189,7 @@ class AstInterpreter(InterpreterBase):
if not os.path.isfile(absname): if not os.path.isfile(absname):
sys.stderr.write(f'Unable to find build file {buildfilename} --> Skipping\n') sys.stderr.write(f'Unable to find build file {buildfilename} --> Skipping\n')
return return
with open(absname, encoding='utf-8') as f: code = self.read_buildfile(absname, buildfilename)
code = f.read()
assert isinstance(code, str)
try: try:
codeblock = mparser.Parser(code, absname).parse() codeblock = mparser.Parser(code, absname).parse()
except mesonlib.MesonException as me: except mesonlib.MesonException as me:

@ -1102,14 +1102,18 @@ class MachineFileParser():
self.sections: T.Dict[str, T.Dict[str, T.Union[str, bool, int, T.List[str]]]] = {} self.sections: T.Dict[str, T.Dict[str, T.Union[str, bool, int, T.List[str]]]] = {}
for fname in filenames: for fname in filenames:
with open(fname, encoding='utf-8') as f: try:
content = f.read() with open(fname, encoding='utf-8') as f:
content = content.replace('@GLOBAL_SOURCE_ROOT@', sourcedir) content = f.read()
content = content.replace('@DIRNAME@', os.path.dirname(fname)) except UnicodeDecodeError as e:
try: raise EnvironmentException(f'Malformed machine file {fname!r} failed to parse as unicode: {e}')
self.parser.read_string(content, fname)
except configparser.Error as e: content = content.replace('@GLOBAL_SOURCE_ROOT@', sourcedir)
raise EnvironmentException(f'Malformed machine file: {e}') content = content.replace('@DIRNAME@', os.path.dirname(fname))
try:
self.parser.read_string(content, fname)
except configparser.Error as e:
raise EnvironmentException(f'Malformed machine file: {e}')
# Parse [constants] first so they can be used in other sections # Parse [constants] first so they can be used in other sections
if self.parser.has_section('constants'): if self.parser.has_section('constants'):

@ -2425,9 +2425,7 @@ class Interpreter(InterpreterBase, HoldableObject):
if not os.path.isfile(absname): if not os.path.isfile(absname):
self.subdir = prev_subdir self.subdir = prev_subdir
raise InterpreterException(f"Nonexistent build file '{buildfilename!s}'") raise InterpreterException(f"Nonexistent build file '{buildfilename!s}'")
with open(absname, encoding='utf-8') as f: code = self.read_buildfile(absname, buildfilename)
code = f.read()
assert isinstance(code, str)
try: try:
codeblock = mparser.Parser(code, absname).parse() codeblock = mparser.Parser(code, absname).parse()
except mesonlib.MesonException as me: except mesonlib.MesonException as me:

@ -93,12 +93,19 @@ class InterpreterBase:
# do nothing in an AST interpreter # do nothing in an AST interpreter
return return
def read_buildfile(self, fname: str, errname: str) -> str:
try:
with open(fname, encoding='utf-8') as f:
return f.read()
except UnicodeDecodeError as e:
node = mparser.BaseNode(1, 1, errname)
raise InvalidCode.from_node(f'Build file failed to parse as unicode: {e}', node=node)
def load_root_meson_file(self) -> None: def load_root_meson_file(self) -> None:
mesonfile = os.path.join(self.source_root, self.subdir, environment.build_filename) mesonfile = os.path.join(self.source_root, self.subdir, environment.build_filename)
if not os.path.isfile(mesonfile): if not os.path.isfile(mesonfile):
raise InvalidArguments(f'Missing Meson file in {mesonfile}') raise InvalidArguments(f'Missing Meson file in {mesonfile}')
with open(mesonfile, encoding='utf-8') as mf: code = self.read_buildfile(mesonfile, mesonfile)
code = mf.read()
if code.isspace(): if code.isspace():
raise InvalidCode('Builder file is empty.') raise InvalidCode('Builder file is empty.')
assert isinstance(code, str) assert isinstance(code, str)

@ -78,7 +78,11 @@ class OptionInterpreter:
def process(self, option_file: str) -> None: def process(self, option_file: str) -> None:
try: try:
with open(option_file, encoding='utf-8') as f: with open(option_file, encoding='utf-8') as f:
ast = mparser.Parser(f.read(), option_file).parse() code = f.read()
except UnicodeDecodeError as e:
raise mesonlib.MesonException(f'Malformed option file {option_file!r} failed to parse as unicode: {e}')
try:
ast = mparser.Parser(code, option_file).parse()
except mesonlib.MesonException as me: except mesonlib.MesonException as me:
me.file = option_file me.file = option_file
raise me raise me

Loading…
Cancel
Save