[MERGE #6087 @akroshg] April servicing update for ChakraCore
Merge pull request #6087 from akroshg:stage1904
Fixes
CVE-2019-0739
CVE-2019-0806
CVE-2019-0810
CVE-2019-0812
CVE-2019-0829
CVE-2019-0860
CVE-2019-0861
diff --git a/Build/NuGet/.pack-version b/Build/NuGet/.pack-version
index 29eb291..40faed9 100644
--- a/Build/NuGet/.pack-version
+++ b/Build/NuGet/.pack-version
@@ -1 +1 @@
-1.11.7
+1.11.8
diff --git a/lib/Backend/GlobOpt.cpp b/lib/Backend/GlobOpt.cpp
index f09edda..76af550 100644
--- a/lib/Backend/GlobOpt.cpp
+++ b/lib/Backend/GlobOpt.cpp
@@ -3258,10 +3258,14 @@
}
originalPropertySym = sym->AsPropertySym();
- // Dont give a vale to 'arguments' property sym to prevent field copy prop of 'arguments'
+ // Don't give a value to 'arguments' property sym to prevent field copy prop of 'arguments'
if (originalPropertySym->AsPropertySym()->m_propertyId == Js::PropertyIds::arguments &&
originalPropertySym->AsPropertySym()->m_fieldKind == PropertyKindData)
{
+ if (opnd->AsSymOpnd()->IsPropertySymOpnd())
+ {
+ this->FinishOptPropOp(instr, opnd->AsPropertySymOpnd());
+ }
return nullptr;
}
@@ -4813,7 +4817,7 @@
}
else
{
- return NewGenericValue(src1ValueInfo->Type().ToDefiniteAnyNumber(), dst);
+ return NewGenericValue(src1ValueInfo->Type().ToDefiniteAnyNumber().SetCanBeTaggedValue(true), dst);
}
break;
@@ -4874,7 +4878,7 @@
{
valueType = ValueType::Number;
}
- return CreateDstUntransferredValue(valueType, instr, src1Val, src2Val);
+ return CreateDstUntransferredValue(valueType.SetCanBeTaggedValue(true), instr, src1Val, src2Val);
}
case Js::OpCode::Add_A:
@@ -4908,12 +4912,12 @@
{
// If one of them is a float, the result probably is a float instead of just int
// but should always be a number.
- valueType = ValueType::Float;
+ valueType = ValueType::Float.SetCanBeTaggedValue(true);
}
else
{
// Could be int, could be number
- valueType = ValueType::Number;
+ valueType = ValueType::Number.SetCanBeTaggedValue(true);
}
}
else if (src1ValueInfo->IsLikelyFloat() || src2ValueInfo->IsLikelyFloat())
@@ -4937,7 +4941,7 @@
&& (src2Val && src2ValueInfo->IsNotString() && src2ValueInfo->IsPrimitive()))
{
// If src1 and src2 are not strings and primitive, add should yield a number.
- valueType = ValueType::Number;
+ valueType = ValueType::Number.SetCanBeTaggedValue(true);
}
else if((src1Val && src1ValueInfo->IsLikelyString()) || (src2Val && src2ValueInfo->IsLikelyString()))
{
@@ -4958,7 +4962,7 @@
ValueType divValueType = GetDivValueType(instr, src1Val, src2Val, false);
if (divValueType.IsLikelyInt() || divValueType.IsFloat())
{
- return CreateDstUntransferredValue(divValueType, instr, src1Val, src2Val);
+ return CreateDstUntransferredValue(divValueType.SetCanBeTaggedValue(true), instr, src1Val, src2Val);
}
}
// fall-through
@@ -4990,11 +4994,11 @@
// This should ideally be NewNumberAndLikelyFloatValue since we know the result is a number but not sure if it will
// be a float value. However, that Number/LikelyFloat value type doesn't exist currently and all the necessary
// checks are done for float values (tagged int checks, etc.) so it's sufficient to just create a float value here.
- valueType = ValueType::Float;
+ valueType = ValueType::Float.SetCanBeTaggedValue(true);
}
else
{
- valueType = ValueType::Number;
+ valueType = ValueType::Number.SetCanBeTaggedValue(true);
}
return CreateDstUntransferredValue(valueType, instr, src1Val, src2Val);
diff --git a/lib/Backend/GlobOptFields.cpp b/lib/Backend/GlobOptFields.cpp
index 6a8007d..dbddb24 100644
--- a/lib/Backend/GlobOptFields.cpp
+++ b/lib/Backend/GlobOptFields.cpp
@@ -237,10 +237,17 @@
this->KillAllFields(bv); // This also kills all property type values, as the same bit-vector tracks those stack syms
SetAnyPropertyMayBeWrittenTo();
}
- else if (inGlobOpt && indexOpnd && !indexOpnd->GetValueType().IsInt() && !currentBlock->globOptData.IsInt32TypeSpecialized(indexOpnd->m_sym))
+ else if (inGlobOpt)
{
- // Write/delete to a non-integer numeric index can't alias a name on the RHS of a dot, but it change object layout
- this->KillAllObjectTypes(bv);
+ Value * indexValue = indexOpnd ? this->currentBlock->globOptData.FindValue(indexOpnd->GetSym()) : nullptr;
+ ValueInfo * indexValueInfo = indexValue ? indexValue->GetValueInfo() : nullptr;
+ int indexLowerBound = 0;
+
+ if (indirOpnd->GetOffset() < 0 || (indexOpnd && (!indexValueInfo || !indexValueInfo->TryGetIntConstantLowerBound(&indexLowerBound, false) || indexLowerBound < 0)))
+ {
+ // Write/delete to a non-integer numeric index can't alias a name on the RHS of a dot, but it change object layout
+ this->KillAllObjectTypes(bv);
+ }
}
}
@@ -487,7 +494,9 @@
case Js::OpCode::NewScObjectNoCtor:
if (inGlobOpt)
{
- KillObjectHeaderInlinedTypeSyms(this->currentBlock, false);
+ // Opcodes that make an object into a prototype may break object-header-inlining and final type opt.
+ // Kill all known object layouts.
+ KillAllObjectTypes(bv);
}
break;
diff --git a/lib/Backend/JITType.cpp b/lib/Backend/JITType.cpp
index a207dc5..a235bd0 100644
--- a/lib/Backend/JITType.cpp
+++ b/lib/Backend/JITType.cpp
@@ -35,7 +35,7 @@
Js::DynamicTypeHandler * handler = dynamicType->GetTypeHandler();
data->handler.isObjectHeaderInlinedTypeHandler = handler->IsObjectHeaderInlinedTypeHandler();
- data->handler.isLocked = handler->GetIsLocked();
+ data->handler.flags = handler->GetFlags();
data->handler.inlineSlotCapacity = handler->GetInlineSlotCapacity();
data->handler.offsetOfInlineSlots = handler->GetOffsetOfInlineSlots();
data->handler.slotCapacity = handler->GetSlotCapacity();
diff --git a/lib/Backend/JITTypeHandler.cpp b/lib/Backend/JITTypeHandler.cpp
index aca726b..dbecfb9 100644
--- a/lib/Backend/JITTypeHandler.cpp
+++ b/lib/Backend/JITTypeHandler.cpp
@@ -19,7 +19,13 @@
bool
JITTypeHandler::IsLocked() const
{
- return m_data.isLocked != FALSE;
+ return Js::DynamicTypeHandler::GetIsLocked(m_data.flags);
+}
+
+bool
+JITTypeHandler::IsPrototype() const
+{
+ return Js::DynamicTypeHandler::GetIsPrototype(m_data.flags);
}
uint16
diff --git a/lib/Backend/JITTypeHandler.h b/lib/Backend/JITTypeHandler.h
index c6e909f..9d2cc35 100644
--- a/lib/Backend/JITTypeHandler.h
+++ b/lib/Backend/JITTypeHandler.h
@@ -12,6 +12,7 @@
bool IsObjectHeaderInlinedTypeHandler() const;
bool IsLocked() const;
+ bool IsPrototype() const;
uint16 GetInlineSlotCapacity() const;
uint16 GetOffsetOfInlineSlots() const;
diff --git a/lib/Backend/Lower.cpp b/lib/Backend/Lower.cpp
index cb3efbe..a5d19c4 100644
--- a/lib/Backend/Lower.cpp
+++ b/lib/Backend/Lower.cpp
@@ -6223,7 +6223,7 @@
// Load the value from the slot, getting the slot ID from the cache.
uint16 index = propertySymOpnd->GetSlotIndex();
- Assert(index != -1);
+ AssertOrFailFast(index != (uint16)-1);
if (opndSlotArray->IsRegOpnd())
{
@@ -7204,7 +7204,7 @@
// Store the value to the slot, getting the slot index from the cache.
uint16 index = propertySymOpnd->GetSlotIndex();
- Assert(index != -1);
+ AssertOrFailFast(index != (uint16)-1);
#if defined(RECYCLER_WRITE_BARRIER_JIT) && (defined(_M_IX86) || defined(_M_AMD64))
if (opndSlotArray->IsRegOpnd())
@@ -7353,6 +7353,19 @@
{
Assert(labelTypeCheckFailed == nullptr && labelBothTypeChecksFailed == nullptr);
AssertMsg(!instrStFld->HasBailOutInfo(), "Why does a direct field store have bailout?");
+
+ if (propertySymOpnd->HasInitialType() && propertySymOpnd->HasFinalType())
+ {
+ bool isPrototypeTypeHandler = propertySymOpnd->GetInitialType()->GetTypeHandler()->IsPrototype();
+ if (isPrototypeTypeHandler)
+ {
+ LoadScriptContext(instrStFld);
+ m_lowererMD.LoadHelperArgument(instrStFld, IR::IntConstOpnd::New(propertySymOpnd->GetPropertyId(), TyInt32, m_func, true));
+ IR::Instr * invalidateCallInstr = IR::Instr::New(Js::OpCode::Call, m_func);
+ instrStFld->InsertBefore(invalidateCallInstr);
+ m_lowererMD.ChangeToHelperCall(invalidateCallInstr, IR::HelperInvalidateProtoCaches);
+ }
+ }
instrStFld->Remove();
return true;
}
@@ -8177,6 +8190,16 @@
// Now do the store.
GenerateDirectFieldStore(instrStFld, propertySymOpnd);
+
+ bool isPrototypeTypeHandler = initialType->GetTypeHandler()->IsPrototype();
+ if (isPrototypeTypeHandler)
+ {
+ LoadScriptContext(instrStFld);
+ m_lowererMD.LoadHelperArgument(instrStFld, IR::IntConstOpnd::New(propertySymOpnd->GetPropertyId(), TyInt32, m_func, true));
+ IR::Instr * invalidateCallInstr = IR::Instr::New(Js::OpCode::Call, m_func);
+ instrStFld->InsertBefore(invalidateCallInstr);
+ m_lowererMD.ChangeToHelperCall(invalidateCallInstr, IR::HelperInvalidateProtoCaches);
+ }
}
bool
diff --git a/lib/Common/ChakraCoreVersion.h b/lib/Common/ChakraCoreVersion.h
index 80ab6ed..0ade5e4 100644
--- a/lib/Common/ChakraCoreVersion.h
+++ b/lib/Common/ChakraCoreVersion.h
@@ -17,7 +17,7 @@
// ChakraCore version number definitions (used in ChakraCore binary metadata)
#define CHAKRA_CORE_MAJOR_VERSION 1
#define CHAKRA_CORE_MINOR_VERSION 11
-#define CHAKRA_CORE_PATCH_VERSION 7
+#define CHAKRA_CORE_PATCH_VERSION 8
#define CHAKRA_CORE_VERSION_RELEASE_QFE 0 // Redundant with PATCH_VERSION. Keep this value set to 0.
// -------------
diff --git a/lib/JITIDL/JITTypes.h b/lib/JITIDL/JITTypes.h
index 600a38b..8bc85a7 100644
--- a/lib/JITIDL/JITTypes.h
+++ b/lib/JITIDL/JITTypes.h
@@ -90,7 +90,7 @@
typedef struct TypeHandlerIDL
{
IDL_Field(boolean) isObjectHeaderInlinedTypeHandler;
- IDL_Field(boolean) isLocked;
+ IDL_Field(unsigned char) flags;
IDL_Field(unsigned short) inlineSlotCapacity;
IDL_Field(unsigned short) offsetOfInlineSlots;
diff --git a/lib/Runtime/Language/JavascriptOperators.cpp b/lib/Runtime/Language/JavascriptOperators.cpp
index 8d6d2ca..90f94b6 100644
--- a/lib/Runtime/Language/JavascriptOperators.cpp
+++ b/lib/Runtime/Language/JavascriptOperators.cpp
@@ -9582,6 +9582,11 @@
Var result = CALL_ENTRYPOINT(threadContext, marshalledFunction->GetEntryPoint(), function, CallInfo(flags, 2), thisVar, putValue);
Assert(result);
+
+ // Set implicit call flags so we bail out if we're trying to propagate the stored value forward. We can't count on the getter/setter
+ // to produce the stored value on a LdFld.
+ threadContext->AddImplicitCallFlags(ImplicitCall_Accessor);
+
return nullptr;
});
}
diff --git a/lib/Runtime/Library/JavascriptRegExpConstructor.cpp b/lib/Runtime/Library/JavascriptRegExpConstructor.cpp
index e1d347b..2be4848 100644
--- a/lib/Runtime/Library/JavascriptRegExpConstructor.cpp
+++ b/lib/Runtime/Library/JavascriptRegExpConstructor.cpp
@@ -360,6 +360,10 @@
EnsureValues(); // The last match info relies on the last input. Use it before it is changed.
this->lastInput = tempInput;
}
+
+ // Set implicit call flags since we are not necessarily making the original stored value available on re-load
+ // and are killing the store that backs two exposed properties.
+ this->GetScriptContext()->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_Accessor);
*result = true;
return true;
case PropertyIds::lastMatch:
diff --git a/lib/Runtime/Types/DictionaryTypeHandler.cpp b/lib/Runtime/Types/DictionaryTypeHandler.cpp
index 5da831b..e002554 100644
--- a/lib/Runtime/Types/DictionaryTypeHandler.cpp
+++ b/lib/Runtime/Types/DictionaryTypeHandler.cpp
@@ -139,7 +139,7 @@
PropertyString* propertyString = scriptContext->GetPropertyString(*propertyId);
*propertyStringName = propertyString;
T dataSlot = descriptor.template GetDataPropertyIndex<false>();
- if (dataSlot != NoSlots && (attribs & PropertyWritable))
+ if (dataSlot != NoSlots && (attribs & PropertyWritable) && type == typeToEnumerate)
{
PropertyValueInfo::SetCacheInfo(info, propertyString, propertyString->GetLdElemInlineCache(), false);
SetPropertyValueInfo(info, instance, dataSlot, &descriptor);
diff --git a/lib/Runtime/Types/SimpleTypeHandler.cpp b/lib/Runtime/Types/SimpleTypeHandler.cpp
index 32e6d3f..dd08d12 100644
--- a/lib/Runtime/Types/SimpleTypeHandler.cpp
+++ b/lib/Runtime/Types/SimpleTypeHandler.cpp
@@ -328,7 +328,7 @@
*propertyStringName = propStr;
PropertyValueInfo::SetCacheInfo(info, propStr, propStr->GetLdElemInlineCache(), false);
- if ((attribs & PropertyWritable) == PropertyWritable)
+ if ((attribs & PropertyWritable) == PropertyWritable && type == typeToEnumerate)
{
PropertyValueInfo::Set(info, instance, index, attribs);
}
diff --git a/lib/Runtime/Types/TypeHandler.h b/lib/Runtime/Types/TypeHandler.h
index 0feb677..6034bf3 100644
--- a/lib/Runtime/Types/TypeHandler.h
+++ b/lib/Runtime/Types/TypeHandler.h
@@ -348,13 +348,17 @@
(v) Seal
(vi) Freeze
*/
- bool GetIsLocked() const { return (this->flags & IsLockedFlag) != 0; }
+ bool GetIsLocked() const { return GetIsLocked(this->flags); }
+ static bool GetIsLocked(byte flags) { return (flags & IsLockedFlag) != 0; }
bool GetIsShared() const { return (this->flags & IsSharedFlag) != 0; }
bool GetMayBecomeShared() const { return (this->flags & MayBecomeSharedFlag) != 0; }
bool GetIsOrMayBecomeShared() const { return (this->flags & (MayBecomeSharedFlag | IsSharedFlag)) != 0; }
bool GetHasKnownSlot0() const { return (this->flags & HasKnownSlot0Flag) != 0; }
- bool GetIsPrototype() const { return (this->flags & IsPrototypeFlag) != 0; }
+
+ bool GetIsPrototype() const { return GetIsPrototype(this->flags); }
+ static bool GetIsPrototype(byte flags) { return (flags & IsPrototypeFlag) != 0; }
+
bool GetIsInlineSlotCapacityLocked() const { return (this->propertyTypes & PropertyTypesInlineSlotCapacityLocked) != 0; }
void LockTypeHandler() { Assert(IsLockable()); SetFlags(IsLockedFlag); }