Преглед изворни кода

Add bounds check back to TypedArray DirectSetItem

CVE-2016-0193

BaseTypedDirectSetItem used to perform a bounds check of the given index
against the length and would no-op if the index was out of range.  Fixes
were made back in Dec 2014 that changed this check to a bool
skipSetItem.  skipSetItem was set to true if the index was out of range,
or negative zero, or a string that wasn't an integer, but it was only
checked for in the `JavascriptOperators::OP_SetElementI` case.

In other cases it was sometimes set to true if index >= GetLength(), but
many cases were missed and just set the value to false, allowing for
writing to an element out of range.

To fix it the skipSetItem parameter has been removed from the
DirectSetItem API in favor of putting the bounds check back and creating
a separate DirectSetItemNoSet which peforms the equivalent of what
DirectSetItem did when skipSetItem was true.  This new API is called
from the one place that does the extra -0 and string checking where it
matters, `TypedArrayBase::ValidateIndexAndDirectSetItem`.

Eliminating the skipSetItem parameter ensures we won't mess up calls to
DirectSetItem API in future changes.
Ian Halliday пре 9 година
родитељ
комит
352303b681

+ 11 - 11
lib/Runtime/Library/JavascriptArray.cpp

@@ -5184,8 +5184,8 @@ Case0:
                     lowerExists = typedArrayBase->HasItem(lower);
                     upperExists = typedArrayBase->HasItem(upper);
 
-                    h.ThrowTypeErrorOnFailure(typedArrayBase->DirectSetItem(lower, upperValue, false));
-                    h.ThrowTypeErrorOnFailure(typedArrayBase->DirectSetItem(upper, lowerValue, false));
+                    h.ThrowTypeErrorOnFailure(typedArrayBase->DirectSetItem(lower, upperValue));
+                    h.ThrowTypeErrorOnFailure(typedArrayBase->DirectSetItem(upper, lowerValue));
                 }
             }
             else
@@ -5204,21 +5204,21 @@ Case0:
                     {
                         if (upperExists)
                         {
-                            h.ThrowTypeErrorOnFailure(typedArrayBase->DirectSetItem(lower, upperValue, false));
-                            h.ThrowTypeErrorOnFailure(typedArrayBase->DirectSetItem(upper, lowerValue, false));
+                            h.ThrowTypeErrorOnFailure(typedArrayBase->DirectSetItem(lower, upperValue));
+                            h.ThrowTypeErrorOnFailure(typedArrayBase->DirectSetItem(upper, lowerValue));
                         }
                         else
                         {
                             // This will always fail for a TypedArray if lower < length
                             h.ThrowTypeErrorOnFailure(typedArrayBase->DeleteItem(lower, PropertyOperation_ThrowIfNotExtensible));
-                            h.ThrowTypeErrorOnFailure(typedArrayBase->DirectSetItem(upper, lowerValue, false));
+                            h.ThrowTypeErrorOnFailure(typedArrayBase->DirectSetItem(upper, lowerValue));
                         }
                     }
                     else
                     {
                         if (upperExists)
                         {
-                            h.ThrowTypeErrorOnFailure(typedArrayBase->DirectSetItem(lower, upperValue, false));
+                            h.ThrowTypeErrorOnFailure(typedArrayBase->DirectSetItem(lower, upperValue));
                             // This will always fail for a TypedArray if upper < length
                             h.ThrowTypeErrorOnFailure(typedArrayBase->DeleteItem(upper, PropertyOperation_ThrowIfNotExtensible));
                         }
@@ -5930,7 +5930,7 @@ Case0:
                 // The object we got back from the constructor might not be a TypedArray. In fact, it could be any object.
                 if (newTypedArray)
                 {
-                    newTypedArray->DirectSetItem(i, element, false);
+                    newTypedArray->DirectSetItem(i, element);
                 }
                 else if (newArr)
                 {
@@ -8567,7 +8567,7 @@ Case0:
                     {
                         Var val = typedArrayBase->DirectGetItem(fromIndex);
 
-                        typedArrayBase->DirectSetItem(toIndex, val, false);
+                        typedArrayBase->DirectSetItem(toIndex, val);
                     }
                     else if (pArr)
                     {
@@ -8679,7 +8679,7 @@ Case0:
             {
                 if (typedArrayBase)
                 {
-                    typedArrayBase->DirectSetItem(u32k, fillValue, false);
+                    typedArrayBase->DirectSetItem(u32k, fillValue);
                 }
                 else if (pArr)
                 {
@@ -8934,7 +8934,7 @@ Case0:
                 // the normal Set path.
                 if (newTypedArray)
                 {
-                    newTypedArray->DirectSetItem(k, mappedValue, false);
+                    newTypedArray->DirectSetItem(k, mappedValue);
                 }
                 else if (newArr)
                 {
@@ -9816,7 +9816,7 @@ Case0:
             {
                 Var kValue = args[k + 1];
 
-                newTypedArray->DirectSetItem(k, kValue, false);
+                newTypedArray->DirectSetItem(k, kValue);
             }
         }
         else

+ 177 - 54
lib/Runtime/Library/TypedArray.cpp

@@ -459,7 +459,7 @@ namespace Js
         }
         else if (GetScriptContext()->IsNumericPropertyId(propertyId, &index))
         {
-            this->DirectSetItem(index, value, index >= GetLength());
+            this->DirectSetItem(index, value);
             return true;
         }
         else
@@ -492,8 +492,7 @@ namespace Js
 
     BOOL TypedArrayBase::SetItem(uint32 index, Var value, PropertyOperationFlags flags)
     {
-        // Skip set item if index >= GetLength()
-        DirectSetItem(index, value, index >= GetLength());
+        DirectSetItem(index, value);
         return true;
     }
 
@@ -764,7 +763,7 @@ namespace Js
             {
                 for (uint32 i = 0; i < sourceLength; i++)
                 {
-                    DirectSetItem(offset + i, source->DirectGetItem(i), false);
+                    DirectSetItem(offset + i, source->DirectGetItem(i));
                 }
             }
             else
@@ -778,7 +777,7 @@ namespace Js
                 }
                 for (uint32 i = 0; i < sourceLength; i++)
                 {
-                    DirectSetItem(offset + i, tmpArray->DirectGetItem(i), false);
+                    DirectSetItem(offset + i, tmpArray->DirectGetItem(i));
                 }
             }
         }
@@ -805,7 +804,7 @@ namespace Js
             {
                 itemValue = undefinedValue;
             }
-            DirectSetItem(offset + i, itemValue, false);
+            DirectSetItem(offset + i, itemValue);
         }
     }
 
