A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/python/cpython/commit/a8760275bd59fb8d8be1f1bf05313fed31c08321 below:

Fixed possible DoS and arbitrary code execution when ha… · python/cpython@a876027 · GitHub

59 59 60 60

_default_localedir = os.path.join(sys.prefix, 'share', 'locale')

61 61 62 - 63 -

def test(condition, true, false):

64 -

"""

65 -

Implements the C expression:

66 - 67 -

condition ? true : false

68 - 69 -

Required to correctly interpret plural forms.

70 -

"""

71 -

if condition:

72 -

return true

62 +

# Expression parsing for plural form selection.

63 +

#

64 +

# The gettext library supports a small subset of C syntax. The only

65 +

# incompatible difference is that integer literals starting with zero are

66 +

# decimal.

67 +

#

68 +

# https://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms

69 +

# http://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-runtime/intl/plural.y

70 + 71 +

_token_pattern = re.compile(r"""

72 +

(?P<WHITESPACES>[ \t]+) | # spaces and horizontal tabs

73 +

(?P<NUMBER>[0-9]+\b) | # decimal integer

74 +

(?P<NAME>n\b) | # only n is allowed

75 +

(?P<PARENTHESIS>[()]) |

76 +

(?P<OPERATOR>[-*/%+?:]|[><!]=?|==|&&|\|\|) | # !, *, /, %, +, -, <, >,

77 +

# <=, >=, ==, !=, &&, ||,

78 +

# ? :

79 +

# unary and bitwise ops

80 +

# not allowed

81 +

(?P<INVALID>\w+|.) # invalid token

82 +

""", re.VERBOSE|re.DOTALL)

83 + 84 +

def _tokenize(plural):

85 +

for mo in re.finditer(_token_pattern, plural):

86 +

kind = mo.lastgroup

87 +

if kind == 'WHITESPACES':

88 +

continue

89 +

value = mo.group(kind)

90 +

if kind == 'INVALID':

91 +

raise ValueError('invalid token in plural form: %s' % value)

92 +

yield value

93 +

yield ''

94 + 95 +

def _error(value):

96 +

if value:

97 +

return ValueError('unexpected token in plural form: %s' % value)

73 98

else:

74 -

return false

75 - 99 +

return ValueError('unexpected end of plural form')

100 + 101 +

_binary_ops = (

102 +

('||',),

103 +

('&&',),

104 +

('==', '!='),

105 +

('<', '>', '<=', '>='),

106 +

('+', '-'),

107 +

('*', '/', '%'),

108 +

)

109 +

_binary_ops = {op: i for i, ops in enumerate(_binary_ops, 1) for op in ops}

110 +

_c2py_ops = {'||': 'or', '&&': 'and', '/': '//'}

111 + 112 +

def _parse(tokens, priority=-1):

113 +

result = ''

114 +

nexttok = next(tokens)

115 +

while nexttok == '!':

116 +

result += 'not '

117 +

nexttok = next(tokens)

118 + 119 +

if nexttok == '(':

120 +

sub, nexttok = _parse(tokens)

121 +

result = '%s(%s)' % (result, sub)

122 +

if nexttok != ')':

123 +

raise ValueError('unbalanced parenthesis in plural form')

124 +

elif nexttok == 'n':

125 +

result = '%s%s' % (result, nexttok)

126 +

else:

127 +

try:

128 +

value = int(nexttok, 10)

129 +

except ValueError:

130 +

raise _error(nexttok)

131 +

result = '%s%d' % (result, value)

132 +

nexttok = next(tokens)

133 + 134 +

j = 100

135 +

while nexttok in _binary_ops:

136 +

i = _binary_ops[nexttok]

137 +

if i < priority:

138 +

break

139 +

# Break chained comparisons

140 +

if i in (3, 4) and j in (3, 4): # '==', '!=', '<', '>', '<=', '>='

141 +

result = '(%s)' % result

142 +

# Replace some C operators by their Python equivalents

143 +

op = _c2py_ops.get(nexttok, nexttok)

144 +

