Skip to content
This repository has been archived by the owner on Oct 15, 2020. It is now read-only.

Commit

Permalink
deps: update ChakraCore to chakra-core/ChakraCore@2f088a6b07
Browse files Browse the repository at this point in the history
[MERGE #5449 @atulkatti] MSFT:18139538 Remove the use of Guest Arena from parser code to avoid ScriptContext leak.

Merge pull request #5449 from atulkatti:Bug18139538.RemoveGuestArenaUsage.1

MSFT:18171347 Parser's Temporary Guest Arena leaks in case of modules with Regex patterns.

Reviewed-By: chakrabot <[email protected]>
  • Loading branch information
Atul Katti authored and kfarnung committed Jul 18, 2018
1 parent 5a5a284 commit 2a19f01
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 42 deletions.
2 changes: 1 addition & 1 deletion deps/chakrashim/core/lib/Common/Memory/RecyclerRootPtr.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class AutoRecyclerRootPtr : public RecyclerRootPtr<T>
}
void Unroot()
{
if (ptr != nullptr)
if (this->ptr != nullptr)
{
__super::Unroot(recycler);
}
Expand Down
30 changes: 22 additions & 8 deletions deps/chakrashim/core/lib/Parser/Parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,10 @@ Parser::Parser(Js::ScriptContext* scriptContext, BOOL strictMode, PageAllocator
m_doingFastScan(false),
#endif
m_nextBlockId(0),
m_tempGuestArenaReleased(false),
m_tempGuestArena(scriptContext->GetTemporaryGuestAllocator(_u("ParserRegex")), scriptContext->GetRecycler()),
// use the GuestArena directly for keeping the RegexPattern* alive during byte code generation
m_registeredRegexPatterns(scriptContext->GetGuestArena()),
m_registeredRegexPatterns(m_tempGuestArena->GetAllocator()),

m_scriptContext(scriptContext),
m_token(), // should initialize to 0/nullptrs
Expand Down Expand Up @@ -154,12 +156,7 @@ Parser::Parser(Js::ScriptContext* scriptContext, BOOL strictMode, PageAllocator

Parser::~Parser(void)
{
if (m_scriptContext == nullptr || m_scriptContext->GetGuestArena() == nullptr)
{
// If the scriptContext or guestArena have gone away, there is no point clearing each item of this list.
// Just reset it so that destructor of the SList will be no-op
m_registeredRegexPatterns.Reset();
}
this->ReleaseTemporaryGuestArena();

#if ENABLE_BACKGROUND_PARSING
if (this->m_hasParallelJob)
Expand Down Expand Up @@ -1925,7 +1922,7 @@ void Parser::RegisterRegexPattern(UnifiedRegex::RegexPattern *const regexPattern
Assert(regexPattern);

// ensure a no-throw add behavior here, to catch out of memory exceptions, using the guest arena allocator
if (!m_registeredRegexPatterns.PrependNoThrow(m_scriptContext->GetGuestArena(), regexPattern))
if (!m_registeredRegexPatterns.PrependNoThrow(m_tempGuestArena->GetAllocator(), regexPattern))
{
Parser::Error(ERRnoMemory);
}
Expand Down Expand Up @@ -13909,6 +13906,23 @@ void Parser::ProcessCapturedNames(ParseNodeFnc* pnodeFnc)
}
}

void Parser::ReleaseTemporaryGuestArena()
{
// In case of modules the Parser lives longer than the temporary Guest Arena. We may have already released the arena explicitly.
if (!m_tempGuestArenaReleased)
{
// The regex patterns list has references to the temporary Guest Arena. Reset it first.
m_registeredRegexPatterns.Reset();

if (this->m_scriptContext != nullptr)
{
this->m_scriptContext->ReleaseTemporaryGuestAllocator(m_tempGuestArena);
}

m_tempGuestArenaReleased = true;
}
}

bool Parser::IsCreatingStateCache()
{
return (((this->m_grfscr & fscrCreateParserState) == fscrCreateParserState)
Expand Down
9 changes: 6 additions & 3 deletions deps/chakrashim/core/lib/Parser/Parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ namespace Js
{
class ParseableFunctionInfo;
class FunctionBody;
template <bool isGuestArena>
class TempArenaAllocatorWrapper;
};

class Parser
Expand All @@ -192,7 +194,7 @@ class Parser
~Parser(void);

Js::ScriptContext* GetScriptContext() const { return m_scriptContext; }

void ReleaseTemporaryGuestArena();
bool IsCreatingStateCache();

#if ENABLE_BACKGROUND_PARSING
Expand Down Expand Up @@ -271,10 +273,12 @@ class Parser
bool m_isInBackground;
bool m_doingFastScan;
#endif
bool m_tempGuestArenaReleased;
int m_nextBlockId;

AutoRecyclerRootPtr<Js::TempArenaAllocatorWrapper<true>> m_tempGuestArena;
// RegexPattern objects created for literal regexes are recycler-allocated and need to be kept alive until the function body
// is created during byte code generation. The RegexPattern pointer is stored in the script context's guest
// is created during byte code generation. The RegexPattern pointer is stored in a temporary guest
// arena for that purpose. This list is then unregistered from the guest arena at the end of parsing/scanning.
SList<UnifiedRegex::RegexPattern *, ArenaAllocator> m_registeredRegexPatterns;

Expand Down Expand Up @@ -1150,5 +1154,4 @@ class Parser
public:
charcount_t GetSourceIchLim() { return m_sourceLim; }
static BOOL NodeEqualsName(ParseNodePtr pnode, LPCOLESTR sz, uint32 cch);

};
22 changes: 0 additions & 22 deletions deps/chakrashim/core/lib/Runtime/Base/ScriptContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ namespace Js
integerStringMapCacheMissCount(0),
integerStringMapCacheUseCount(0),
#endif
guestArena(nullptr),
#ifdef ENABLE_SCRIPT_DEBUGGING
diagnosticArena(nullptr),
raiseMessageToDebuggerFunctionType(nullptr),
Expand Down Expand Up @@ -798,12 +797,6 @@ namespace Js
interpreterArena = nullptr;
}

if (this->guestArena)
{
ReleaseGuestArena();
guestArena = nullptr;
}

builtInLibraryFunctions = nullptr;

pActiveScriptDirect = nullptr;
Expand Down Expand Up @@ -1304,8 +1297,6 @@ namespace Js

void ScriptContext::InitializePreGlobal()
{
this->guestArena = this->GetRecycler()->CreateGuestArena(_u("Guest"), Throw::OutOfMemory);

#if ENABLE_BACKGROUND_PARSING
if (PHASE_ON1(Js::ParallelParsePhase))
{
Expand Down Expand Up @@ -2680,17 +2671,6 @@ namespace Js
}
}


void ScriptContext::ReleaseGuestArena()
{
AssertMsg(this->guestArena, "No guest arena to release");
if (this->guestArena)
{
this->GetRecycler()->DeleteGuestArena(this->guestArena);
this->guestArena = nullptr;
}
}

void ScriptContext::SetScriptStartEventHandler(ScriptContext::EventHandler eventHandler)
{
AssertMsg(this->scriptStartEventHandler == nullptr, "Do not support multi-cast yet");
Expand Down Expand Up @@ -4895,7 +4875,6 @@ namespace Js
void ScriptContext::BindReference(void * addr)
{
Assert(!this->isClosed);
Assert(this->guestArena);
Assert(recycler->IsValidObject(addr));
#if DBG
Assert(!bindRef.ContainsKey(addr)); // Make sure we don't bind the same pointer twice
Expand Down Expand Up @@ -5062,7 +5041,6 @@ namespace Js
{
return;
}
Assert(this->guestArena);

if (EnableEvalMapCleanup())
{
Expand Down
8 changes: 0 additions & 8 deletions deps/chakrashim/core/lib/Runtime/Base/ScriptContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,6 @@ namespace Js
CacheAllocator enumeratorCacheAllocator;

ArenaAllocator* interpreterArena;
ArenaAllocator* guestArena;

#ifdef ENABLE_SCRIPT_DEBUGGING
ArenaAllocator* diagnosticArena;
Expand Down Expand Up @@ -1378,13 +1377,6 @@ namespace Js
bool EnsureInterpreterArena(ArenaAllocator **);
void ReleaseInterpreterArena();

ArenaAllocator* GetGuestArena() const
{
return guestArena;
}

void ReleaseGuestArena();

Recycler* GetRecycler() const { return recycler; }
RecyclerJavascriptNumberAllocator * GetNumberAllocator() { return &numberAllocator; }
#if ENABLE_NATIVE_CODEGEN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,11 @@ namespace Js
childModuleRecord->GenerateRootFunction();
});
}

if (this->parser != nullptr)
{
this->parser->ReleaseTemporaryGuestArena();
}
}

Var SourceTextModuleRecord::ModuleEvaluation()
Expand Down
13 changes: 13 additions & 0 deletions deps/chakrashim/core/test/es6module/module-functionality.js
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,19 @@ var tests = [
testRunner.LoadModule(functionBody, 'samethread');
}
},
{
name: "OS18171347 - Module's parser leaks temporary Guest Arena allocator when module has a regex pattern.",
body: function() {
testRunner.LoadModule(` /x/ ;`, 'samethread');

try
{
// syntax error
testRunner.LoadModule(` /x/ ; for(i=0);`, 'samethread', {shouldFail:true});
}
catch(e){}
}
},
];

testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

0 comments on commit 2a19f01

Please sign in to comment.