[FIX] base: avoid variable name collision with functions in QWeb
Bug === The arguments of the lambda function might be the same as other variables in the QWeb. In that case the template rendering will crash. To avoid this issue, we encapsulate the name of the argument to be sure it's not the same as other variable in the QWeb engine (so the name of the argument can no longer make the QWeb rendering crash) Task-2674716 Closes #78392. Forward-port of 96b09b127028e5c9a83c89acce86e1b6df904c6f
This commit is contained in:
@@ -295,7 +295,6 @@ class QWeb(object):
|
||||
globals_dict['Mapping'] = Mapping
|
||||
globals_dict['Markup'] = Markup
|
||||
globals_dict['escape'] = escape
|
||||
globals_dict['type'] = type
|
||||
globals_dict['compile_options'] = options
|
||||
globals_dict.update(self._available_objects)
|
||||
return globals_dict
|
||||
@@ -410,7 +409,7 @@ class QWeb(object):
|
||||
code += f'.format({", ".join(values)})'
|
||||
return code
|
||||
|
||||
def _compile_expr_tokens(self, tokens, allowed_keys, raise_on_missing=False):
|
||||
def _compile_expr_tokens(self, tokens, allowed_keys, argument_names=None, raise_on_missing=False):
|
||||
""" Transform the list of token coming into a python instruction in
|
||||
textual form by adding the namepaces for the dynamic values.
|
||||
|
||||
@@ -436,6 +435,10 @@ class QWeb(object):
|
||||
index = 0
|
||||
open_bracket_index = -1
|
||||
bracket_depth = 0
|
||||
|
||||
argument_name = '_arg_%s__'
|
||||
argument_names = argument_names or []
|
||||
|
||||
while index < len(tokens):
|
||||
t = tokens[index]
|
||||
if t.exact_type in [token.LPAR, token.LSQB, token.LBRACE]:
|
||||
@@ -449,7 +452,7 @@ class QWeb(object):
|
||||
while i < len(tokens):
|
||||
t = tokens[i]
|
||||
if t.exact_type == token.NAME:
|
||||
allowed_keys.append(t.string)
|
||||
argument_names.append(t.string)
|
||||
elif t.exact_type == token.COMMA:
|
||||
pass
|
||||
elif t.exact_type == token.COLON:
|
||||
@@ -466,7 +469,7 @@ class QWeb(object):
|
||||
if t.exact_type == token.NAME:
|
||||
if t.string == 'in':
|
||||
break
|
||||
allowed_keys.append(t.string)
|
||||
argument_names.append(t.string)
|
||||
elif t.exact_type in [token.COMMA, token.LPAR, token.RPAR]:
|
||||
pass
|
||||
else:
|
||||
@@ -495,7 +498,12 @@ class QWeb(object):
|
||||
elif t.exact_type in [token.RPAR, token.RSQB, token.RBRACE]:
|
||||
bracket_depth -= 1
|
||||
if bracket_depth == 0:
|
||||
code = self._compile_expr_tokens(tokens[open_bracket_index + 1:index], list(allowed_keys), raise_on_missing)
|
||||
code = self._compile_expr_tokens(
|
||||
tokens[open_bracket_index + 1:index],
|
||||
list(allowed_keys),
|
||||
list(argument_names),
|
||||
raise_on_missing,
|
||||
)
|
||||
code = tokens[open_bracket_index].string + code + t.string
|
||||
tokens[open_bracket_index:index + 1] = [tokenize.TokenInfo(token.QWEB, code, tokens[open_bracket_index].start, t.end, '')]
|
||||
index = open_bracket_index
|
||||
@@ -526,7 +534,9 @@ class QWeb(object):
|
||||
index += 1
|
||||
while index < len(tokens):
|
||||
t = tokens[index]
|
||||
if t.exact_type in [token.COMMA, token.NAME, token.COLON]:
|
||||
if t.exact_type == token.NAME and t.string in argument_names:
|
||||
code.append(argument_name % t.string)
|
||||
if t.exact_type in [token.COMMA, token.COLON]:
|
||||
code.append(t.string)
|
||||
if t.exact_type == token.COLON:
|
||||
break
|
||||
@@ -535,6 +545,8 @@ class QWeb(object):
|
||||
pos = (t.end[0], 0)
|
||||
else:
|
||||
pos = t.end
|
||||
elif string in argument_names:
|
||||
code.append(argument_name % t.string)
|
||||
elif string in allowed_keys:
|
||||
code.append(string)
|
||||
elif index + 1 < len(tokens) and tokens[index + 1].exact_type == token.EQUAL: # function kw
|
||||
@@ -1048,7 +1060,7 @@ class QWeb(object):
|
||||
{t_foreach} = {self._compile_expr(expr_foreach)} or []
|
||||
if isinstance({t_foreach}, Sized):
|
||||
values[{repr(expr_as + '_size')}] = {size} = len({t_foreach})
|
||||
elif type({t_foreach}) == int:
|
||||
elif ({t_foreach}).__class__ == int:
|
||||
values[{repr(expr_as + '_size')}] = {size} = {t_foreach}
|
||||
{t_foreach} = range({size})
|
||||
else:
|
||||
|
||||
@@ -684,6 +684,7 @@ class TestQWebBasic(TransactionCase):
|
||||
("fn(a=11, b=22) or a", {'a': 1, 'fn': lambda a,b: b}, 22),
|
||||
("(lambda a: a)(5)", {}, 5),
|
||||
("(lambda a: a[0])([5])", {}, 5),
|
||||
("(lambda test: len(test))('aaa')", {}, 3),
|
||||
("{'a': lambda a: a[0], 'b': 3}['a']([5])", {}, 5),
|
||||
("list(map(lambda a: a[0], r))", {'r': [(1,11), (2,22)]}, [1, 2]),
|
||||
("z + (head or 'z')", {'z': 'a'}, "az"),
|
||||
@@ -693,8 +694,10 @@ class TestQWebBasic(TransactionCase):
|
||||
("any({x == 5 for x in [1,2,3]})", {}, False),
|
||||
("{x:y for x,y in [('a', 11),('b', 22)]}", {}, {'a': 11, 'b': 22}),
|
||||
("[(y,x) for x,y in [(1, 11),(2, 22)]]", {}, [(11, 1), (22, 2)]),
|
||||
("(lambda a: a + 5)(a=x)", {'x': 10}, 15),
|
||||
("(lambda a: a + 5)(x)", {'x': 10}, 15),
|
||||
("(lambda a: a + x)(5)", {'x': 10}, 15),
|
||||
("sum(x for x in range(4)) + ((x))", {'x': 10}, 16),
|
||||
("['test_' + x for x in ['a', 'b']]", {}, ['test_a', 'test_b'])
|
||||
]
|
||||
|
||||
IrQweb = self.env['ir.qweb']
|
||||
|
||||
@@ -37,7 +37,7 @@ __all__ = ['test_expr', 'safe_eval', 'const_eval']
|
||||
# lp:703841), does import time.
|
||||
_ALLOWED_MODULES = ['_strptime', 'math', 'time']
|
||||
|
||||
_UNSAFE_ATTRIBUTES = ['f_builtins', 'f_globals', 'f_locals', 'gi_frame',
|
||||
_UNSAFE_ATTRIBUTES = ['f_builtins', 'f_globals', 'f_locals', 'gi_frame', 'gi_code',
|
||||
'co_code', 'func_globals']
|
||||
|
||||
def to_opcodes(opnames, _opmap=opmap):
|
||||
|
||||
Reference in New Issue
Block a user