right, nexttok = _parse(tokens, i + 1)

145 +

result = '%s %s %s' % (result, op, right)

146 +

j = i

147 +

if j == priority == 4: # '<', '>', '<=', '>='

148 +

result = '(%s)' % result

149 + 150 +

if nexttok == '?' and priority <= 0:

151 +

if_true, nexttok = _parse(tokens, 0)

152 +

if nexttok != ':':

153 +

raise _error(nexttok)

154 +

if_false, nexttok = _parse(tokens)

155 +

result = '%s if %s else %s' % (if_true, result, if_false)

156 +

if priority == 0:

157 +

result = '(%s)' % result

158 + 159 +

return result, nexttok

76 160 77 161

def c2py(plural):

78 162

"""Gets a C expression as used in PO files for plural forms and returns a

79 -

Python lambda function that implements an equivalent expression.

163 +

Python function that implements an equivalent expression.

80 164

"""

81 -

# Security check, allow only the "n" identifier

82 -

try:

83 -

from cStringIO import StringIO

84 -

except ImportError:

85 -

from StringIO import StringIO

86 -

import token, tokenize

87 -

tokens = tokenize.generate_tokens(StringIO(plural).readline)

88 -

try:

89 -

danger = [x for x in tokens if x[0] == token.NAME and x[1] != 'n']

90 -

except tokenize.TokenError:

91 -

raise ValueError, \

92 -

'plural forms expression error, maybe unbalanced parenthesis'

93 -

else:

94 -

if danger:

95 -

raise ValueError, 'plural forms expression could be dangerous'

96 - 97 -

# Replace some C operators by their Python equivalents

98 -

plural = plural.replace('&&', ' and ')

99 -

plural = plural.replace('||', ' or ')

100 - 101 -

expr = re.compile(r'\!([^=])')

102 -

plural = expr.sub(' not \\1', plural)

103 - 104 -

# Regular expression and replacement function used to transform

105 -

# "a?b:c" to "test(a,b,c)".

106 -

expr = re.compile(r'(.*?)\?(.*?):(.*)')

107 -

def repl(x):

108 -

return "test(%s, %s, %s)" % (x.group(1), x.group(2),

109 -

expr.sub(repl, x.group(3)))

110 - 111 -

# Code to transform the plural expression, taking care of parentheses

112 -

stack = ['']

113 -

for c in plural:

114 -

if c == '(':

115 -

stack.append('')

116 -

elif c == ')':

117 -

if len(stack) == 1:

118 -

# Actually, we never reach this code, because unbalanced

119 -

# parentheses get caught in the security check at the

120 -

# beginning.

121 -

raise ValueError, 'unbalanced parenthesis in plural form'

122 -

s = expr.sub(repl, stack.pop())

123 -

stack[-1] += '(%s)' % s

124 -

else:

125 -

stack[-1] += c

126 -

plural = expr.sub(repl, stack.pop())

127 - 128 -

return eval('lambda n: int(%s)' % plural)

129 165 166 +

if len(plural) > 1000:

167 +

raise ValueError('plural form expression is too long')

168 +

try:

169 +

result, nexttok = _parse(_tokenize(plural))

170 +

if nexttok:

171 +

raise _error(nexttok)

172 + 173 +

depth = 0

174 +

for c in result:

175 +

if c == '(':

176 +

depth += 1

177 +

if depth > 20:

178 +

# Python compiler limit is about 90.

179 +

# The most complex example has 2.

180 +

raise ValueError('plural form expression is too complex')

181 +

elif c == ')':

182 +

depth -= 1

183 + 184 +

ns = {}

185 +

exec('''if 1:

186 +

def func(n):

187 +

if not isinstance(n, int):

188 +

raise ValueError('Plural value must be an integer.')

189 +

return int(%s)

190 +

''' % result, ns)

191 +

return ns['func']

192 +

except RuntimeError:

193 +

# Recursion error can be raised in _parse() or exec().

194 +

raise ValueError('plural form expression is too complex')

130 195 131 196 132 197

def _expand_lang(locale):


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4