Explicitly forbid negative indexes in arrays

This emits its own error because:
1- It's clearer to understand
2- It's easier to find where we're dealing with negative offsets, if
we'll ever want to allow that.

Note that trying to use a negative index already results in a hard PHP
error being thrown.

Bug: T237219
Change-Id: Ib11eaaca5e21f740269141c75e62bac48093e8d0
This commit is contained in:
Daimona Eaytoy 2019-11-04 18:45:58 +01:00 committed by Krinkle
parent 6a1531b7d4
commit b7c7ae168d
6 changed files with 39 additions and 0 deletions

View file

@ -443,6 +443,7 @@
"abusefilter-exception-regexfailure": "Error in regular expression \"$2\" at character $1.",
"abusefilter-exception-overridebuiltin": "Illegal overriding of built-in variable \"$2\" at character $1.",
"abusefilter-exception-outofbounds": "Requesting non-existent array item $2 (array size = $3) at character $1.",
"abusefilter-exception-negativeindex": "Negative indexes are not allowed in arrays. Got index \"$2\" at character $1.",
"abusefilter-exception-notarray": "Requesting array item of non-array at character $1.",
"abusefilter-exception-unclosedcomment": "Unclosed comment at character $1.",
"abusefilter-exception-invalidiprange": "Invalid IP range \"$2\" provided at character $1.",

View file

@ -477,6 +477,7 @@
"abusefilter-exception-regexfailure": "Error message from the abuse filter parser. Parameters:\n* $1 - Position in the string\n* $2 - Regular expression",
"abusefilter-exception-overridebuiltin": "Error message from the abuse filter parser. Parameters:\n* $1 - Position in the string\n* $2 - Built-in variable",
"abusefilter-exception-outofbounds": "Error message from the abuse filter parser. Parameters:\n* $1 - Position in the string\n* $2 - Index\n* $3 - Number of items in array",
"abusefilter-exception-negativeindex": "Error message from the abuse filter parser. Parameters:\n* $1 - Position in the string\n* $2 - Index",
"abusefilter-exception-notarray": "Error message from the abuse filter parser. Parameters:\n* $1 - Position in the string",
"abusefilter-exception-unclosedcomment": "Error message from the abuse filter parser. Parameters:\n* $1 - Position in the string",
"abusefilter-exception-invalidiprange": "Error message from the abuse filter parser. Parameters:\n* $1 - Position in the string\n* $2 - String provided as an argument to a function",

View file

@ -54,6 +54,7 @@ class AFPUserVisibleException extends AFPException {
// abusefilter-exception-notarray, abusefilter-exception-unclosedcomment
// abusefilter-exception-invalidiprange, abusefilter-exception-disabledvar
// abusefilter-exception-variablevariable, abusefilter-exception-toomanyargs
// abusefilter-exception-negativeoffset
return wfMessage(
'abusefilter-exception-' . $this->mExceptionID,
$this->mPosition, ...$this->mParams

View file

@ -186,6 +186,8 @@ class AbuseFilterCachingParser extends AbuseFilterParser {
if ( count( $array ) <= $offset ) {
throw new AFPUserVisibleException( 'outofbounds', $node->position,
[ $offset, count( $array ) ] );
} elseif ( $offset < 0 ) {
throw new AFPUserVisibleException( 'negativeindex', $node->position, [ $offset ] );
}
return $array[$offset];
@ -314,6 +316,8 @@ class AbuseFilterCachingParser extends AbuseFilterParser {
if ( count( $array ) <= $offset ) {
throw new AFPUserVisibleException( 'outofbounds', $node->position,
[ $offset, count( $array ) ] );
} elseif ( $offset < 0 ) {
throw new AFPUserVisibleException( 'negativeindex', $node->position, [ $offset ] );
}
$array[$offset] = $value;

View file

@ -505,6 +505,8 @@ class AbuseFilterParser {
if ( count( $array->toArray() ) <= $idx ) {
throw new AFPUserVisibleException( 'outofbounds', $this->mCur->pos,
[ $idx, count( $array->getData() ) ] );
} elseif ( $idx < 0 ) {
throw new AFPUserVisibleException( 'negativeindex', $this->mCur->pos, [ $idx ] );
}
}
}
@ -905,6 +907,8 @@ class AbuseFilterParser {
if ( count( $result->getData() ) <= $idx ) {
throw new AFPUserVisibleException( 'outofbounds', $this->mCur->pos,
[ $idx, count( $result->getData() ) ] );
} elseif ( $idx < 0 ) {
throw new AFPUserVisibleException( 'negativeindex', $this->mCur->pos, [ $idx ] );
}
// @phan-suppress-next-line PhanTypeArraySuspiciousNullable Guaranteed to be array
$result = $result->getData()[$idx];

View file

@ -360,6 +360,34 @@ class AbuseFilterParserTest extends AbuseFilterParserTestCase {
];
}
/**
* Test the 'negativeindex' exception
*
* @param string $expr The expression to test
* @param string $caller The function where the exception is thrown
* @dataProvider negativeIndex
*/
public function testNegativeIndexException( $expr, $caller ) {
$this->exceptionTest( 'negativeindex', $expr, $caller );
$this->exceptionTestInSkippedBlock( 'negativeindex', $expr, $caller );
}
/**
* Data provider for testNegativeIndexException
* The second parameter is the function where the exception is raised.
* One expression for each throw.
*
* @return array
*/
public function negativeIndex() {
return [
[ '[0][-1]', '' ],
[ "x := ['foo']; x[-1]", '' ],
[ "x := ['foo']; x[-1] := 2; x[-1] == 2", '' ],
[ "x := ['foo']; x[-5] := 2;", '' ]
];
}
/**
* Test the 'unrecognisedkeyword' exception
*