Index: trunk/extensions/InlineScripts/interpreter/Interpreter.php |
— | — | @@ -16,6 +16,10 @@ |
17 | 17 | public function __construct() { |
18 | 18 | global $wgInlineScriptsParserClass; |
19 | 19 | $this->mCodeParser = new $wgInlineScriptsParserClass( $this ); |
| 20 | + $this->mMaxRecursion = |
| 21 | + $this->mEvaluations = |
| 22 | + $this->mTokens = |
| 23 | + 0; |
20 | 24 | } |
21 | 25 | |
22 | 26 | public function checkRecursionLimit( $rec ) { |
— | — | @@ -28,7 +32,8 @@ |
29 | 33 | public function increaseEvaluationsCount() { |
30 | 34 | global $wgInlineScriptsLimits; |
31 | 35 | $this->mEvaluations++; |
32 | | - return $this->mEvaluations <= $wgInlineScriptsLimits['evaluations']; |
| 36 | + if( $this->mEvaluations > $wgInlineScriptsLimits['evaluations'] ) |
| 37 | + throw new ISUserVisibleException( 'toomanyevals', 0 ); |
33 | 38 | } |
34 | 39 | |
35 | 40 | public function getMaxTokensLeft() { |
— | — | @@ -93,7 +98,7 @@ |
94 | 99 | * in a sepereate context with its own output, variables and parser frame. |
95 | 100 | */ |
96 | 101 | class InlineScriptEvaluationContext { |
97 | | - var $mVars, $mOut, $mParser, $mFrame, $mInterpteter; |
| 102 | + var $mVars, $mOut, $mParser, $mFrame, $mInterpreter; |
98 | 103 | |
99 | 104 | static $mFunctions = array( |
100 | 105 | 'out' => 'funcOut', |
— | — | @@ -131,7 +136,7 @@ |
132 | 137 | public function __construct( $interpreter, $parser, $frame ) { |
133 | 138 | $this->mVars = array(); |
134 | 139 | $this->mOut = ''; |
135 | | - $this->mInterpteter = $interpreter; |
| 140 | + $this->mInterpreter = $interpreter; |
136 | 141 | $this->mParser = $parser; |
137 | 142 | $this->mFrame = $frame; |
138 | 143 | } |
— | — | @@ -141,6 +146,10 @@ |
142 | 147 | throw new ISException( 'evaluateNode() accepts only nonterminals' ); |
143 | 148 | } |
144 | 149 | |
| 150 | + if( !$this->mInterpreter->checkRecursionLimit( $rec ) ) { |
| 151 | + throw new ISUserVisibleException( 'recoverflow', 0 ); |
| 152 | + } |
| 153 | + |
145 | 154 | $c = $node->getChildren(); |
146 | 155 | switch( $node->getType() ) { |
147 | 156 | case 'stmts': |
— | — | @@ -172,7 +181,7 @@ |
173 | 182 | case 'foreach': |
174 | 183 | $array = $this->evaluateNode( $c[4], $rec + 1 ); |
175 | 184 | if( $array->type != ISData::DList ) |
176 | | - throw new ISException( 'invalidforeach', $c[0]->type ); |
| 185 | + throw new ISUserVisibleException( 'invalidforeach', $c[0]->type ); |
177 | 186 | $last = new ISData(); |
178 | 187 | foreach( $array->data as $item ) { |
179 | 188 | $this->setVar( $c[2], $item, $rec ); |
— | — | @@ -206,6 +215,7 @@ |
207 | 216 | return $this->evaluateNode( $c[0], $rec + 1 ); |
208 | 217 | } |
209 | 218 | case 'exprset': |
| 219 | + $this->mInterpreter->increaseEvaluationsCount(); |
210 | 220 | if( $c[1]->value == '=' ) { |
211 | 221 | $new = $this->evaluateNode( $c[2], $rec + 1 ); |
212 | 222 | $this->setVar( $c[0], $new, $rec ); |
— | — | @@ -226,6 +236,7 @@ |
227 | 237 | return $this->evaluateNode( $c[4], $rec + 1 ); |
228 | 238 | } |
229 | 239 | case 'exprlogical': |
| 240 | + $this->mInterpreter->increaseEvaluationsCount(); |
230 | 241 | $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); |
231 | 242 | switch( $c[1]->value ) { |
232 | 243 | case '&': |
— | — | @@ -246,10 +257,12 @@ |
247 | 258 | } |
248 | 259 | case 'exprequals': |
249 | 260 | case 'exprcompare': |
| 261 | + $this->mInterpreter->increaseEvaluationsCount(); |
250 | 262 | $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); |
251 | 263 | $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); |
252 | 264 | return ISData::compareOp( $arg1, $arg2, $c[1]->value ); |
253 | 265 | case 'exprsum': |
| 266 | + $this->mInterpreter->increaseEvaluationsCount(); |
254 | 267 | $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); |
255 | 268 | $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); |
256 | 269 | switch( $c[1]->value ) { |
— | — | @@ -259,14 +272,17 @@ |
260 | 273 | return ISData::sub( $arg1, $arg2 ); |
261 | 274 | } |
262 | 275 | case 'exprmul': |
| 276 | + $this->mInterpreter->increaseEvaluationsCount(); |
263 | 277 | $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); |
264 | 278 | $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); |
265 | 279 | return ISData::mulRel( $arg1, $arg2, $c[1]->value, $c[1]->line ); |
266 | 280 | case 'exprpow': |
| 281 | + $this->mInterpreter->increaseEvaluationsCount(); |
267 | 282 | $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); |
268 | 283 | $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); |
269 | 284 | return ISData::pow( $arg1, $arg2 ); |
270 | 285 | case 'exprkeyword': |
| 286 | + $this->mInterpreter->increaseEvaluationsCount(); |
271 | 287 | $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); |
272 | 288 | $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); |
273 | 289 | switch( $c[1]->value ) { |
— | — | @@ -278,15 +294,18 @@ |
279 | 295 | throw new ISException( "Invalid keyword: {$c[1]->value}" ); |
280 | 296 | } |
281 | 297 | case 'exprinvert': |
| 298 | + $this->mInterpreter->increaseEvaluationsCount(); |
282 | 299 | $arg = $this->evaluateNode( $c[1], $rec + 1 ); |
283 | 300 | return ISData::boolInvert( $arg ); |
284 | 301 | case 'exprunary': |
| 302 | + $this->mInterpreter->increaseEvaluationsCount(); |
285 | 303 | $arg = $this->evaluateNode( $c[1], $rec + 1 ); |
286 | 304 | if( $c[0]->value == '-' ) |
287 | 305 | return ISData::unaryMinus( $arg ); |
288 | 306 | else |
289 | 307 | return $arg; |
290 | 308 | case 'exprfunction': |
| 309 | + $this->mInterpreter->increaseEvaluationsCount(); |
291 | 310 | if( $c[0] instanceof ISToken ) { |
292 | 311 | $funcname = $c[0]->value; |
293 | 312 | if( !isset( self::$mFunctions[$funcname] ) ) |
Index: trunk/extensions/InlineScripts/interpreter/Shared.php |
— | — | @@ -164,7 +164,7 @@ |
165 | 165 | |
166 | 166 | public function appendTokenCount( &$interpr ) { |
167 | 167 | global $wgInlineScriptsLimits; |
168 | | - $interpr->mTokens += $this->mTokensCount; |
| 168 | + $interpr->mTokens += $this->mTokens; |
169 | 169 | if( $interpr->mTokens > $wgInlineScriptsLimits['tokens'] ) |
170 | 170 | throw new ISUserVisibleException( 'toomanytokens', 0 ); |
171 | 171 | } |
Index: trunk/extensions/InlineScripts/interpreterTests.txt |
— | — | @@ -209,7 +209,26 @@ |
210 | 210 | </p> |
211 | 211 | !! end |
212 | 212 | |
| 213 | +!! article |
| 214 | +Template:123 |
| 215 | +!! text |
| 216 | +<wikiscript> |
| 217 | +out( 123 ); |
| 218 | +</wikiscript> |
| 219 | +!! endarticle |
| 220 | + |
213 | 221 | !! test |
| 222 | +Nested wikiscripts via parse() |
| 223 | +!! input |
| 224 | +<wikiscript> |
| 225 | +out( parse( '{{123}}' ) ); |
| 226 | +</wikiscript> |
| 227 | +!! result |
| 228 | +<p>123 |
| 229 | +</p> |
| 230 | +!! end |
| 231 | + |
| 232 | +!! test |
214 | 233 | String functions 1 |
215 | 234 | !! input |
216 | 235 | {{#inline: lc( 'FOO' ) == 'foo' & uc( 'foo' ) == 'FOO' & |
Index: trunk/extensions/InlineScripts/InlineScripts.i18n.php |
— | — | @@ -17,7 +17,7 @@ |
18 | 18 | 'inlinescripts-exception-unclosedstring' => 'Unclosed string at char $1', |
19 | 19 | 'inlinescripts-exception-unrecognisedtoken' => 'Unrecognized token at char $1', |
20 | 20 | 'inlinescripts-exception-toomanytokens' => 'Exceeded tokens limit', |
21 | | - 'inlinescripts-exception-toomanyevals' => 'Exceeded evaluations limit at line $1', |
| 21 | + 'inlinescripts-exception-toomanyevals' => 'Exceeded evaluations limit', |
22 | 22 | 'inlinescripts-exception-recoverflow' => 'Too deep abstract syntax tree', |
23 | 23 | 'inlinescripts-exception-notanarray' => 'Tried to get an element of a non-array at line $1', |
24 | 24 | 'inlinescripts-exception-outofbounds' => 'Got out of array bounds at line $1', |
Index: trunk/extensions/InlineScripts/InlineScripts.php |
— | — | @@ -46,7 +46,7 @@ |
47 | 47 | * Maximal amount of tokens (strings, keywords, numbers, operators, |
48 | 48 | * but not whitespace) to be parsed. |
49 | 49 | */ |
50 | | - 'tokens' => 25000, |
| 50 | + 'tokens' => 100000, |
51 | 51 | /** |
52 | 52 | * Maximal amount of operations (multiplications, comarsions, function |
53 | 53 | * calls) to be done. |
— | — | @@ -115,10 +115,11 @@ |
116 | 116 | |
117 | 117 | public static function reportLimits( &$parser, &$report ) { |
118 | 118 | global $wgInlineScriptsLimits; |
| 119 | + $i = self::getInterpreter(); |
119 | 120 | $report .= |
120 | | - "Inline scripts parser evaluations: {$parser->is_evalsCount}/{$wgInlineScriptsLimits['evaluations']}\n" . |
121 | | - "Inline scripts tokens: {$parser->is_tokensCount}/{$wgInlineScriptsLimits['tokens']}\n" . |
122 | | - "Inline scripts AST maximal depth: {$parser->is_maxDepth}/{$wgInlineScriptsLimits['depth']}\n"; |
| 121 | + "Inline scripts parser evaluations: {$i->mEvaluations}/{$wgInlineScriptsLimits['evaluations']}\n" . |
| 122 | + "Inline scripts tokens: {$i->mTokens}/{$wgInlineScriptsLimits['tokens']}\n" . |
| 123 | + "Inline scripts AST maximal depth: {$i->mMaxRecursion}/{$wgInlineScriptsLimits['depth']}\n"; |
123 | 124 | return true; |
124 | 125 | } |
125 | 126 | |