diff --git a/Lib/gettext.py b/Lib/gettext.py --- a/Lib/gettext.py +++ b/Lib/gettext.py @@ -81,15 +81,19 @@ def c2py(plural): expr.sub(repl, x.group(3))) stack = [''] + maybe_func = False for mo in re.finditer(_TOKEN_PATTERN, plural): kind = mo.lastgroup value = mo.group(kind) if kind == 'NUMBER' or kind == 'IDENTIFIER': stack[-1] += value + maybe_func = True elif kind == 'WHITESPACE': continue elif kind == 'PARENTHESIS': if value == '(': + if maybe_func: + raise ValueError('function call in plural form') stack.append('') else: if len(stack) == 1: @@ -105,6 +109,7 @@ def c2py(plural): stack[-1] += ' not ' else: stack[-1] += value + maybe_func = False else: raise ValueError('invalid token in plural form: {}'.format(value)) diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -365,6 +365,10 @@ class PluralFormsTestCase(GettextBaseTest): # Test for a dangerous expression raises(ValueError, gettext.c2py, "os.chmod('/etc/passwd',0777)") + def test_security_function_call(self): + raises = self.assertRaises + raises(ValueError, gettext.c2py, "n()") + class GNUTranslationParsingTest(GettextBaseTest): def test_plural_form_error_issue17898(self): with open(MOFILE, 'wb') as fp: