diff options
author | Xavier Claessens <xavier.claessens@collabora.com> | 2021-10-31 16:16:10 -0400 |
---|---|---|
committer | Eli Schwartz <eschwartz93@gmail.com> | 2022-06-16 17:06:25 -0400 |
commit | 2e3ac3eec00f32dabcfc470cd4c1090303d08e58 (patch) | |
tree | 1c7c1b51798a99a5566c99233b5a6d2b713292c8 | |
parent | 7229443738482db2183d048cf8b8b8e6bd11fa6d (diff) | |
download | meson-2e3ac3eec00f32dabcfc470cd4c1090303d08e58.zip meson-2e3ac3eec00f32dabcfc470cd4c1090303d08e58.tar.gz meson-2e3ac3eec00f32dabcfc470cd4c1090303d08e58.tar.bz2 |
minstall: Add more safety checks when unpickling installdata
When need to catch exceptions just like we do in coredata.load() to
print proper error message instead of backtrace when user mix meson
versions.
This happens frequently when user has a newer version of meson installed
in their HOME and then "sudo meson install" uses the system version of
meson.
-rw-r--r-- | mesonbuild/coredata.py | 19 | ||||
-rw-r--r-- | mesonbuild/mesonlib/universal.py | 22 | ||||
-rw-r--r-- | mesonbuild/minstall.py | 15 |
3 files changed, 30 insertions, 26 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 569fe39..a55d674 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -23,6 +23,7 @@ from .mesonlib import ( MesonException, EnvironmentException, MachineChoice, PerMachine, PerMachineDefaultable, default_libdir, default_libexecdir, default_prefix, split_args, OptionKey, OptionType, stringlistify, + pickle_load ) from .wrap import WrapMode import ast @@ -1047,23 +1048,11 @@ def major_versions_differ(v1: str, v2: str) -> bool: def load(build_dir: str) -> CoreData: filename = os.path.join(build_dir, 'meson-private', 'coredata.dat') - load_fail_msg = f'Coredata file {filename!r} is corrupted. Try with a fresh build tree.' - try: - with open(filename, 'rb') as f: - obj = pickle.load(f) - except (pickle.UnpicklingError, EOFError): - raise MesonException(load_fail_msg) - except (TypeError, ModuleNotFoundError, AttributeError): - raise MesonException( - f"Coredata file {filename!r} references functions or classes that don't " - "exist. This probably means that it was generated with an old " - "version of meson.") - if not isinstance(obj, CoreData): - raise MesonException(load_fail_msg) - if major_versions_differ(obj.version, version): - raise MesonVersionMismatchException(obj.version, version) + obj = pickle_load(filename, 'Coredata', CoreData) + assert isinstance(obj, CoreData), 'for mypy' return obj + def save(obj: CoreData, build_dir: str) -> str: filename = os.path.join(build_dir, 'meson-private', 'coredata.dat') prev_filename = filename + '.prev' diff --git a/mesonbuild/mesonlib/universal.py b/mesonbuild/mesonlib/universal.py index d708671..71f206a 100644 --- a/mesonbuild/mesonlib/universal.py +++ b/mesonbuild/mesonlib/universal.py @@ -31,6 +31,7 @@ import typing as T import uuid import textwrap import copy +import pickle from mesonbuild import mlog @@ -123,6 +124,7 @@ __all__ = [ 'listify', 'partition', 'path_is_in_root', + 'pickle_load', 'Popen_safe', 'quiet_git', 'quote_arg', @@ -2232,3 +2234,23 @@ class OptionKey: def is_base(self) -> bool: """Convenience method to check if this is a base option.""" return self.type is OptionType.BASE + +def pickle_load(filename: str, object_name: str, object_type: T.Type) -> T.Any: + load_fail_msg = f'{object_name} file {filename!r} is corrupted. Try with a fresh build tree.' + try: + with open(filename, 'rb') as f: + obj = pickle.load(f) + except (pickle.UnpicklingError, EOFError): + raise MesonException(load_fail_msg) + except (TypeError, ModuleNotFoundError, AttributeError): + raise MesonException( + f"{object_name} file {filename!r} references functions or classes that don't " + "exist. This probably means that it was generated with an old " + "version of meson.") + if not isinstance(obj, object_type): + raise MesonException(load_fail_msg) + from ..coredata import version as coredata_version + from ..coredata import major_versions_differ, MesonVersionMismatchException + if major_versions_differ(obj.version, coredata_version): + raise MesonVersionMismatchException(obj.version, coredata_version) + return obj diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index 0c69126..551f909 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -18,7 +18,6 @@ from pathlib import Path import argparse import errno import os -import pickle import shlex import shutil import subprocess @@ -28,9 +27,7 @@ import typing as T from . import build from . import environment from .backend.backends import InstallData -from .coredata import major_versions_differ, MesonVersionMismatchException -from .coredata import version as coredata_version -from .mesonlib import MesonException, Popen_safe, RealPathAction, is_windows, setup_vsenv +from .mesonlib import MesonException, Popen_safe, RealPathAction, is_windows, setup_vsenv, pickle_load from .scripts import depfixer, destdir_join from .scripts.meson_exe import run_exe try: @@ -133,13 +130,9 @@ class DirMaker: def load_install_data(fname: str) -> InstallData: - with open(fname, 'rb') as ifile: - obj = pickle.load(ifile) - if not isinstance(obj, InstallData) or not hasattr(obj, 'version'): - raise MesonVersionMismatchException('<unknown>', coredata_version) - if major_versions_differ(obj.version, coredata_version): - raise MesonVersionMismatchException(obj.version, coredata_version) - return obj + obj = pickle_load(fname, 'InstallData', InstallData) + assert isinstance(obj, InstallData), 'fo mypy' + return obj def is_executable(path: str, follow_symlinks: bool = False) -> bool: '''Checks whether any of the "x" bits are set in the source file mode.''' |