From c659be692896f9f36fa46c4955220dc57653f09b Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Sat, 31 Oct 2020 14:17:24 -0400 Subject: [PATCH] Interpreter: Fix nested subsubproject detection A sub-subproject can be configured directly from `subprojects/foo/subprojects/bar/` in the case `bar` is in the same git repository as `foo` and not downloaded separately into the main project's `subprojects/`. In that case the nested subproject violation code was wrong because it is allowed to have more than one "subprojects" in path (was not possible before Meson 0.56.0). Example: - self.environment.source_dir = '/home/user/myproject' - self.root_subdir = 'subprojects/foo/subprojects/bar' - project_root = '/home/user/myproject/subprojects/foo/subprojects/bar' - norm = '/home/user/myproject/subprojects/foo/subprojects/bar/file.c' We want `norm` path to have `project_root` in its parents and not have `project_root / 'subprojects'` in its parents. In that case we are sure `file.c` is within `bar` subproject. --- mesonbuild/interpreter.py | 48 +++++-------------- .../sub_implicit/subprojects/subsub/foo.h | 1 + .../subprojects/subsub/meson.build | 4 ++ .../common/99 subproject subdir/test.json | 5 ++ .../failing/62 subproj filegrab/test.json | 2 +- test cases/failing/63 grab subproj/test.json | 2 +- test cases/failing/64 grab sibling/test.json | 2 +- 7 files changed, 26 insertions(+), 38 deletions(-) create mode 100644 test cases/common/99 subproject subdir/subprojects/sub_implicit/subprojects/subsub/foo.h create mode 100644 test cases/common/99 subproject subdir/test.json diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 6e0423579..9466fe453 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -4786,21 +4786,6 @@ This will probably not work. Try setting b_lundef to false instead.'''.format(self.coredata.options[OptionKey('b_sanitize')].value), location=self.current_node) - def evaluate_subproject_info(self, path_from_source_root, subproject_dir): - depth = 0 - subproj_name = '' - segs = PurePath(path_from_source_root).parts - segs_spd = PurePath(subproject_dir).parts - while segs and segs[0] == segs_spd[0]: - if len(segs_spd) == 1: - subproj_name = segs[1] - segs = segs[2:] - depth += 1 - else: - segs_spd = segs_spd[1:] - segs = segs[1:] - return (depth, subproj_name) - # Check that the indicated file is within the same subproject # as we currently are. This is to stop people doing # nasty things like: @@ -4812,26 +4797,19 @@ Try setting b_lundef to false instead.'''.format(self.coredata.options[OptionKey # subproject than it is defined in (due to e.g. a # declare_dependency). def validate_within_subproject(self, subdir, fname): - norm = os.path.normpath(os.path.join(subdir, fname)) - if os.path.isabs(norm): - if not norm.startswith(self.environment.source_dir): - # Grabbing files outside the source tree is ok. - # This is for vendor stuff like: - # - # /opt/vendorsdk/src/file_with_license_restrictions.c - return - norm = os.path.relpath(norm, self.environment.source_dir) - assert(not os.path.isabs(norm)) - (num_sps, sproj_name) = self.evaluate_subproject_info(norm, self.subproject_dir) - plain_filename = os.path.basename(norm) - if num_sps == 0: - if not self.is_subproject(): - return - raise InterpreterException('Sandbox violation: Tried to grab file %s from a different subproject.' % plain_filename) - if num_sps > 1: - raise InterpreterException('Sandbox violation: Tried to grab file %s from a nested subproject.' % plain_filename) - if sproj_name != self.subproject_directory_name: - raise InterpreterException('Sandbox violation: Tried to grab file %s from a different subproject.' % plain_filename) + srcdir = Path(self.environment.source_dir) + norm = Path(srcdir, subdir, fname).resolve() + if srcdir not in norm.parents: + # Grabbing files outside the source tree is ok. + # This is for vendor stuff like: + # + # /opt/vendorsdk/src/file_with_license_restrictions.c + return + project_root = Path(srcdir, self.root_subdir) + if project_root not in norm.parents: + raise InterpreterException('Sandbox violation: Tried to grab file {} outside current (sub)project.'.format(norm.name)) + if project_root / self.subproject_dir in norm.parents: + raise InterpreterException('Sandbox violation: Tried to grab file {} from a nested subproject.'.format(norm.name)) def source_strings_to_files(self, sources: T.List[str]) -> T.List[mesonlib.File]: mesonlib.check_direntry_issues(sources) diff --git a/test cases/common/99 subproject subdir/subprojects/sub_implicit/subprojects/subsub/foo.h b/test cases/common/99 subproject subdir/subprojects/sub_implicit/subprojects/subsub/foo.h new file mode 100644 index 000000000..a8ad3daba --- /dev/null +++ b/test cases/common/99 subproject subdir/subprojects/sub_implicit/subprojects/subsub/foo.h @@ -0,0 +1 @@ +#define DUMMY 42 diff --git a/test cases/common/99 subproject subdir/subprojects/sub_implicit/subprojects/subsub/meson.build b/test cases/common/99 subproject subdir/subprojects/sub_implicit/subprojects/subsub/meson.build index 18e2ceace..fdbb03fe6 100644 --- a/test cases/common/99 subproject subdir/subprojects/sub_implicit/subprojects/subsub/meson.build +++ b/test cases/common/99 subproject subdir/subprojects/sub_implicit/subprojects/subsub/meson.build @@ -1,3 +1,7 @@ project('subsub') meson.override_dependency('subsub', declare_dependency()) + +# Regression test: Installing a header from nested sub-subproject used to raise: +# ERROR: Sandbox violation: Tried to grab file foo.h from a nested subproject. +install_headers('foo.h') diff --git a/test cases/common/99 subproject subdir/test.json b/test cases/common/99 subproject subdir/test.json new file mode 100644 index 000000000..1921fe559 --- /dev/null +++ b/test cases/common/99 subproject subdir/test.json @@ -0,0 +1,5 @@ +{ + "installed": [ + { "type": "file", "file": "usr/include/foo.h" } + ] +} diff --git a/test cases/failing/62 subproj filegrab/test.json b/test cases/failing/62 subproj filegrab/test.json index dd0d7bbf3..282cb730b 100644 --- a/test cases/failing/62 subproj filegrab/test.json +++ b/test cases/failing/62 subproj filegrab/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/62 subproj filegrab/subprojects/a/meson.build:3:0: ERROR: Sandbox violation: Tried to grab file prog.c from a different subproject." + "line": "test cases/failing/62 subproj filegrab/subprojects/a/meson.build:3:0: ERROR: Sandbox violation: Tried to grab file prog.c outside current (sub)project." } ] } diff --git a/test cases/failing/63 grab subproj/test.json b/test cases/failing/63 grab subproj/test.json index 81479051a..37ebb3501 100644 --- a/test cases/failing/63 grab subproj/test.json +++ b/test cases/failing/63 grab subproj/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/63 grab subproj/meson.build:7:0: ERROR: Sandbox violation: Tried to grab file sub.c from a different subproject." + "line": "test cases/failing/63 grab subproj/meson.build:7:0: ERROR: Sandbox violation: Tried to grab file sub.c from a nested subproject." } ] } diff --git a/test cases/failing/64 grab sibling/test.json b/test cases/failing/64 grab sibling/test.json index 1604d47bf..bd609ec19 100644 --- a/test cases/failing/64 grab sibling/test.json +++ b/test cases/failing/64 grab sibling/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/64 grab sibling/subprojects/a/meson.build:3:0: ERROR: Sandbox violation: Tried to grab file sneaky.c from a different subproject." + "line": "test cases/failing/64 grab sibling/subprojects/a/meson.build:3:0: ERROR: Sandbox violation: Tried to grab file sneaky.c outside current (sub)project." } ] }