@@ -1421,7 +1420,7 @@ namespace Js
                     // We're likely to have constructed a new TypedArray, but the constructor could return any object
                     if (newTypedArrayBase)
                     {
-                        newTypedArrayBase->DirectSetItem(k, kValue, false);
+                        newTypedArrayBase->DirectSetItem(k, kValue);
                     }
                     else if (newArr)
                     {
@@ -1499,7 +1498,7 @@ namespace Js
                 // If constructor built a TypedArray (likely) or Array (maybe likely) we can do a more direct set operation
                 if (newTypedArrayBase)
                 {
-                    newTypedArrayBase->DirectSetItem(k, kValue, false);
+                    newTypedArrayBase->DirectSetItem(k, kValue);
                 }
                 else if (newArr)
                 {
@@ -1722,7 +1721,7 @@ namespace Js
 
                 for (uint32 i = 0; i < captured; i++)
                 {
-                    newArr->DirectSetItem(i, tempList->Item(i), false);
+                    newArr->DirectSetItem(i, tempList->Item(i));
                 }
             }
             else
@@ -2491,9 +2490,15 @@ namespace Js
 
         // If index is not numeric, goto [[Set]] property path
         if (*isNumericIndex)
-            return DirectSetItem(indexToSet, value, skipSetItem);
+        {
+            return skipSetItem ?
+                DirectSetItemNoSet(indexToSet, value) :
+                DirectSetItem(indexToSet, value);
+        }
         else
+        {
             return TRUE;
+        }
     }
 
     // Validate the index used for typed arrays with below rules:
@@ -2973,14 +2978,24 @@ namespace Js
         return static_cast<BoolArray*>(RecyclableObject::FromVar(aValue));
     }
 
-    __inline BOOL Int8Array::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Int8Array::DirectSetItem(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToInt8);
+    }
+
+    __inline BOOL Int8VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToInt8);
+    }
+
+    __inline BOOL Int8Array::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToInt8);
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToInt8);
     }
 
-    __inline BOOL Int8VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Int8VirtualArray::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToInt8);
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToInt8);
     }
 
     __inline Var Int8Array::DirectGetItem(__in uint32 index)
@@ -2993,13 +3008,22 @@ namespace Js
         return BaseTypedDirectGetItem(index);
     }
 
