VYPR
High severityNVD Advisory· Published Feb 15, 2018· Updated Sep 16, 2024

CVE-2018-0858

CVE-2018-0858

Description

ChakraCore scripting engine memory corruption vulnerability allows remote code execution via specially crafted content.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

ChakraCore scripting engine memory corruption vulnerability allows remote code execution via specially crafted content.

Vulnerability

A memory corruption vulnerability exists in the ChakraCore scripting engine, affecting how it handles objects in memory. This issue, identified as CVE-2018-0858, is a scripting engine memory corruption vulnerability that can be exploited remotely. The vulnerability affects ChakraCore versions prior to the fix included in servicing release 18-02B. The official description confirms the flaw is due to improper handling of objects in memory by the ChakraCore scripting engine [1]. A commit fix shows changes to the type definitions in the TTD namespace, specifically altering Js::Var* to Field(Js::Var)* in the slot array map and related functions [4]. This indicates the bug involves incorrect type handling during time-travel debugging data structures.

Exploitation

An attacker can exploit this vulnerability by crafting specially designed content that, when loaded by a target user in an application using ChakraCore (such as Microsoft Edge), triggers the memory corruption. The attacker requires the ability to host or deliver malicious web content to the victim. No additional privileges are needed beyond what a typical web user has. The attack is network-based and requires user interaction (e.g., visiting a malicious website or clicking a link) [2]. The exploitation sequence involves the ChakraCore engine processing the malicious content, leading to memory corruption.

Impact

Successful exploitation allows the attacker to execute arbitrary code in the context of the current user. This can lead to complete compromise of the target system, including the ability to install programs, view, change, or delete data, and create new accounts with full user rights. The impact is classified as remote code execution [1] [2]. Given the browser context, the attacker may gain the same privileges as the user running the browser.

Mitigation

Microsoft addressed this vulnerability in the ChakraCore servicing release 18-02B. The fix is included in the commit 972009a89e51c69971b80b1f5394886b304f880a [4]. Users should update to the latest patched version of ChakraCore or ensure that applications using it (such as Microsoft Edge) receive the update. Microsoft Edge was patched in the February 2018 security update [2]. ChakraCore 1.11 receives security updates until March 9, 2021 [3]. There is no evidence this CVE is listed in the CISA Known Exploited Vulnerabilities (KEV) catalog.

AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
Microsoft.ChakraCoreNuGet
< 1.8.11.8.1

Affected products

2

Patches

1
972009a89e51

ChakraCore fix for servicing release 18-02B: CVE-2018-0858

