Bug 1258619 - Properly sandbox functions inside a template
The way functions are being sandboxed in moz.configure land is that
their global namespace is being replaced with a limited and identifiable
dict. And we avoid re-wrapping a function that already received this
treatment.
The problem is that template functions have their global namespace
replaced, and any function that is defined within the template inherits
that global namespace. So when it comes time to wrap those functions
defined in templates with e.g. depends, we detect that they're already
wrapped although they are not, because we look if their global namespace
is of the recognizable type we use when replacing it.
So instead of looking at the global namespace type, keep track of all
functions that are wrapped.
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -234,19 +234,19 @@ def command_line_helper():
# it is a one off and because the required functionality doesn't need
# to be exposed for other usecases.
return depends.__self__._helper
# All options defined above this point can't be injected in mozconfig_options
# below, so collect them.
@template
-@advanced
def early_options():
@depends('--help')
+ @advanced
def early_options(help):
return set(
option.env
for option in depends.__self__._options.itervalues()
if option.env
)
return early_options
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -129,16 +129,19 @@ class ConfigureSandbox(dict):
# - config set by each @depends function
self._db = {}
# Store options added with `imply_option`, and the reason they were
# added (which can either have been given to `imply_option`, or
# infered.
self._implied_options = {}
+ # Store all results from _prepare_function
+ self.__prepared_functions = set()
+
self._helper = CommandLineHelper(environ, argv)
self._config, self._stdout, self._stderr = config, stdout, stderr
self._help = None
self._help_option = self.option_impl('--help',
help='print this message')
self._seen.add(self._help_option)
@@ -423,25 +426,26 @@ class ConfigureSandbox(dict):
return func
def _prepare_function(self, func):
'''Alter the given function global namespace with the common ground
for @depends, @template and @advanced.
'''
if not inspect.isfunction(func):
raise TypeError("Unexpected type: '%s'" % type(func))
- if isinstance(func.func_globals, SandboxedGlobal):
+ if func in self.__prepared_functions:
return func, func.func_globals
glob = SandboxedGlobal(func.func_globals)
glob.update(
__builtins__=self.BUILTINS,
__file__=self._paths[-1],
os=self.OS,
)
func = wraps(func)(types.FunctionType(
func.func_code,
glob,
func.__name__,
func.func_defaults,
func.func_closure
))
+ self.__prepared_functions.add(func)
return func, glob