-    __inline BOOL Uint8Array::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Uint8Array::DirectSetItem(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToUInt8);
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToUInt8);
     }
-    __inline BOOL Uint8VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Uint8VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToUInt8);
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToUInt8);
+    }
+
+    __inline BOOL Uint8Array::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToUInt8);
+    }
+    __inline BOOL Uint8VirtualArray::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToUInt8);
     }
 
     __inline Var Uint8Array::DirectGetItem(__in uint32 index)
@@ -3012,9 +3036,14 @@ namespace Js
     }
 
 
-    __inline BOOL Uint8ClampedArray::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Uint8ClampedArray::DirectSetItem(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToUInt8Clamped);
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToUInt8Clamped);
+    }
+
+    __inline BOOL Uint8ClampedArray::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToUInt8Clamped);
     }
 
     __inline Var Uint8ClampedArray::DirectGetItem(__in uint32 index)
@@ -3022,9 +3051,14 @@ namespace Js
         return BaseTypedDirectGetItem(index);
     }
 
-    __inline BOOL Uint8ClampedVirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Uint8ClampedVirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToUInt8Clamped);
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToUInt8Clamped);
+    }
+
+    __inline BOOL Uint8ClampedVirtualArray::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToUInt8Clamped);
     }
 
     __inline Var Uint8ClampedVirtualArray::DirectGetItem(__in uint32 index)
@@ -3032,9 +3066,14 @@ namespace Js
         return BaseTypedDirectGetItem(index);
     }
 
-    __inline BOOL Int16Array::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Int16Array::DirectSetItem(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToInt16);
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToInt16);
+    }
+
+    __inline BOOL Int16Array::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToInt16);
     }
 
     __inline Var Int16Array::DirectGetItem(__in uint32 index)
@@ -3042,9 +3081,14 @@ namespace Js
         return BaseTypedDirectGetItem(index);
     }
 
-    __inline BOOL Int16VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Int16VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToInt16);
+    }
+
+    __inline BOOL Int16VirtualArray::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToInt16);
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToInt16);
     }
 
     __inline Var Int16VirtualArray::DirectGetItem(__in uint32 index)
@@ -3053,9 +3097,14 @@ namespace Js
     }
 
 
-    __inline BOOL Uint16Array::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Uint16Array::DirectSetItem(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToUInt16);
+    }
+
+    __inline BOOL Uint16Array::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToUInt16);
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToUInt16);
     }
 
     __inline Var Uint16Array::DirectGetItem(__in uint32 index)
@@ -3063,9 +3112,14 @@ namespace Js
         return BaseTypedDirectGetItem(index);
     }
 
-    __inline BOOL Uint16VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Uint16VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToUInt16);
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToUInt16);
+    }
+
+    __inline BOOL Uint16VirtualArray::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToUInt16);
     }
 
     __inline Var Uint16VirtualArray::DirectGetItem(__in uint32 index)
@@ -3075,9 +3129,14 @@ namespace Js
 
 
 
-    __inline BOOL Int32Array::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Int32Array::DirectSetItem(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToInt32);
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToInt32);
+    }
+
+    __inline BOOL Int32Array::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToInt32);
     }
 
     __inline Var Int32Array::DirectGetItem(__in uint32 index)
@@ -3085,9 +3144,14 @@ namespace Js
         return BaseTypedDirectGetItem(index);
     }
 
-    __inline BOOL Int32VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Int32VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToInt32);
+    }
+
+    __inline BOOL Int32VirtualArray::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToInt32);
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToInt32);
     }
 
     __inline Var Int32VirtualArray::DirectGetItem(__in uint32 index)
@@ -3096,9 +3160,14 @@ namespace Js
     }
 
 
-    __inline BOOL Uint32Array::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Uint32Array::DirectSetItem(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToUInt32);
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToUInt32);
+    }
+
+    __inline BOOL Uint32Array::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToUInt32);
     }
 
     __inline Var Uint32Array::DirectGetItem(__in uint32 index)
@@ -3106,9 +3175,14 @@ namespace Js
         return BaseTypedDirectGetItem(index);
     }
 
-    __inline BOOL Uint32VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Uint32VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToUInt32);
+    }
+
+    __inline BOOL Uint32VirtualArray::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToUInt32);
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToUInt32);
     }
 
     __inline Var Uint32VirtualArray::DirectGetItem(__in uint32 index)
@@ -3118,9 +3192,14 @@ namespace Js
 
 
 
