1
0
mirror of https://github.com/robertkrimen/otto synced 2025-10-12 20:27:30 +08:00

Fix subtle range bug in String.substring (uint => int64)

Was looking for negative in the following calculation:

uint(0) - uint(3) => uint(0)
This commit is contained in:
Robert Krimen 2013-02-20 16:18:29 -08:00
parent ec902a6452
commit bf322e56ee
4 changed files with 41 additions and 35 deletions

View File

@ -45,6 +45,8 @@ TEST := -v --run _underscore_
TEST := -v --run _parseFloat
TEST := -v --run _underscore_utility
TEST := -v --run Array_splice
TEST := -v --run String_substring
TEST := -v --run String_slice
TEST := .
test: test-i

View File

@ -162,11 +162,11 @@ func builtinArray_splice(call FunctionCall) Value {
length := uint(toUint32(thisObject.get("length")))
start := valueToRangeIndex(call.Argument(0), length, false)
deleteCount := valueToRangeIndex(call.Argument(1), length-start, true)
deleteCount := valueToRangeIndex(call.Argument(1), uint(int64(length)-start), true)
valueArray := make([]Value, deleteCount)
for index := uint(0); index < deleteCount; index++ {
indexString := arrayIndexToString(start + index)
for index := int64(0); index < deleteCount; index++ {
indexString := arrayIndexToString(uint(start + index))
if thisObject.hasProperty(indexString) {
valueArray[index] = thisObject.get(indexString)
}
@ -177,7 +177,7 @@ func builtinArray_splice(call FunctionCall) Value {
// length 8 - delete 4 @ start 1
itemList := []Value{}
itemCount := uint(len(call.ArgumentList))
itemCount := int64(len(call.ArgumentList))
if itemCount > 2 {
itemCount -= 2 // Less the first two arguments
itemList = call.ArgumentList[2:]
@ -186,14 +186,15 @@ func builtinArray_splice(call FunctionCall) Value {
}
if itemCount < deleteCount {
// The Object/Array is shrinking
stop := length - deleteCount // The new length of the Object/Array before
stop := int64(length) - deleteCount
// The new length of the Object/Array before
// appending the itemList remainder
// Stopping at the lower bound of the insertion:
// Move an item from the after the deleted portion
// to a position after the inserted portion
for index := start; index < stop; index++ {
from := arrayIndexToString(index + deleteCount) // Position just after deletion
to := arrayIndexToString(index + itemCount) // Position just after splice (insertion)
from := arrayIndexToString(uint(index + deleteCount)) // Position just after deletion
to := arrayIndexToString(uint(index + itemCount)) // Position just after splice (insertion)
if thisObject.hasProperty(from) {
thisObject.put(to, thisObject.get(from), true)
} else {
@ -203,8 +204,8 @@ func builtinArray_splice(call FunctionCall) Value {
// Delete off the end
// We don't bother to delete below <stop + itemCount> (if any) since those
// will be overwritten anyway
for index := length; index > (stop + itemCount); index-- {
thisObject.delete(arrayIndexToString(index-1), true)
for index := int64(length); index > (stop + itemCount); index-- {
thisObject.delete(arrayIndexToString(uint(index-1)), true)
}
} else if itemCount > deleteCount {
// The Object/Array is growing
@ -214,9 +215,9 @@ func builtinArray_splice(call FunctionCall) Value {
// Starting from the upper bound of the deletion:
// Move an item from the after the deleted portion
// to a position after the inserted portion
for index := length - deleteCount; index > start; index-- {
from := arrayIndexToString(index + deleteCount - 1)
to := arrayIndexToString(index + itemCount - 1)
for index := int64(length) - deleteCount; index > start; index-- {
from := arrayIndexToString(uint(index + deleteCount - 1))
to := arrayIndexToString(uint(index + itemCount - 1))
if thisObject.hasProperty(from) {
thisObject.put(to, thisObject.get(from), true)
} else {
@ -225,10 +226,10 @@ func builtinArray_splice(call FunctionCall) Value {
}
}
for index := uint(0); index < itemCount; index++ {
thisObject.put(arrayIndexToString(index+start), itemList[index], true)
for index := int64(0); index < itemCount; index++ {
thisObject.put(arrayIndexToString(uint(index+start)), itemList[index], true)
}
thisObject.put("length", toValue(length+itemCount-deleteCount), true)
thisObject.put("length", toValue(uint(int64(length)+itemCount-deleteCount)), true)
return toValue(call.runtime.newArray(valueArray))
}
@ -250,8 +251,8 @@ func builtinArray_slice(call FunctionCall) Value {
if _arrayStash, ok := thisObject.stash.(*_arrayStash); ok {
copy(sliceValueArray, _arrayStash.valueArray[start:start+sliceLength])
} else {
for index := uint(0); index < sliceLength; index++ {
from := arrayIndexToString(index + start)
for index := int64(0); index < sliceLength; index++ {
from := arrayIndexToString(uint(index + start))
if thisObject.hasProperty(from) {
sliceValueArray[index] = thisObject.get(from)
}

View File

@ -388,7 +388,7 @@ func builtinString_slice(call FunctionCall) Value {
length := uint(len(target))
start, end := rangeStartEnd(call.ArgumentList, length, false)
if start >= length || end-start <= 0 {
if end-start <= 0 {
return toValue("")
}
return toValue(target[start:end])

View File

@ -62,35 +62,38 @@ func valueOfArrayIndex(list []Value, index int) Value {
// A range index can be anything from 0 up to length. It is NOT safe to use as an index
// to an array, but is useful for slicing and in some ECMA algorithms.
func valueToRangeIndex(indexValue Value, length uint, negativeIsZero bool) uint {
index := toIntegerFloat(indexValue)
if negativeIsZero {
index := uint(math.Max(index, 0))
// minimum(index, length)
if index >= length {
return length
func valueToRangeIndex(indexValue Value, length uint, negativeIsZero bool) int64 {
{
index := toIntegerFloat(indexValue)
length := float64(length)
if negativeIsZero {
index := math.Max(index, 0)
// minimum(index, length)
if index >= length {
index = length
}
return int64(uint(index))
}
return index
}
if index < 0 {
index = math.Max(index+float64(length), 0)
} else {
index = math.Min(index, float64(length))
if index < 0 {
index = math.Max(index+length, 0)
} else {
index = math.Min(index, length)
}
return int64(uint(index))
}
return uint(index)
}
func rangeStartEnd(array []Value, size uint, negativeIsZero bool) (start, end uint) {
func rangeStartEnd(array []Value, size uint, negativeIsZero bool) (start, end int64) {
start = valueToRangeIndex(valueOfArrayIndex(array, 0), size, negativeIsZero)
if len(array) == 1 {
// If there is only the start argument, then end = size
end = size
end = int64(size)
return
}
// Assuming the argument is undefined...
end = size
end = int64(size)
endValue := valueOfArrayIndex(array, 1)
if !endValue.IsUndefined() {
// Which it is not, so get the value as an array index