https://github.com/chakra-core/ChakraCoreJianchun XuJan 17, 2018via ghsa
40 files changed · +238 106
  • lib/Backend/FunctionJITTimeInfo.cpp+2 2 modified
    @@ -112,7 +112,7 @@ FunctionJITTimeInfo::BuildJITTimeData(
             if(objTypeSpecInfo)
             {
                 jitData->objTypeSpecFldInfoCount = jitData->bodyData->inlineCacheCount;
    -            jitData->objTypeSpecFldInfoArray = (ObjTypeSpecFldIDL**)objTypeSpecInfo;
    +            jitData->objTypeSpecFldInfoArray = unsafe_write_barrier_cast<ObjTypeSpecFldIDL**>(objTypeSpecInfo);
             }
             for (Js::InlineCacheIndex i = 0; i < jitData->bodyData->inlineCacheCount; ++i)
             {
    @@ -131,7 +131,7 @@ FunctionJITTimeInfo::BuildJITTimeData(
             Assert(globObjTypeSpecInfo != nullptr);
     
             jitData->globalObjTypeSpecFldInfoCount = codeGenData->GetGlobalObjTypeSpecFldInfoCount();
    -        jitData->globalObjTypeSpecFldInfoArray = (ObjTypeSpecFldIDL**)globObjTypeSpecInfo;
    +        jitData->globalObjTypeSpecFldInfoArray = unsafe_write_barrier_cast<ObjTypeSpecFldIDL**>(globObjTypeSpecInfo);
         }
         const Js::FunctionCodeGenJitTimeData * nextJITData = codeGenData->GetNext();
         if (nextJITData != nullptr)
    
  • lib/Backend/JITTimeFunctionBody.cpp+2 2 modified
    @@ -25,7 +25,7 @@ JITTimeFunctionBody::InitializeJITFunctionData(
         jitBody->constCount = numConstants;
         if (numConstants > 0)
         {
    -        jitBody->constTable = (intptr_t *)PointerValue(functionBody->GetConstTable());
    +        jitBody->constTable = unsafe_write_barrier_cast<intptr_t *>(functionBody->GetConstTable());
             if (!functionBody->GetIsAsmJsFunction())
             {
                 jitBody->constTableContent = AnewStructZ(arena, ConstTableContentIDL);
    @@ -242,7 +242,7 @@ JITTimeFunctionBody::InitializeJITFunctionData(
         jitBody->displayName = (char16 *)functionBody->GetDisplayName();
         jitBody->objectLiteralTypesAddr = (intptr_t)functionBody->GetObjectLiteralTypesWithLock();
         jitBody->literalRegexCount = functionBody->GetLiteralRegexCount();
    -    jitBody->literalRegexes = (intptr_t*)functionBody->GetLiteralRegexesWithLock();
    +    jitBody->literalRegexes = unsafe_write_barrier_cast<intptr_t*>(functionBody->GetLiteralRegexesWithLock());
     
         Js::AuxArray<uint32> * slotIdInCachedScopeToNestedIndexArray = functionBody->GetSlotIdInCachedScopeToNestedIndexArrayWithLock();
         if (slotIdInCachedScopeToNestedIndexArray)
    
  • lib/Common/Memory/Allocator.h+1 1 modified
    @@ -174,7 +174,7 @@ inline T* PostAllocationCallback(const type_info& objType, T *obj)
     
     // Free routine where we don't care about following C++ semantics (e.g. calling the destructor)
     #define AllocatorFree(alloc, freeFunc, obj, size) \
    -        (alloc->*freeFunc)((void*)obj, size)
    +        (alloc->*freeFunc)(obj, size)
     
     // default type allocator implementation
     template <typename TAllocator, typename T>
    
  • lib/Common/Memory/WriteBarrierMacros.h+8 0 modified
    @@ -41,3 +41,11 @@
     
     // use with FieldWithBarrier structs
     #define FORCE_NO_WRITE_BARRIER_TAG(arg) arg, _no_write_barrier_tag()
    +
    +// Unsafely cast a typical "Field() *" type. Only use in rare cases where we
    +// understand the underlying memory usage.
    +template <class T, class U>
    +inline T unsafe_write_barrier_cast(U p)
    +{
    +    return (T)p;
    +}
    
  • lib/Runtime/Base/FunctionBody.h+3 2 modified
    @@ -3598,8 +3598,9 @@ namespace Js
             static uint const EncodedSlotCountSlotIndex = 0;
             static uint const ScopeMetadataSlotIndex = 1;    // Either a FunctionBody* or DebuggerScope*
             static uint const FirstSlotIndex = 2;
    +
         public:
    -        ScopeSlots(Var* slotArray) : slotArray((Field(Var)*)slotArray)
    +        ScopeSlots(Field(Var)* slotArray) : slotArray(slotArray)
             {
             }
     
    @@ -3710,7 +3711,7 @@ namespace Js
             bool   GetStrictMode() const { return strictMode; }
             void   SetStrictMode(bool flag) { this->strictMode = flag; }
     
    -        void** GetDataAddress() { return (void**)&this->scopes; }
    +        Field(void*)* GetDataAddress() { return this->scopes; }
             static uint32 GetOffsetOfStrictMode() { return offsetof(FrameDisplay, strictMode); }
             static uint32 GetOffsetOfLength() { return offsetof(FrameDisplay, length); }
             static uint32 GetOffsetOfScopes() { return offsetof(FrameDisplay, scopes); }
    
  • lib/Runtime/ByteCode/AsmJsByteCodeDumper.cpp+1 1 modified
    @@ -217,7 +217,7 @@ namespace Js
     
         void AsmJsByteCodeDumper::DumpConstants(AsmJsFunc* func, FunctionBody* body)
         {
    -        byte* table = (byte*)((Var*)body->GetConstTable());
    +        byte* table = (byte*)body->GetConstTable();
             auto constSrcInfos = func->GetTypedRegisterAllocator().GetConstSourceInfos();
             for (int i = 0; i < WAsmJs::LIMIT; ++i)
             {
    
  • lib/Runtime/Debug/DiagObjectModel.cpp+1 1 modified
    @@ -4086,7 +4086,7 @@ namespace Js
             else
             {
                 // The scope is defined by a slot array object so grab the function body out to get the function name.
    -            ScopeSlots slotArray = ScopeSlots(reinterpret_cast<Var*>(instance));
    +            ScopeSlots slotArray = ScopeSlots(reinterpret_cast<Field(Var)*>(instance));
     
                 if(slotArray.IsDebuggerScopeSlotArray())
                 {
    
  • lib/Runtime/Debug/DiagObjectModel.h+3 2 modified
    @@ -251,8 +251,9 @@ namespace Js
             virtual void PopulateMembers() override;
             virtual IDiagObjectAddress * GetObjectAddress(int index) override;
     
    -        ScopeSlots GetSlotArray() {
    -            Var *slotArray = (Var *) instance;
    +        ScopeSlots GetSlotArray()
    +        {
    +            Field(Var) *slotArray = (Field(Var) *) instance;
                 Assert(slotArray != nullptr);
                 return ScopeSlots(slotArray);
             }
    
  • lib/Runtime/Debug/TTInflateMap.cpp+2 2 modified
    @@ -191,7 +191,7 @@ namespace TTD
             return this->m_environmentMap.LookupKnownItem(envid);
         }
     
    -    Js::Var* InflateMap::LookupSlotArray(TTD_PTR_ID slotid) const
    +    Field(Js::Var)* InflateMap::LookupSlotArray(TTD_PTR_ID slotid) const
         {
             return this->m_slotArrayMap.LookupKnownItem(slotid);
         }
    @@ -238,7 +238,7 @@ namespace TTD
             this->m_environmentPinSet->AddNew(value);
         }
     
    -    void InflateMap::AddSlotArray(TTD_PTR_ID slotId, Js::Var* value)
    +    void InflateMap::AddSlotArray(TTD_PTR_ID slotId, Field(Js::Var)* value)
         {
             this->m_slotArrayMap.AddItem(slotId, value);
             this->m_slotArrayPinSet->AddNew(value);
    
  • lib/Runtime/Debug/TTInflateMap.h+4 4 modified
    @@ -15,14 +15,14 @@ namespace TTD
             TTDIdentifierDictionary<TTD_PTR_ID, Js::DynamicTypeHandler*> m_handlerMap;
             TTDIdentifierDictionary<TTD_PTR_ID, Js::Type*> m_typeMap;
     
    -        //The maps for script contexts and objects 
    +        //The maps for script contexts and objects
             TTDIdentifierDictionary<TTD_LOG_PTR_ID, Js::GlobalObject*> m_tagToGlobalObjectMap; //get the script context from here
             TTDIdentifierDictionary<TTD_PTR_ID, Js::RecyclableObject*> m_objectMap;
     
             //The maps for inflated function bodies
             TTDIdentifierDictionary<TTD_PTR_ID, Js::FunctionBody*> m_functionBodyMap;
             TTDIdentifierDictionary<TTD_PTR_ID, Js::FrameDisplay*> m_environmentMap;
    -        TTDIdentifierDictionary<TTD_PTR_ID, Js::Var*> m_slotArrayMap;
    +        TTDIdentifierDictionary<TTD_PTR_ID, Field(Js::Var)*> m_slotArrayMap;
     
             //The maps for resolving debug scopes
             TTDIdentifierDictionary<TTD_PTR_ID, Js::FunctionBody*> m_debuggerScopeHomeBodyMap;
    @@ -72,7 +72,7 @@ namespace TTD
     
             Js::FunctionBody* LookupFunctionBody(TTD_PTR_ID functionId) const;
             Js::FrameDisplay* LookupEnvironment(TTD_PTR_ID envid) const;
    -        Js::Var* LookupSlotArray(TTD_PTR_ID slotid) const;
    +        Field(Js::Var)* LookupSlotArray(TTD_PTR_ID slotid) const;
     
             void LookupInfoForDebugScope(TTD_PTR_ID dbgScopeId, Js::FunctionBody** homeBody, int32* chainIndex) const;
     
    @@ -86,7 +86,7 @@ namespace TTD
     
             void AddInflationFunctionBody(TTD_PTR_ID functionId, Js::FunctionBody* value);
             void AddEnvironment(TTD_PTR_ID envId, Js::FrameDisplay* value);
    -        void AddSlotArray(TTD_PTR_ID slotId, Js::Var* value);
    +        void AddSlotArray(TTD_PTR_ID slotId, Field(Js::Var)* value);
     
             void UpdateFBScopes(const NSSnapValues::SnapFunctionBodyScopeChain& scopeChainInfo, Js::FunctionBody* fb);
     
    
  • lib/Runtime/Debug/TTSnapObjects.cpp+1 1 modified
    @@ -918,7 +918,7 @@ namespace TTD
                     }
                 }
     
    -            return ctx->GetLibrary()->CreateBoundFunction_TTD(bFunction, bThis, snapBoundInfo->ArgCount, (Js::Var*)bArgs);
    +            return ctx->GetLibrary()->CreateBoundFunction_TTD(bFunction, bThis, snapBoundInfo->ArgCount, bArgs);
             }
     
             void EmitAddtlInfo_SnapBoundFunctionInfo(const SnapObject* snpObject, FileWriter* writer)
    
  • lib/Runtime/Debug/TTSnapshot.cpp+1 1 modified
    @@ -541,7 +541,7 @@ namespace TTD
             for(auto iter = this->m_slotArrayEntries.GetIterator(); iter.IsValid(); iter.MoveNext())
             {
                 const NSSnapValues::SlotArrayInfo* sai = iter.Current();
    -            Js::Var* slots = NSSnapValues::InflateSlotArrayInfo(sai, inflator);
    +            Field(Js::Var)* slots = NSSnapValues::InflateSlotArrayInfo(sai, inflator);
     
                 inflator->AddSlotArray(sai->SlotId, slots);
             }
    
  • lib/Runtime/Debug/TTSnapshotExtractor.cpp+3 3 modified
    @@ -88,7 +88,7 @@ namespace TTD
             }
         }
     
    -    void SnapshotExtractor::ExtractSlotArrayIfNeeded(Js::ScriptContext* ctx, Js::Var* scope)
    +    void SnapshotExtractor::ExtractSlotArrayIfNeeded(Js::ScriptContext* ctx, Field(Js::Var)* scope)
         {
             if(this->m_marks.IsMarked(scope))
             {
    @@ -177,7 +177,7 @@ namespace TTD
                         break;
                     case Js::ScopeType::ScopeType_SlotArray:
                     {
    -                    this->ExtractSlotArrayIfNeeded(ctx, (Js::Var*)scope);
    +                    this->ExtractSlotArrayIfNeeded(ctx, (Field(Js::Var)*)scope);
     
                         entryInfo->IDValue = TTD_CONVERT_SLOTARRAY_TO_PTR_ID((Js::Var*)scope);
                         break;
    @@ -322,7 +322,7 @@ namespace TTD
                     {
                         if(this->m_marks.MarkAndTestAddr<MarkTableTag::SlotArrayTag>(scope))
                         {
    -                        Js::ScopeSlots slotArray = (Js::Var*)scope;
    +                        Js::ScopeSlots slotArray = (Field(Js::Var)*)scope;
                             uint slotArrayCount = static_cast<uint>(slotArray.GetCount());
                             if(!slotArray.IsDebuggerScopeSlotArray())
                             {
    
  • lib/Runtime/Debug/TTSnapshotExtractor.h+1 1 modified
    @@ -39,7 +39,7 @@ namespace TTD
             void ExtractTypeIfNeeded(Js::Type* jstype, ThreadContext* threadContext);
     
             //Ensure that a slot/scope has been extracted
    -        void ExtractSlotArrayIfNeeded(Js::ScriptContext* ctx, Js::Var* scope);
    +        void ExtractSlotArrayIfNeeded(Js::ScriptContext* ctx, Field(Js::Var)* scope);
             void ExtractScopeIfNeeded(Js::ScriptContext* ctx, Js::FrameDisplay* environment);
             void ExtractScriptFunctionEnvironmentIfNeeded(Js::ScriptFunction* function);
     
    
  • lib/Runtime/Debug/TTSnapValues.cpp+4 4 modified
    @@ -556,12 +556,12 @@ namespace TTD
     
             //////////////////
     
    -        Js::Var* InflateSlotArrayInfo(const SlotArrayInfo* slotInfo, InflateMap* inflator)
    +        Field(Js::Var)* InflateSlotArrayInfo(const SlotArrayInfo* slotInfo, InflateMap* inflator)
             {
                 Js::ScriptContext* ctx = inflator->LookupScriptContext(slotInfo->ScriptContextLogId);
                 Field(Js::Var)* slotArray = RecyclerNewArray(ctx->GetRecycler(), Field(Js::Var), slotInfo->SlotCount + Js::ScopeSlots::FirstSlotIndex);
     
    -            Js::ScopeSlots scopeSlots((Js::Var*)slotArray);
    +            Js::ScopeSlots scopeSlots(slotArray);
                 scopeSlots.SetCount(slotInfo->SlotCount);
     
                 Js::Var undef = ctx->GetLibrary()->GetUndefined();
    @@ -625,7 +625,7 @@ namespace TTD
                     }
                 }
     
    -            return (Js::Var*)slotArray;
    +            return slotArray;
             }
     
             void EmitSlotArrayInfo(const SlotArrayInfo* slotInfo, FileWriter* writer, NSTokens::Separator separator)
    @@ -782,7 +782,7 @@ namespace TTD
                     }
                     case Js::ScopeType::ScopeType_SlotArray:
                     {
    -                    Js::Var* saval = inflator->LookupSlotArray(scp.IDValue);
    +                    Field(Js::Var)* saval = inflator->LookupSlotArray(scp.IDValue);
                         environment->SetItem(i, saval);
                         break;
                     }
    
  • lib/Runtime/Debug/TTSnapValues.h+1 1 modified
    @@ -153,7 +153,7 @@ namespace TTD
                 TTD_WELLKNOWN_TOKEN OptWellKnownDbgScope;
             };
     
    -        Js::Var* InflateSlotArrayInfo(const SlotArrayInfo* slotInfo, InflateMap* inflator);
    +        Field(Js::Var)* InflateSlotArrayInfo(const SlotArrayInfo* slotInfo, InflateMap* inflator);
     
             void EmitSlotArrayInfo(const SlotArrayInfo* slotInfo, FileWriter* writer, NSTokens::Separator separator);
             void ParseSlotArrayInfo(SlotArrayInfo* slotInfo, bool readSeparator, FileReader* reader, SlabAllocator& alloc);
    
  • lib/Runtime/Language/AsmJsModule.cpp+1 1 modified
    @@ -2501,7 +2501,7 @@ namespace Js
     #else
             Field(Var) * slotArray = RecyclerNewArray(scriptContext->GetRecycler(), Field(Var), moduleBody->scopeSlotArraySize + ScopeSlots::FirstSlotIndex);
     #endif
    -        ScopeSlots scopeSlots((Js::Var*)slotArray);
    +        ScopeSlots scopeSlots(slotArray);
             scopeSlots.SetCount(moduleBody->scopeSlotArraySize);
             scopeSlots.SetScopeMetadata(moduleBody->GetFunctionInfo());
     
    
  • lib/Runtime/Language/InterpreterStackFrame.cpp+4 3 modified
    @@ -1254,7 +1254,7 @@ namespace Js
                     {
                         uint32 scopeSlots = this->executeFunction->scopeSlotArraySize;
                         Assert(scopeSlots != 0);
    -                    ScopeSlots((Var*)nextAllocBytes).SetCount(0); // Start with count as 0. It will get set in NewScopeSlots
    +                    ScopeSlots((Field(Var)*)nextAllocBytes).SetCount(0); // Start with count as 0. It will get set in NewScopeSlots
                         newInstance->localClosure = nextAllocBytes;
                         nextAllocBytes += (scopeSlots + ScopeSlots::FirstSlotIndex) * sizeof(Var);
                     }
    @@ -2733,7 +2733,7 @@ namespace Js
     
                     scriptFuncObj->GetDynamicType()->SetEntryPoint(AsmJsExternalEntryPoint);
                     scriptFuncObj->GetFunctionBody()->GetAsmJsFunctionInfo()->SetModuleFunctionBody(asmJsModuleFunctionBody);
    -                scriptFuncObj->SetModuleEnvironment((Field(Var)*)moduleMemoryPtr);
    +                scriptFuncObj->SetModuleEnvironment(moduleMemoryPtr);
                     if (!info->IsRuntimeProcessed())
                     {
                         // don't reset entrypoint upon relinking
    @@ -3812,6 +3812,7 @@ namespace Js
     #endif
     
             if (playout->Return == Js::Constants::NoRegister)
    +        
             {
                 Arguments args(CallInfo(CallFlags_NotUsed, playout->ArgCount), m_outParams);
                 JavascriptFunction::CallFunction<true>(function, function->GetEntryPoint(), args);
    @@ -7406,7 +7407,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(uint loopId)
             slotArray = (Field(Var)*)this->GetLocalClosure();
             Assert(slotArray != nullptr);
     
    -        ScopeSlots scopeSlots((Js::Var*)slotArray);
    +        ScopeSlots scopeSlots(slotArray);
             scopeSlots.SetCount(scopeSlotCount);
             scopeSlots.SetScopeMetadata((Var)functionBody->GetFunctionInfo());
             Var undef = functionBody->GetScriptContext()->GetLibrary()->GetUndefined();
    
  • lib/Runtime/Language/JavascriptOperators.cpp+2 2 modified
    @@ -6975,7 +6975,7 @@ namespace Js
             Assert(size > ScopeSlots::FirstSlotIndex); // Should never see empty slot array
             Field(Var)* slotArray = RecyclerNewArray(scriptContext->GetRecycler(), Field(Var), size); // last initialized slot contains reference to array of propertyIds, correspondent to objects in previous slots
             uint count = size - ScopeSlots::FirstSlotIndex;
    -        ScopeSlots slots((Js::Var*)slotArray);
    +        ScopeSlots slots(slotArray);
             slots.SetCount(count);
             AssertMsg(!FunctionBody::Is(scope), "Scope should only be FunctionInfo or DebuggerScope, not FunctionBody");
             slots.SetScopeMetadata(scope);
    @@ -7002,7 +7002,7 @@ namespace Js
     
         Field(Var)* JavascriptOperators::OP_CloneScopeSlots(Field(Var) *slotArray, ScriptContext *scriptContext)
         {
    -        ScopeSlots slots((Js::Var*)slotArray);
    +        ScopeSlots slots(slotArray);
             uint size = ScopeSlots::FirstSlotIndex + static_cast<uint>(slots.GetCount());
     
             Field(Var)* slotArrayClone = RecyclerNewArray(scriptContext->GetRecycler(), Field(Var), size);
    
  • lib/Runtime/Library/BoundFunction.cpp+4 3 modified
    @@ -188,7 +188,7 @@ namespace Js
                     newValues[index++] = args[i];
                 }
     
    -            actualArgs = Arguments(args.Info, (Var*)newValues);
    +            actualArgs = Arguments(args.Info, unsafe_write_barrier_cast<Var*>(newValues));
                 actualArgs.Info.Count = boundFunction->count + argCount;
             }
             else
    @@ -522,13 +522,14 @@ namespace Js
             TTD::NSSnapObjects::StdExtractSetKindSpecificInfo<TTD::NSSnapObjects::SnapBoundFunctionInfo*, TTD::NSSnapObjects::SnapObjectType::SnapBoundFunctionObject>(objData, bfi, alloc, depCount, depArray);
         }
     
    -    BoundFunction* BoundFunction::InflateBoundFunction(ScriptContext* ctx, RecyclableObject* function, Var bThis, uint32 ct, Var* args)
    +    BoundFunction* BoundFunction::InflateBoundFunction(
    +        ScriptContext* ctx, RecyclableObject* function, Var bThis, uint32 ct, Field(Var)* args)
         {
             BoundFunction* res = RecyclerNew(ctx->GetRecycler(), BoundFunction, ctx->GetLibrary()->GetBoundFunctionType());
     
             res->boundThis = bThis;
             res->count = ct;
    -        res->boundArgs = (Field(Var)*)args;
    +        res->boundArgs = args;
     
             res->targetFunction = function;
     
    
  • lib/Runtime/Library/BoundFunction.h+2 1 modified
    @@ -63,7 +63,8 @@ namespace Js
             virtual TTD::NSSnapObjects::SnapObjectType GetSnapTag_TTD() const override;
             virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override;
     
    -        static BoundFunction* InflateBoundFunction(ScriptContext* ctx, RecyclableObject* function, Var bThis, uint32 ct, Var* args);
    +        static BoundFunction* InflateBoundFunction(
    +            ScriptContext* ctx, RecyclableObject* function, Var bThis, uint32 ct, Field(Var)* args);
     #endif
     
         private:
    
  • lib/Runtime/Library/ConcatString.cpp+3 1 modified
    @@ -130,8 +130,10 @@ namespace Js
     
             if (this->propertyRecord == nullptr)
             {
    +            Js::PropertyRecord const * propertyRecord = nullptr;
                 scriptContext->GetOrAddPropertyRecord(this->GetSz(), static_cast<int>(this->GetLength()),
    -                (Js::PropertyRecord const **)&(this->propertyRecord));
    +                &propertyRecord);
    +            this->propertyRecord = propertyRecord;
             }
     
             this->propertyString = scriptContext->GetPropertyString(propertyRecord->GetPropertyId());
    
  • lib/Runtime/Library/JavascriptArray.cpp+17 5 modified
    @@ -7016,7 +7016,8 @@ namespace Js
         }
     
         template<typename T>
    -    void JavascriptArray::ArraySegmentSpliceHelper(JavascriptArray *pnewArr, SparseArraySegment<T> *seg, SparseArraySegment<T> **prev,
    +    void JavascriptArray::ArraySegmentSpliceHelper(
    +        JavascriptArray *pnewArr, SparseArraySegment<T> *seg, Field(SparseArraySegment<T>*) *prev,
                                                         uint32 start, uint32 deleteLen, Var* insertArgs, uint32 insertLen, Recycler *recycler)
         {
             // book keeping variables
    @@ -7138,7 +7139,9 @@ namespace Js
                     // All splice happens in one segment.
                     SparseArraySegmentBase *nextSeg = startSeg->next;
                     // Splice the segment first, which might OOM throw but the array would be intact.
    -                JavascriptArray::ArraySegmentSpliceHelper(pnewArr, (SparseArraySegment<T>*)startSeg, (SparseArraySegment<T>**)prevSeg, start, deleteLen, insertArgs, insertLen, recycler);
    +                JavascriptArray::ArraySegmentSpliceHelper(
    +                    pnewArr, startSeg, SparseArraySegment<T>::AddressFrom(prevSeg),
    +                    start, deleteLen, insertArgs, insertLen, recycler);
                     while (nextSeg)
                     {
                         // adjust next segments left
    @@ -7476,15 +7479,24 @@ namespace Js
                     bool isInlineSegment = JavascriptArray::IsInlineSegment(oldHead, pArr);
                     if (isIntArray)
                     {
    -                    ArraySegmentSpliceHelper<int32>(newArr, SparseArraySegment<int32>::From(pArr->head), (SparseArraySegment<int32>**)&pArr->head, start, deleteLen, insertArgs, insertLen, recycler);
    +                    ArraySegmentSpliceHelper<int32>(newArr,
    +                        SparseArraySegment<int32>::From(pArr->head),
    +                        SparseArraySegment<int32>::AddressFrom(&pArr->head),
    +                        start, deleteLen, insertArgs, insertLen, recycler);
                     }
                     else if (isFloatArray)
                     {
    -                    ArraySegmentSpliceHelper<double>(newArr, SparseArraySegment<double>::From(pArr->head), (SparseArraySegment<double>**)&pArr->head, start, deleteLen, insertArgs, insertLen, recycler);
    +                    ArraySegmentSpliceHelper<double>(newArr,
    +                        SparseArraySegment<double>::From(pArr->head),
    +                        SparseArraySegment<double>::AddressFrom(&pArr->head),
    +                        start, deleteLen, insertArgs, insertLen, recycler);
                     }
                     else
                     {
    -                    ArraySegmentSpliceHelper<Var>(newArr, SparseArraySegment<Var>::From(pArr->head), (SparseArraySegment<Var>**)&pArr->head, start, deleteLen, insertArgs, insertLen, recycler);
    +                    ArraySegmentSpliceHelper<Var>(newArr,
    +                        SparseArraySegment<Var>::From(pArr->head),
    +                        SparseArraySegment<Var>::AddressFrom(&pArr->head),
    +                        start, deleteLen, insertArgs, insertLen, recycler);
                     }
     
                     if (isInlineSegment && oldHead != pArr->head)
    
  • lib/Runtime/Library/JavascriptArray.h+3 2 modified
    @@ -595,8 +595,9 @@ namespace Js
             static void ArraySpliceHelper(JavascriptArray* pNewArr, JavascriptArray* pArr, uint32 start, uint32 deleteLen,
                                                         Var* insertArgs, uint32 insertLen, ScriptContext *scriptContext);
             template<typename T>
    -        static void ArraySegmentSpliceHelper(JavascriptArray *pnewArr, SparseArraySegment<T> *seg, SparseArraySegment<T> **prev, uint32 start, uint32 deleteLen,
    -                                                    Var* insertArgs, uint32 insertLen, Recycler *recycler);
    +        static void ArraySegmentSpliceHelper(
    +            JavascriptArray *pnewArr, SparseArraySegment<T> *seg, Field(SparseArraySegment<T>*) *prev,
    +            uint32 start, uint32 deleteLen, Var* insertArgs, uint32 insertLen, Recycler *recycler);
             template<typename T>
             static RecyclableObject* ObjectSpliceHelper(RecyclableObject* pObj, T len, T start, T deleteLen,
                                                         Var* insertArgs, uint32 insertLen, ScriptContext *scriptContext, RecyclableObject* pNewObj = nullptr);
    
  • lib/Runtime/Library/JavascriptGeneratorFunction.cpp+2 2 modified
    @@ -137,7 +137,7 @@ namespace Js
             // and use that buffer for this InterpreterStackFrame.
             Field(Var)* argsHeapCopy = RecyclerNewArray(scriptContext->GetRecycler(), Field(Var), stackArgs.Info.Count);
             CopyArray(argsHeapCopy, stackArgs.Info.Count, stackArgs.Values, stackArgs.Info.Count);
    -        Arguments heapArgs(callInfo, (Var*)argsHeapCopy);
    +        Arguments heapArgs(callInfo, unsafe_write_barrier_cast<Var*>(argsHeapCopy));
     
             DynamicObject* prototype = scriptContext->GetLibrary()->CreateGeneratorConstructorPrototypeObject();
             JavascriptGenerator* generator = scriptContext->GetLibrary()->CreateGenerator(heapArgs, generatorFunction->scriptFunction, prototype);
    @@ -163,7 +163,7 @@ namespace Js
             // and use that buffer for this InterpreterStackFrame.
             Field(Var)* argsHeapCopy = RecyclerNewArray(scriptContext->GetRecycler(), Field(Var), stackArgs.Info.Count);
             CopyArray(argsHeapCopy, stackArgs.Info.Count, stackArgs.Values, stackArgs.Info.Count);
    -        Arguments heapArgs(callInfo, (Var*)argsHeapCopy);
    +        Arguments heapArgs(callInfo, unsafe_write_barrier_cast<Var*>(argsHeapCopy));
     
             JavascriptExceptionObject* e = nullptr;
             JavascriptPromiseResolveOrRejectFunction* resolve;
    
  • lib/Runtime/Library/JavascriptLibrary.cpp+2 1 modified
    @@ -5736,7 +5736,8 @@ namespace Js
             return function;
         }
     
    -    Js::RecyclableObject* JavascriptLibrary::CreateBoundFunction_TTD(RecyclableObject* function, Var bThis, uint32 ct, Var* args)
    +    Js::RecyclableObject* JavascriptLibrary::CreateBoundFunction_TTD(
    +        RecyclableObject* function, Var bThis, uint32 ct, Field(Var)* args)
         {
             return BoundFunction::InflateBoundFunction(this->scriptContext, function, bThis, ct, args);
         }
    
  • lib/Runtime/Library/JavascriptLibrary.h+2 1 modified
    @@ -733,7 +733,8 @@ namespace Js
             static void AddWeakMapElementInflate_TTD(Js::JavascriptWeakMap* map, Var key, Var value);
     
             Js::RecyclableObject* CreateExternalFunction_TTD(Js::Var fname);
    -        Js::RecyclableObject* CreateBoundFunction_TTD(RecyclableObject* function, Var bThis, uint32 ct, Var* args);
    +        Js::RecyclableObject* CreateBoundFunction_TTD(
    +                RecyclableObject* function, Var bThis, uint32 ct, Field(Var)* args);
     
             Js::RecyclableObject* CreateProxy_TTD(RecyclableObject* handler, RecyclableObject* target);
             Js::RecyclableObject* CreateRevokeFunction_TTD(RecyclableObject* proxy);
    
  • lib/Runtime/Library/RegexHelper.cpp+4 4 modified
    @@ -915,7 +915,7 @@ namespace Js
                 ArenaAllocator* tempAlloc,
                 JavascriptString* matchStr,
                 int numberOfCaptures,
    -            Var* captures,
    +            Field(Var)* captures,
                 CharCount position)
             {
                 CharCount* substitutionOffsets = nullptr;
    @@ -925,7 +925,7 @@ namespace Js
                     tempAlloc,
                     &substitutionOffsets);
                 auto getGroup = [&](int captureIndex, Var nonMatchValue) {
    -                return captureIndex <= numberOfCaptures ? captures[captureIndex] : nonMatchValue;
    +                return captureIndex <= numberOfCaptures ? PointerValue(captures[captureIndex]) : nonMatchValue;
                 };
                 UnifiedRegex::GroupInfo match(position, matchStr->GetLength());
                 int numGroups = numberOfCaptures + 1; // Take group 0 into account.
    @@ -951,7 +951,7 @@ namespace Js
                 ArenaAllocator* tempAlloc,
                 JavascriptString* matchStr,
                 int numberOfCaptures,
    -            Var* captures,
    +            Field(Var)* captures,
                 CharCount position)
             {
                 // replaceFn Arguments:
    @@ -1088,7 +1088,7 @@ namespace Js
                         CharCount substringLength = position - nextSourcePosition;
                         accumulatedResultBuilder.Append(input, nextSourcePosition, substringLength);
     
    -                    appendReplacement(accumulatedResultBuilder, tempAlloc, matchStr, (int) numberOfCapturesToKeep, (Var*)captures, position);
    +                    appendReplacement(accumulatedResultBuilder, tempAlloc, matchStr, (int) numberOfCapturesToKeep, captures, position);
     
                         nextSourcePosition = JavascriptRegExp::AddIndex(position, matchStr->GetLength());
                     }
    
  • lib/Runtime/Library/ScriptFunction.cpp+6 4 modified
    @@ -490,7 +490,7 @@ namespace Js
                 BufferStringBuilder builder(cch, scriptContext);
                 utf8::DecodeOptions options = pFuncBody->GetUtf8SourceInfo()->IsCesu8() ? utf8::doAllowThreeByteSurrogates : utf8::doDefault;
                 size_t decodedCount = utf8::DecodeUnitsInto(builder.DangerousGetWritableBuffer(), pbStart, pbStart + cbLength, options);
    -            
    +
                 if (decodedCount != cch)
                 {
                     AssertMsg(false, "Decoded incorrect number of characters for function body");
    @@ -574,7 +574,7 @@ namespace Js
                 }
                 case Js::ScopeType::ScopeType_SlotArray:
                 {
    -                Js::ScopeSlots slotArray = (Js::Var*)scope;
    +                Js::ScopeSlots slotArray = (Field(Js::Var)*)scope;
                     uint slotArrayCount = static_cast<uint>(slotArray.GetCount());
     
                     //get the function body associated with the scope
    @@ -707,7 +707,8 @@ namespace Js
         JavascriptArrayBuffer* AsmJsScriptFunction::GetAsmJsArrayBuffer() const
         {
     #ifdef ASMJS_PLAT
    -        return *(JavascriptArrayBuffer**)(this->GetModuleEnvironment() + AsmJsModuleMemory::MemoryTableBeginOffset);
    +        return (JavascriptArrayBuffer*)PointerValue(
    +            *(this->GetModuleEnvironment() + AsmJsModuleMemory::MemoryTableBeginOffset));
     #else
             Assert(UNREACHED);
             return nullptr;
    @@ -742,7 +743,8 @@ namespace Js
     
         WebAssemblyMemory* WasmScriptFunction::GetWebAssemblyMemory() const
         {
    -        return *(WebAssemblyMemory**)(this->GetModuleEnvironment() + AsmJsModuleMemory::MemoryTableBeginOffset);
    +        return (WebAssemblyMemory*)PointerValue(
    +            *(this->GetModuleEnvironment() + AsmJsModuleMemory::MemoryTableBeginOffset));
         }
     #endif
     
    
  • lib/Runtime/Library/SparseArraySegment.h+5 0 modified
    @@ -104,6 +104,11 @@ namespace Js
                 return static_cast<SparseArraySegment*>(seg);
             }
     
    +        static inline Field(SparseArraySegment*)* AddressFrom(Field(SparseArraySegmentBase*) *addr)
    +        {
    +            return reinterpret_cast<Field(SparseArraySegment*)*>(addr);
    +        }
    +
         private:
             template<bool isLeaf>
             static SparseArraySegment<T>* Allocate(Recycler* recycler, uint32 left, uint32 length, uint32 size, uint32 fillStart = 0);
    
  • lib/Runtime/Library/StackScriptFunction.cpp+17 15 modified
    @@ -229,12 +229,12 @@ namespace Js
                         }
                         if (callerFunctionBody->DoStackScopeSlots() && interpreterFrame->IsClosureInitDone())
                         {
    -                        Var* stackScopeSlots = (Var*)interpreterFrame->GetLocalClosure();
    +                        Field(Var)* stackScopeSlots = (Field(Var)*)interpreterFrame->GetLocalClosure();
                             if (stackScopeSlots)
                             {
                                 // Scope slot pointer may be null if bailout didn't restore it, which means we don't need it.
    -                            Var* boxedScopeSlots = this->BoxScopeSlots(stackScopeSlots, static_cast<uint>(ScopeSlots(stackScopeSlots).GetCount()));
    -                            interpreterFrame->SetLocalClosure((Var)boxedScopeSlots);
    +                            Field(Var)* boxedScopeSlots = this->BoxScopeSlots(stackScopeSlots, static_cast<uint>(ScopeSlots(stackScopeSlots).GetCount()));
    +                            interpreterFrame->SetLocalClosure(boxedScopeSlots);
                             }
                         }
     
    @@ -304,7 +304,7 @@ namespace Js
                             }
                             if (callerFunctionBody->DoStackScopeSlots())
                             {
    -                            Var* stackScopeSlots = this->GetScopeSlotsFromNativeFrame(walker, callerFunctionBody);
    +                            Field(Var)* stackScopeSlots = (Field(Var)*)this->GetScopeSlotsFromNativeFrame(walker, callerFunctionBody);
                                 if (stackScopeSlots)
                                 {
                                     // Scope slot pointer may be null if bailout didn't restore it, which means we don't need it.
    @@ -356,7 +356,7 @@ namespace Js
                         int i;
                         for (i = 0; i < frameDisplay->GetLength(); i++)
                         {
    -                        Var *slotArray = (Var*)frameDisplay->GetItem(i);
    +                        Field(Var) *slotArray = (Field(Var)*)frameDisplay->GetItem(i);
     
                             if (ScopeSlots::Is(slotArray))
                             {
    @@ -373,10 +373,10 @@ namespace Js
                         }
                         for (; i < frameDisplay->GetLength(); i++)
                         {
    -                        Var *pScope = (Var*)frameDisplay->GetItem(i);
    +                        Field(Var) *pScope = (Field(Var)*)frameDisplay->GetItem(i);
                             if (ScopeSlots::Is(pScope))
                             {
    -                            Var *boxedSlots = this->BoxScopeSlots(pScope, static_cast<uint>(ScopeSlots(pScope).GetCount()));
    +                            Field(Var) *boxedSlots = this->BoxScopeSlots(pScope, static_cast<uint>(ScopeSlots(pScope).GetCount()));
                                 frameDisplay->SetItem(i, boxedSlots);
                             }
                         }
    @@ -652,7 +652,7 @@ namespace Js
             for (uint16 i = 0; i < length; i++)
             {
                 // TODO: Once we allocate the slots on the stack, we can only look those slots
    -            Var * pScope = (Var *)frameDisplay->GetItem(i);
    +            Field(Var) * pScope = (Field(Var) *)frameDisplay->GetItem(i);
                 // We don't do stack slots if we exceed max encoded slot count
                 if (ScopeSlots::Is(pScope))
                 {
    @@ -664,19 +664,21 @@ namespace Js
             return boxedFrameDisplay;
         }
     
    -    Var * StackScriptFunction::BoxState::BoxScopeSlots(Var * slotArray, uint count)
    +    Field(Var) * StackScriptFunction::BoxState::BoxScopeSlots(Field(Var) * slotArray, uint count)
         {
             Assert(slotArray != nullptr);
             Assert(count != 0);
    -        Field(Var) * boxedSlotArray = nullptr;
    -        if (boxedValues.TryGetValue(slotArray, (void **)&boxedSlotArray))
    +
    +        void * tmp = nullptr;
    +        if (boxedValues.TryGetValue(slotArray, &tmp))
             {
    -            return (Var*)boxedSlotArray;
    +            return (Field(Var) *)tmp;
             }
     
    +        Field(Var) * boxedSlotArray = nullptr;
             if (!ThreadContext::IsOnStack(slotArray))
             {
    -            boxedSlotArray = (Field(Var)*)slotArray;
    +            boxedSlotArray = slotArray;
             }
             else
             {
    @@ -686,7 +688,7 @@ namespace Js
             boxedValues.Add(slotArray, boxedSlotArray);
     
             ScopeSlots scopeSlots(slotArray);
    -        ScopeSlots boxedScopeSlots((Js::Var*)boxedSlotArray);
    +        ScopeSlots boxedScopeSlots(boxedSlotArray);
     
             boxedScopeSlots.SetCount(count);
             boxedScopeSlots.SetScopeMetadata(scopeSlots.GetScopeMetadataRaw());
    @@ -702,7 +704,7 @@ namespace Js
                 }
                 boxedScopeSlots.Set(i, slotValue);
             }
    -        return (Var*)boxedSlotArray;
    +        return boxedSlotArray;
         }
     
         ScriptFunction * StackScriptFunction::BoxState::BoxStackFunction(ScriptFunction * scriptFunction)
    
  • lib/Runtime/Library/StackScriptFunction.h+1 1 modified
    @@ -56,7 +56,7 @@ namespace Js
                 ScriptContext * scriptContext;
                 void * returnAddress;
     
    -            Var * BoxScopeSlots(Var * scopeSlots, uint count);
    +            Field(Var) * BoxScopeSlots(Field(Var) * scopeSlots, uint count);
                 bool NeedBoxFrame(FunctionBody * functionBody);
                 bool NeedBoxScriptFunction(ScriptFunction * scriptFunction);
                 ScriptFunction * BoxStackFunction(ScriptFunction * scriptFunction);
    
  • lib/Runtime/Library/WebAssemblyEnvironment.cpp+1 1 modified
    @@ -82,7 +82,7 @@ void WebAssemblyEnvironment::SetVarElement(Field(Var)* ptr, T* val, uint32 index
     
         Field(Var)* dst = ptr + index;
         CheckPtrIsValid<Var>((intptr_t)dst);
    -    AssertMsg(*(T**)dst == nullptr, "We shouldn't overwrite anything on the environment once it is set");
    +    AssertMsg(*dst == nullptr, "We shouldn't overwrite anything on the environment once it is set");
         *dst = val;
     }
     
    
  • lib/Runtime/Library/WebAssemblyEnvironment.h+1 1 modified
    @@ -20,7 +20,7 @@ namespace Js
         public:
             WebAssemblyEnvironment(WebAssemblyModule* module);
     
    -        Var* GetStartPtr() const { return (Var*)PointerValue(start); }
    +        Field(Var)* GetStartPtr() const { return start; }
     
             WasmScriptFunction* GetWasmFunction(uint32 index) const;
             void SetWasmFunction(uint32 index, WasmScriptFunction* func);
    
  • lib/Runtime/Library/WebAssemblyInstance.cpp+2 2 modified
    @@ -183,7 +183,7 @@ void WebAssemblyInstance::CreateWasmFunctions(WebAssemblyModule * wasmModule, Sc
             Wasm::WasmFunctionInfo* wasmFuncInfo = wasmModule->GetWasmFunctionInfo(i);
             FunctionBody* body = wasmFuncInfo->GetBody();
             WasmScriptFunction* funcObj = ctx->GetLibrary()->CreateWasmScriptFunction(body);
    -        funcObj->SetModuleEnvironment((Field(Var)*)env->GetStartPtr());
    +        funcObj->SetModuleEnvironment(env->GetStartPtr());
             funcObj->SetSignature(body->GetAsmJsFunctionInfo()->GetWasmSignature());
             funcObj->SetEnvironment(frameDisplay);
     
    @@ -440,7 +440,7 @@ void WebAssemblyInstance::InitialGlobals(WebAssemblyModule * wasmModule, ScriptC
                 {
                     JavascriptError::ThrowTypeError(ctx, WASMERR_InvalidGlobalRef);
                 }
    -            
    +
                 if (sourceGlobal->GetType() != global->GetType())
                 {
                     JavascriptError::ThrowTypeError(ctx, WASMERR_InvalidTypeConversion);
    
  • lib/Runtime/Library/WebAssemblyTable.cpp+4 3 modified
    @@ -11,9 +11,10 @@
     namespace Js
     {
     
    -WebAssemblyTable::WebAssemblyTable(Var * values, uint32 currentLength, uint32 initialLength, uint32 maxLength, DynamicType * type) :
    +WebAssemblyTable::WebAssemblyTable(
    +        Field(Var) * values, uint32 currentLength, uint32 initialLength, uint32 maxLength, DynamicType * type) :
         DynamicObject(type),
    -    m_values((Field(Var)*)values),
    +    m_values(values),
         m_currentLength(currentLength),
         m_initialLength(initialLength),
         m_maxLength(maxLength)
    @@ -229,7 +230,7 @@ WebAssemblyTable::Create(uint32 initial, uint32 maximum, ScriptContext * scriptC
         {
             values = RecyclerNewArrayZ(scriptContext->GetRecycler(), Field(Var), initial);
         }
    -    return RecyclerNew(scriptContext->GetRecycler(), WebAssemblyTable, (Var*)values, initial, initial, maximum, scriptContext->GetLibrary()->GetWebAssemblyTableType());
    +    return RecyclerNew(scriptContext->GetRecycler(), WebAssemblyTable, values, initial, initial, maximum, scriptContext->GetLibrary()->GetWebAssemblyTableType());
     }
     
     void
    
  • lib/Runtime/Library/WebAssemblyTable.h+2 1 modified
    @@ -23,7 +23,8 @@ namespace Js
                 static FunctionInfo Get;
                 static FunctionInfo Set;
             };
    -        WebAssemblyTable(Var * values, uint32 currentLength, uint32 initialLength, uint32 maxLength, DynamicType * type);
    +        WebAssemblyTable(
    +            Field(Var) * values, uint32 currentLength, uint32 initialLength, uint32 maxLength, DynamicType * type);
             static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
             static Var EntryGetterLength(RecyclableObject* function, CallInfo callInfo, ...);
             static Var EntryGrow(RecyclableObject* function, CallInfo callInfo, ...);
    
  • lib/Runtime/Types/DynamicObjectPropertyEnumerator.cpp+1 1 modified
    @@ -117,7 +117,7 @@ namespace Js
             data->cachedCount = 0;
             data->propertyCount = propertyCount;
             data->strings = reinterpret_cast<Field(PropertyString*)*>(data + 1);
    -        data->indexes = (BigPropertyIndex *)(data->strings + propertyCount);
    +        data->indexes = unsafe_write_barrier_cast<BigPropertyIndex *>(data->strings + propertyCount);
             data->attributes = (PropertyAttributes*)(data->indexes + propertyCount);
             data->completed = false;
             data->enumNonEnumerable = GetEnumNonEnumerable();
    
  • tools/RecyclerChecker/RecyclerChecker.cpp+89 23 modified
    @@ -7,20 +7,47 @@
     MainVisitor::MainVisitor(
             CompilerInstance& compilerInstance, ASTContext& context, bool fix)
         : _compilerInstance(compilerInstance), _context(context),
    -     _fix(fix), _fixed(false), _barrierTypeDefined(false)
    +     _fix(fix), _fixed(false), _diagEngine(context.getDiagnostics()),
    +     _barrierTypeDefined(false)
     {
         if (_fix)
         {
             _rewriter.setSourceMgr(compilerInstance.getSourceManager(),
                                    compilerInstance.getLangOpts());
         }
    +
    +#define SWB_WIKI \
    +    "https://github.com/microsoft/ChakraCore/wiki/Software-Write-Barrier#coding-rules"
    +
    +    _diagUnbarrieredField = _diagEngine.getCustomDiagID(
    +        DiagnosticsEngine::Error,
    +        "Unbarriered field, see " SWB_WIKI);
    +   _diagIllegalBarrierCast = _diagEngine.getCustomDiagID(
    +        DiagnosticsEngine::Error,
    +        "Illegal casting away of write barrier, see " SWB_WIKI);
    +#undef SWB_WIKI
    +}
    +
    +void MainVisitor::ReportUnbarriedField(SourceLocation location)
    +{
    +    DiagReport(location, _diagUnbarrieredField);
    +}
    +
    +void MainVisitor::ReportIllegalBarrierCast(SourceLocation location)
    +{
    +    DiagReport(location, _diagIllegalBarrierCast);
    +}
    +
    +void MainVisitor::DiagReport(SourceLocation location, unsigned diagId)
    +{
    +    _diagEngine.Report(location, diagId);
     }
     
     bool MainVisitor::VisitCXXRecordDecl(CXXRecordDecl* recordDecl)
     {
    -    if (Log::GetLevel() < Log::LogLevel::Info)
    +    if (Log::GetLevel() < Log::LogLevel::Verbose)
         {
    -        return true; // At least Info level, otherwise this not needed
    +        return true; // At least Verbose level, otherwise this not needed
         }
     
         std::string typeName = recordDecl->getQualifiedNameAsString();
    @@ -99,11 +126,6 @@ void MainVisitor::ProcessUnbarrieredFields(
         }
     
         const auto& sourceMgr = _compilerInstance.getSourceManager();
    -    DiagnosticsEngine& diagEngine = _context.getDiagnostics();
    -    const unsigned diagID = diagEngine.getCustomDiagID(
    -        DiagnosticsEngine::Error,
    -        "Unbarriered field, see "
    -        "https://github.com/microsoft/ChakraCore/wiki/Software-Write-Barrier#coding-rules");
     
         for (auto field : recordDecl->fields())
         {
    @@ -141,7 +163,7 @@ void MainVisitor::ProcessUnbarrieredFields(
                 {
                     if (pushFieldType(originalType))
                     {
    -                    Log::outs() << "Queue field type: " << originalTypeName
    +                    Log::verbose() << "Queue field type: " << originalTypeName
                             << " (" << typeName << "::" << fieldName << ")\n";
                     }
                 }
    @@ -168,7 +190,7 @@ void MainVisitor::ProcessUnbarrieredFields(
                                 << fieldName << "\n";
                 }
     
    -            diagEngine.Report(location, diagID);
    +            ReportUnbarriedField(location);
             }
         }
     }
    @@ -351,14 +373,14 @@ void MainVisitor::RecordRecyclerAllocation(const string& allocationFunction, con
     template <class Set, class DumpItemFunc>
     void MainVisitor::dump(const char* name, const Set& set, const DumpItemFunc& func)
     {
    -    Log::outs() << "-------------------------\n\n";
    -    Log::outs() << name << "\n";
    -    Log::outs() << "-------------------------\n\n";
    +    Log::verbose() << "-------------------------\n\n";
    +    Log::verbose() << name << "\n";
    +    Log::verbose() << "-------------------------\n\n";
         for (auto item : set)
         {
    -        func(Log::outs(), item);
    +        func(Log::verbose(), item);
         }
    -    Log::outs() << "-------------------------\n\n";
    +    Log::verbose() << "-------------------------\n\n";
     }
     
     template <class Item>
    @@ -384,7 +406,7 @@ void MainVisitor::Inspect()
         Dump(pointerClasses);
         Dump(barrieredClasses);
     
    -    Log::outs() << "Recycler allocations\n";
    +    Log::verbose() << "Recycler allocations\n";
         for (auto item : _allocatorTypeMap)
         {
             dump(item.first.c_str(), item.second);
    @@ -428,7 +450,7 @@ void MainVisitor::Inspect()
                 {
                     if (pushBarrierType(base.getType().getTypePtr()))
                     {
    -                    Log::outs() << "Queue base type: " << base.getType().getAsString()
    +                    Log::verbose() << "Queue base type: " << base.getType().getAsString()
                             << " (base of " << typeName << ")\n";
                     }
                 }
    @@ -521,8 +543,8 @@ void CheckAllocationsInFunctionVisitor::VisitAllocate(
     
             if (allocationType & AllocationTypes::WriteBarrier)
             {
    -            Log::outs() << "In \"" << _functionDecl->getQualifiedNameAsString() << "\"\n";
    -            Log::outs() << "  Allocating \"" << allocatedTypeStr << "\" in write barriered memory\n";
    +            Log::verbose() << "In \"" << _functionDecl->getQualifiedNameAsString() << "\"\n";
    +            Log::verbose() << "  Allocating \"" << allocatedTypeStr << "\" in write barriered memory\n";
             }
     
             _mainVisitor->RecordAllocation(allocatedType, allocationType);
    @@ -565,6 +587,45 @@ bool CheckAllocationsInFunctionVisitor::VisitCallExpr(CallExpr* callExpr)
         return true;
     }
     
    +// Check if type is a "Field() *" pointer type, or alternatively a pointer to
    +// any type in "alt" if provided.
    +bool CheckAllocationsInFunctionVisitor::IsFieldPointer(
    +    const QualType& qtype, const char* alt)
    +{
    +    if (qtype->isPointerType())
    +    {
    +        auto name = qtype->getPointeeType()
    +            .getDesugaredType(_mainVisitor->getContext()).getAsString();
    +        return StartsWith(name, "class Memory::WriteBarrierPtr<")
    +            || StartsWith(name, "typename WriteBarrierFieldTypeTraits<")
    +            || (alt && strstr(alt, name.c_str()));
    +    }
    +
    +    return false;
    +}
    +
    +bool CheckAllocationsInFunctionVisitor::CommonVisitCastExpr(CastExpr *cast)
    +{
    +    if (IsFieldPointer(cast->getSubExpr()->getType()) &&  // from Field() *
    +        cast->getType()->isPointerType() &&     // to a pointer type
    +        !IsFieldPointer(cast->getType(),        // not another Field() *
    +            "int|float|double|unsigned char"))  // not int/float/double/byte *
    +    {
    +        _mainVisitor->ReportIllegalBarrierCast(cast->getLocStart());
    +
    +        if (Log::GetLevel() >= Log::LogLevel::Info)
    +        {
    +            cast->dumpColor();
    +            cast->getSubExpr()->getType()->getPointeeType()
    +                .getDesugaredType(_mainVisitor->getContext()).dump("CAST_FROM");
    +            cast->getType()->getPointeeType()
    +                .getDesugaredType(_mainVisitor->getContext()).dump("CAST_TO");
    +        }
    +    }
    +
    +    return true;
    +}
    +
     void RecyclerCheckerConsumer::HandleTranslationUnit(ASTContext& context)
     {
         MainVisitor mainVisitor(_compilerInstance, context, _fix);
    @@ -585,20 +646,25 @@ bool RecyclerCheckerAction::ParseArgs(
     {
         for (auto i = args.begin(); i != args.end(); i++)
         {
    -        if (*i == "-verbose")
    +        if (*i == "-fix")
             {
    -            Log::SetLevel(Log::LogLevel::Verbose);
    +            this->_fix = true;
             }
    -        else if (*i == "-fix")
    +        else if (*i == "-info")
             {
    -            this->_fix = true;
    +            Log::SetLevel(Log::LogLevel::Info);
    +        }
    +        else if (*i == "-verbose")
    +        {
    +            Log::SetLevel(Log::LogLevel::Verbose);
             }
             else
             {
                 Log::errs()
                     << "ERROR: Unrecognized check-recycler option: " << *i << "\n"
                     << "Supported options:\n"
                     << "  -fix          Fix missing write barrier annotations"
    +                << "  -info         Log info messages\n"
                     << "  -verbose      Log verbose messages\n";
                 return false;
             }
    
  • tools/RecyclerChecker/RecyclerChecker.h+25 0 modified
    @@ -40,6 +40,11 @@ class MainVisitor:
         bool _fix;      // whether user requested to fix missing annotations
         bool _fixed;    // whether this plugin committed any annotation fixes
     
    +    // For emitting checker errors
    +    DiagnosticsEngine& _diagEngine;
    +    unsigned _diagUnbarrieredField;
    +    unsigned _diagIllegalBarrierCast;
    +
         bool _barrierTypeDefined;
         map<string, set<string>> _allocatorTypeMap;
         set<string> _pointerClasses;
    @@ -51,6 +56,7 @@ class MainVisitor:
         MainVisitor(CompilerInstance& compilerInstance, ASTContext& context, bool fix);
     
         const ASTContext& getContext() const { return _context; }
    +    const CompilerInstance& getCompilerInstance() const { return _compilerInstance; }
     
         bool VisitCXXRecordDecl(CXXRecordDecl* recordDecl);
         bool VisitFunctionDecl(FunctionDecl* functionDecl);
    @@ -61,6 +67,9 @@ class MainVisitor:
         void Inspect();
         bool ApplyFix();
     
    +    void ReportUnbarriedField(SourceLocation location);
    +    void ReportIllegalBarrierCast(SourceLocation location);
    +
     private:
         template <class Set, class DumpItemFunc>
         void dump(const char* name, const Set& set, const DumpItemFunc& func);
    @@ -73,6 +82,8 @@ class MainVisitor:
     
         bool MatchType(const string& type, const char* source, const char** pSourceEnd);
         const char* GetFieldTypeAnnotation(QualType qtype);
    +
    +    void DiagReport(SourceLocation location, unsigned diagId);
     };
     
     class CheckAllocationsInFunctionVisitor:
    @@ -87,12 +98,26 @@ class CheckAllocationsInFunctionVisitor:
         bool VisitCXXNewExpr(CXXNewExpr* newExpression);
         bool VisitCallExpr(CallExpr* callExpr);
     
    +#define IMPLEMENT_VISIT_CAST(Expr) \
    +    bool Visit##Expr(Expr *cast) { return CommonVisitCastExpr(cast); }
    +
    +    IMPLEMENT_VISIT_CAST(CStyleCastExpr)
    +    IMPLEMENT_VISIT_CAST(CXXFunctionalCastExpr)
    +    IMPLEMENT_VISIT_CAST(CXXConstCastExpr)
    +    IMPLEMENT_VISIT_CAST(CXXDynamicCastExpr)
    +    IMPLEMENT_VISIT_CAST(CXXReinterpretCastExpr)
    +    IMPLEMENT_VISIT_CAST(CXXStaticCastExpr)
    +#undef IMPLEMENT_VISIT_CAST
    +
     private:
         MainVisitor* _mainVisitor;
         FunctionDecl* _functionDecl;
     
         template <class A0, class A1, class T>
         void VisitAllocate(const A0& getArg0, const A1& getArg1, const T& getAllocType);
    +
    +    bool IsFieldPointer(const QualType& qtype, const char* alt = nullptr);
    +    bool CommonVisitCastExpr(CastExpr *cast);
     };
     
     class RecyclerCheckerConsumer: public ASTConsumer
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.