-    __inline BOOL Float32Array::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Float32Array::DirectSetItem(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToFloat);
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToFloat);
+    }
+
+    __inline BOOL Float32Array::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToFloat);
     }
 
     Var Float32Array::DirectGetItem(__in uint32 index)
@@ -3128,9 +3207,14 @@ namespace Js
         return TypedDirectGetItemWithCheck(index);
     }
 
-    __inline BOOL Float32VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Float32VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToFloat);
+    }
+
+    __inline BOOL Float32VirtualArray::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToFloat);
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToFloat);
     }
 
     Var Float32VirtualArray::DirectGetItem(__in uint32 index)
@@ -3139,9 +3223,14 @@ namespace Js
     }
 
 
-    __inline BOOL Float64Array::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Float64Array::DirectSetItem(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToNumber);
+    }
+
+    __inline BOOL Float64Array::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToNumber);
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToNumber);
     }
 
     __inline Var Float64Array::DirectGetItem(__in uint32 index)
@@ -3149,9 +3238,14 @@ namespace Js
         return TypedDirectGetItemWithCheck(index);
     }
 
-    __inline BOOL Float64VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Float64VirtualArray::DirectSetItem(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToNumber);
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToNumber);
+    }
+
+    __inline BOOL Float64VirtualArray::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToNumber);
     }
 
     __inline Var Float64VirtualArray::DirectGetItem(__in uint32 index)
@@ -3160,9 +3254,14 @@ namespace Js
     }
 
 
-    __inline BOOL Int64Array::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Int64Array::DirectSetItem(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToInt64);
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToInt64);
+    }
+
+    __inline BOOL Int64Array::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToInt64);
     }
 
     __inline Var Int64Array::DirectGetItem(__in uint32 index)
@@ -3170,9 +3269,14 @@ namespace Js
         return BaseTypedDirectGetItem(index);
     }
 
-    __inline BOOL Uint64Array::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL Uint64Array::DirectSetItem(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToUInt64);
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToUInt64);
+    }
+
+    __inline BOOL Uint64Array::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToUInt64);
     }
 
     __inline Var Uint64Array::DirectGetItem(__in uint32 index)
@@ -3180,9 +3284,14 @@ namespace Js
         return BaseTypedDirectGetItem(index);
     }
 
-    __inline BOOL BoolArray::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL BoolArray::DirectSetItem(__in uint32 index, __in Js::Var value)
+    {
+        return BaseTypedDirectSetItem(index, value, JavascriptConversion::ToBool);
+    }
+
+    __inline BOOL BoolArray::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
     {
-        return BaseTypedDirectSetItem(index, value, skipSetElement, JavascriptConversion::ToBool);
+        return BaseTypedDirectSetItemNoSet(index, value, JavascriptConversion::ToBool);
     }
 
     __inline Var BoolArray::DirectGetItem(__in uint32 index)
@@ -3239,7 +3348,7 @@ namespace Js
         return static_cast<CharArray*>(RecyclableObject::FromVar(aValue));
     }
 
-    __inline BOOL CharArray::DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement)
+    __inline BOOL CharArray::DirectSetItem(__in uint32 index, __in Js::Var value)
     {
         ScriptContext* scriptContext = GetScriptContext();
         // A typed array is Integer Indexed Exotic object, so doing a get translates to 9.4.5.9 IntegerIndexedElementSet
@@ -3250,7 +3359,7 @@ namespace Js
             JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray);
         }
 
-        if (skipSetElement)
+        if (index >= GetLength())
         {
             return FALSE;
         }
@@ -3271,6 +3380,20 @@ namespace Js
         return TRUE;
     }
 
+    __inline BOOL CharArray::DirectSetItemNoSet(__in uint32 index, __in Js::Var value)
+    {
+        ScriptContext* scriptContext = GetScriptContext();
+        // A typed array is Integer Indexed Exotic object, so doing a get translates to 9.4.5.9 IntegerIndexedElementSet
+        Js::JavascriptConversion::ToString(value, scriptContext);
+
+        if (this->IsDetachedBuffer())
+        {
+            JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray);
+        }
+
+        return FALSE;
+    }
+
     __inline Var CharArray::DirectGetItem(__in uint32 index)
     {
         // A typed array is Integer Indexed Exotic object, so doing a get translates to 9.4.5.8 IntegerIndexedElementGet

+ 23 - 7
lib/Runtime/Library/TypedArray.h

@@ -138,7 +138,8 @@ namespace Js
         static BOOL IsDetachedTypedArray(Var aValue);
         static HRESULT GetBuffer(Var aValue, ArrayBuffer** outBuffer, uint32* outOffset, uint32* outLength);
 
-        virtual BOOL DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetItem) = 0;
+        virtual BOOL DirectSetItem(__in uint32 index, __in Js::Var value) = 0;
+        virtual BOOL DirectSetItemNoSet(__in uint32 index, __in Js::Var value) = 0;
         virtual Var  DirectGetItem(__in uint32 index) = 0;
 
         uint32 GetByteLength() const { return length * BYTES_PER_ELEMENT; }
@@ -335,7 +336,6 @@ namespace Js
                 // If we want to start copying past the length of the array, all index are no-op
                 return true;
             }
-
             if (UInt32Math::Add(newStart, newLength) > GetLength())
             {
                 newLength = GetLength() - newStart;
@@ -360,7 +360,7 @@ namespace Js
             return TRUE;
         }
 
-        __inline BOOL BaseTypedDirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetElement, TypeName (*convFunc)(Var value, ScriptContext* scriptContext))
+        __inline BOOL BaseTypedDirectSetItem(__in uint32 index, __in Js::Var value, TypeName (*convFunc)(Var value, ScriptContext* scriptContext))
         {
             // This call can potentially invoke user code, and may end up detaching the underlying array (this).
             // Therefore it was brought out and above the IsDetached check
@@ -371,7 +371,7 @@ namespace Js
                 JavascriptError::ThrowTypeError(GetScriptContext(), JSERR_DetachedTypedArray);
             }
 
-            if (skipSetElement)
+            if (index >= GetLength())
             {
                 return FALSE;
             }
@@ -383,9 +383,24 @@ namespace Js
             typedBuffer[index] = typedValue;
 
             return TRUE;
+        }
+
+        __inline BOOL BaseTypedDirectSetItemNoSet(__in uint32 index, __in Js::Var value, TypeName (*convFunc)(Var value, ScriptContext* scriptContext))
+        {
+            // This call can potentially invoke user code, and may end up detaching the underlying array (this).
+            // Therefore it was brought out and above the IsDetached check
+            convFunc(value, GetScriptContext());
+
+            if (this->IsDetachedBuffer()) // 9.4.5.9 IntegerIndexedElementSet
+            {
+                JavascriptError::ThrowTypeError(GetScriptContext(), JSERR_DetachedTypedArray);
             }
 
-        virtual BOOL DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetItem) override sealed;
+            return FALSE;
+        }
+
+        virtual BOOL DirectSetItem(__in uint32 index, __in Js::Var value) override sealed;
+        virtual BOOL DirectSetItemNoSet(__in uint32 index, __in Js::Var value) override sealed;
         virtual Var  DirectGetItem(__in uint32 index) override sealed;
 
 
@@ -393,7 +408,7 @@ namespace Js
         {
             AssertMsg(arr != nullptr, "Array shouldn't be nullptr.");
 
-            return arr->DirectSetItem(index, value, index >= arr->GetLength());
+            return arr->DirectSetItem(index, value);
         }
 
     protected:
@@ -438,7 +453,8 @@ namespace Js
         Var Subarray(uint32 begin, uint32 end);
         static CharArray* FromVar(Var aValue);
 
-        virtual BOOL DirectSetItem(__in uint32 index, __in Js::Var value, __in bool skipSetItem) override;
+        virtual BOOL DirectSetItem(__in uint32 index, __in Js::Var value) override;
+        virtual BOOL DirectSetItemNoSet(__in uint32 index, __in Js::Var value) override;
         virtual Var  DirectGetItem(__in uint32 index) override;
 
     protected:

+ 9 - 0
test/typedarray/bug_OS_6911900.js

@@ -0,0 +1,9 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+var ua = new Uint32Array(0x10);
+ua.__proto__ = new Array(0xffffffff);
+ua.fill(0x41, 0x41414141, 0x41414141 + 1); // shouldn't assert or crash
+print("passed");

+ 5 - 0
test/typedarray/rlexe.xml

@@ -322,4 +322,9 @@ Below test fails with difference in space. Investigate the cause and re-enable t
       <compile-flags>-mic:1 -off:simplejit -off:JITLoopBody -mmoc:0</compile-flags>
     </default>
   </test>
+  <test>
+    <default>
+      <files>bug_OS_6911900.js</files>
+    </default>
+  </test>
 </regress-exe>