SlideShare a Scribd company logo
ChakraCore: analysis of JavaScript-engine
for Microsoft Edge
Author: Svyatoslav Razmyslov
Date: 22.01.2016
On the JSConf US conference in December 2015 the developers announced that they were planning to
make open the source code of Chakra key components, a JavaScript-engine, operating in Microsoft
Edge. Recently the ChackraCore source code became available under the MIT license in the
corresponding repository on GitHub. In this article you will find interesting code fragments that were
detected with the help of PVS-Studio code analyzer.
Introduction
ChakraCore is the core part of Chakra, the high-performance JavaScript engine that powers Microsoft
Edge and Windows applications written in HTML/CSS/JS. ChakraCore supports Just-in-time (JIT)
compilation of JavaScript for x86/x64/ARM, garbage collection, and a wide range of the latest JavaScript
features.
PVS-Studio is a static analyzer for bug detection in the source code of programs, written in C, C++ and
C#. PVS-Studio tool is designed for developers of contemporary applications and integrates into the
Visual Studio environments of 2010-2015.
In an article on an open source project check, we report only about a limited number of all of the
warnings issued by the analyzer, therefore we recommend the authors of the project to run the analyzer
on their code themselves and study complete analysis results. We also provide developers of open
source projects with a temporary key.
Various errors
V501 There are identical sub-expressions 'this->propId == Js::PropertyIds::_superReferenceSymbol' to
the left and to the right of the '||' operator. diagobjectmodel.cpp 123
IDiagObjectModelDisplay * ResolvedObject::CreateDisplay()
{
....
if (this->isConst ||
this->propId == Js::PropertyIds::_superReferenceSymbol ||
this->propId == Js::PropertyIds::_superReferenceSymbol)
{
pOMDisplay->SetDefaultTypeAttribute(....);
}
....
}
There two similar checks in the condition. Probably, while writing the code, a programmer accidentally
chose the same constant in the IntelliSense menu, for instance, instead of "Js::PropertyIds::
_superCtorReferenceSymbol".
V501 There are identical sub-expressions 'GetVarSymID(srcIndexOpnd->GetStackSym())' to the left and
to the right of the '==' operator. globopt.cpp 20795
void GlobOpt::EmitMemop(....)
{
....
IR::RegOpnd *srcBaseOpnd = nullptr;
IR::RegOpnd *srcIndexOpnd = nullptr;
IRType srcType;
GetMemOpSrcInfo(...., srcBaseOpnd, srcIndexOpnd, srcType);
Assert(GetVarSymID(srcIndexOpnd->GetStackSym()) == // <=
GetVarSymID(srcIndexOpnd->GetStackSym())); // <=
....
}
Two more identical comparisons. Most likely "srcIndexOpnd->GetStackSym()" was meant to be
compared with "srcBaseOpnd ->GetStackSym()" .
V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error
presence. Check lines: 3220, 3231. lower.cpp 3220
bool Lowerer::GenerateFastBrSrEq(....,
IR::RegOpnd * srcReg1,
IR::RegOpnd * srcReg2,
....)
{
if (srcReg2 && IsConstRegOpnd(srcReg2))
{
....
}
else if (srcReg1 && IsConstRegOpnd(srcReg1))
{
....
}
else if (srcReg2 && (srcReg2->m_sym->m_isStrConst))
{
....
}
else if (srcReg1 && (srcReg1->m_sym->m_isStrConst)) // <=
{
....
}
else if (srcReg2 && (srcReg2->m_sym->m_isStrEmpty))
{
....
}
else if (srcReg1 && (srcReg1->m_sym->m_isStrConst)) // <=
{
....
}
return false;
}
The analyzer detected two similar checks in the cascade of conditional operators; as a result a code
block in the last condition never gets control. Full code of the given example is very long and it's hard to
notice a misprint. It is a good example, showing benefits from using a static code analyzer during the
work with similar code, when the programmer gets quickly tired and lets his guard down.
Most likely, last two conditions were meant to be like this:
....
else if (srcReg2 && (srcReg2->m_sym->m_isStrEmpty))
{
....
}
else if (srcReg1 && (srcReg1->m_sym-> m_isStrEmpty)) // <=
{
....
}
V713 The pointer scriptContext was utilized in the logical expression before it was verified against
nullptr in the same logical expression. diaghelpermethodwrapper.cpp 214
template <bool doCheckParentInterpreterFrame>
void HandleHelperOrLibraryMethodWrapperException(....)
{
....
if (!exceptionObject->IsDebuggerSkip() ||
exceptionObject == scriptContext->GetThreadContext()->.... ||
exceptionObject == scriptContext->GetThreadContext()->.... ||
!scriptContext) // <=
{
throw exceptionObject->CloneIfStaticExceptionObject(....);
}
....
}
Dereference of "scriptContext" pointer is done before its validity is checked. It was luck that such a bug
wasn't noticed and didn't affect the program. Such bugs can live in the code for a very long time and
show up in rare atypical situations.
V570 The 'this->isInlined' variable is assigned to itself. functioncodegenjittimedata.h 625
void SetupRecursiveInlineeChain(
Recycler *const recycler,
const ProfileId profiledCallSiteId)
{
if (!inlinees)
{
inlinees = RecyclerNewArrayZ(....);
}
inlinees[profiledCallSiteId] = this;
inlineeCount++;
this->isInlined = isInlined; // <=
}
It's very suspicious that the same value is stored in the 'isInlined' boolean variable. Most likely the
programmer intended to write something else.
Here is one more fragment, where the variable is assigned to itself:
 V570 The 'sym->m_isTaggableIntConst' variable is assigned to itself. linearscan.cpp 3170
V590 Consider inspecting the 'sub[i] != '-' && sub[i] == '/'' expression. The expression is excessive or
contains a misprint. rl.cpp 1388
const char *
stristr
(
const char * str,
const char * sub
)
{
....
for (i = 0; i < len; i++)
{
if (tolower(str[i]) != tolower(sub[i]))
{
if ((str[i] != '/' && str[i] != '-') ||
(sub[i] != '-' && sub[i] == '/')) { / <=
// if the mismatch is not between '/' and '-'
break;
}
}
}
....
}
The analyzer detected, that a part of the (sub[i] != '-') conditional expression doesn't influence the check
result. To make sure, let's have a look at the truth table. Most likely there is a misprint here; it's hard to
say how to write this code correctly.
V603 The object was created but it is not being used. If you wish to call constructor, 'this-
>StringCopyInfo::StringCopyInfo(....)' should be used. stringcopyinfo.cpp 64
void StringCopyInfo::InstantiateForceInlinedMembers()
{
AnalysisAssert(false);
StringCopyInfo copyInfo;
JavascriptString *const string = nullptr;
wchar_t *const buffer = nullptr;
(StringCopyInfo()); // <=
(StringCopyInfo(string, buffer)); // <=
copyInfo.SourceString();
copyInfo.DestinationBuffer();
}
Programmers often make mistakes, trying to explicitly call the constructor to initialize the object. In this
example we see new unnamed objects of "StringCopyInfo" type that get created and then immediately
destroyed. As a result, the class fields are left uninitialized.
The correct solution would be to create an initialization function and call it from the constructors in this
fragment as well.
V610 Undefined behavior. Check the shift operator '<<'. The left operand '-1' is negative. constants.h 39
class Constants
{
public:
....
static const int Int31MinValue = -1 << 30;
....
};
According to the latest standard of the C++ language, a shift of a negative number results in undefined
behavior.
V557 Array overrun is possible. The value of 'i' index could reach 8. rl.cpp 2375
enum TestInfoKind::_TIK_COUNT = 9
const char * const TestInfoEnvLstFmt[] =
{
" TESTFILE="%s"",
" BASELINE="%s"",
" CFLAGS="%s"",
" LFLAGS="%s"",
NULL,
NULL,
NULL,
NULL // <= TestInfoEnvLstFmt[7]
};
void
WriteEnvLst
(
Test * pDir, TestList * pTestList
)
{
....
// print the other TIK_*
for(int i=0;i < _TIK_COUNT; i++) {
if (variants->testInfo.data[i] && TestInfoEnvLstFmt[i]){// <=
LstFilesOut->Add(TestInfoEnvLstFmt[i], // <=
variants->testInfo.data[i]);
}
....
}
....
}
The analyzer detected that array index is out of bounds. The things is that the for() loop performs 9
iterations, but there are only 8 elements in the "TestInfoEnvLstFmt[]" array.
Perhaps, one more NULL was forgotten in the end:
const char * const TestInfoEnvLstFmt[] =
{
" TESTFILE="%s"",
" BASELINE="%s"",
" CFLAGS="%s"",
" LFLAGS="%s"",
NULL,
NULL,
NULL,
NULL // <= TestInfoEnvLstFmt[7]
NULL // <= TestInfoEnvLstFmt[8]
};
But there is a chance that some string is missing in the middle of the array!
Dangerous pointers
V595 diagnostic looks for such code fragments where the pointer is dereferenced before it is compared
with null. Usually in the projects there are several of such warnings. Such an error holds the record in
out error base according to the number of issues found (see examples). But in general V595 diagnostics
are too boring to give a lot of examples from a project. Also the check and dereference of a pointer can
be located quite far away from each other in the function, having dozens or even hundreds of strings
between them; that makes the explanation of this bug more complicated in the scope of an article.
That's why I'll provide several short examples of the code that most probably contain an error related to
the pointer handling.
V595 The 'instrLd' pointer was utilized before it was verified against nullptr. Check lines: 1823, 1831.
flowgraph.cpp 1823
IR::Instr *
FlowGraph::PeepTypedCm(IR::Instr *instr)
{
....
if (instrLd && !instrLd->GetSrc1()->IsEqual(instr->GetDst()))
{
return nullptr;
}
if(instrLd2 && !instrLd2->GetSrc1()->IsEqual(instrLd->GetDst()))
{
return nullptr;
}
....
}
Have a look at the pointer with the name "instrLd". In the first case we see that it is dereferenced and
compared with null, in the second case a programmer forgot to do so, that's why it can cause null
pointer dereference.
V595 The 'src2Val' pointer was utilized before it was verified against nullptr. Check lines: 9717, 9725.
globopt.cpp 9717
bool GlobOpt::TypeSpecializeIntBinary(....)
{
....
bool isIntConstMissingItem = src2Val->GetValueInfo()->....
if(isIntConstMissingItem)
{
isIntConstMissingItem = Js::SparseArraySegment<int>::....
}
if (!src2Val || !(src2Val->GetValueInfo()->IsLikelyInt()) ||
isIntConstMissingItem)
{
return false;
}
....
}
Pointer "Src2Val" is used at the beginning of the function, but then the developers actively began
checking whether this pointer is equal to zero.
V595 The 'm_lastInstr' pointer was utilized before it was verified against nullptr. Check lines: 214, 228.
irbuilderasmjs.cpp 214
void
IRBuilderAsmJs::AddInstr(IR::Instr * instr, uint32 offset)
{
m_lastInstr->InsertAfter(instr); // <=
if (offset != Js::Constants::NoByteCodeOffset)
{
....
}
else if (m_lastInstr) // <=
{
instr->SetByteCodeOffset(m_lastInstr->GetByteCodeOffset());
}
m_lastInstr = instr;
....
}
One more example of careless use of a pointer that can potentially be a null pointer.
A list of similar fragments:
 V595 The 'arrayData' pointer was utilized before it was verified against nullptr. Check lines: 868,
870. immutablelist.h 868
 V595 The 'pMembersList' pointer was utilized before it was verified against nullptr. Check lines:
2012, 2015. diagobjectmodel.cpp 2012
 V595 The 'walkerRef' pointer was utilized before it was verified against nullptr. Check lines:
3191, 3193. diagobjectmodel.cpp 3191
 V595 The 'block->loop' pointer was utilized before it was verified against nullptr. Check lines:
981, 1002. globopt.cpp 981
 V595 The 'src2Val' pointer was utilized before it was verified against nullptr. Check lines: 12528,
12536. globopt.cpp 12528
 V595 The 'symDst' pointer was utilized before it was verified against nullptr. Check lines: 1966,
1967. irbuilderasmjs.cpp 1966
 V595 The 'symDst' pointer was utilized before it was verified against nullptr. Check lines: 2010,
2011. irbuilderasmjs.cpp 2010
 V595 The 'symDst' pointer was utilized before it was verified against nullptr. Check lines: 2076,
2077. irbuilderasmjs.cpp 2076
 V595 The 'symDst' pointer was utilized before it was verified against nullptr. Check lines: 3591,
3592. irbuilderasmjs.cpp 3591
 V595 The 'symDst' pointer was utilized before it was verified against nullptr. Check lines: 4113,
4114. irbuilderasmjs.cpp 4113
 V595 The 'symDst' pointer was utilized before it was verified against nullptr. Check lines: 4510,
4511. irbuilderasmjs.cpp 4510
 V595 The 'm_lastInstr' pointer was utilized before it was verified against nullptr. Check lines:
1102, 1116. irbuilder.cpp 1102
This list shows some simplest and clearest examples. To examine all fragments like that, developers
should have a look at the analysis result themselves.
V522 Dereferencing of the null pointer 'tempNumberTracker' might take place. backwardpass.cpp 578
void
BackwardPass::MergeSuccBlocksInfo(BasicBlock * block)
{
TempNumberTracker * tempNumberTracker = nullptr; // <= line 346
....
if (!block->isDead)
{
....
if(!IsCollectionPass())
{
....
if (this->DoMarkTempNumbers())
{
tempNumberTracker = JitAnew(....); // <= line 413
}
....
....
if (blockSucc->tempNumberTracker != nullptr)
{
....
tempNumberTracker->MergeData(....); // <= line 578
if (deleteData)
{
blockSucc->tempNumberTracker = nullptr;
}
}
....
}
Example of another diagnostic which is also connected with the pointers. Here is a code fragment of the
MergeSuccBlocksInfo() function, which is quite long - 707 strings. But with the help of static analysis we
managed to find "tempNumberTracker" pointer, whose initialization can potentially fail due to several
conditions. As a result, if the odds are against the programmer, there will be dereference of a null
pointer.
Stop! Check Assert!
Assert, located in the program indicates that a programmer assumes that some expression is true for a
correctly running program. But can these "successful checks be trusted"?
V547 Expression 'srcIndex - src->left >= 0' is always true. Unsigned type value is always >= 0.
sparsearraysegment.inl 355
class SparseArraySegmentBase
{
public:
static const uint32 MaxLength;
....
uint32 size;
....
}
template<typename T>
SparseArraySegment<T>* SparseArraySegment<T>::CopySegment(....,
uint32 srcIndex, ....)
{
....
AssertMsg(srcIndex - src->left >= 0, // <=
"src->left > srcIndex resulting in 
negative indexing of src->elements");
js_memcpy_s(dst->elements + dstIndex - dst->left,
sizeof(T) * inputLen,
src->elements + srcIndex - src->left,
sizeof(T) * inputLen);
return dst;
}
Note the comparison "srcIndex-src-> left > = 0". Difference of two unsigned numbers will always be
greater than or equal to zero. Further on this function is used for working with the memory. The result
can be different from the one that the programmer expected.
V547 Expression is always true. Probably the '&&' operator should be used here. bytecodegenerator.cpp
805
void ByteCodeGenerator::AssignRegister(Symbol *sym)
{
AssertMsg(sym->GetDecl() == nullptr ||
sym->GetDecl()->nop != knopConstDecl || // <=
sym->GetDecl()->nop != knopLetDecl, "...."); // <=
if (sym->GetLocation() == Js::Constants::NoRegister)
{
sym->SetLocation(NextVarRegister());
}
}
In this Assert testing of some values is done only partially. If the expression "sym->GetDecl() == nullptr"
is false, then the following conditions are always true. You can check it by building a truth table.
V547 Expression 'callSiteId >= 0' is always true. Unsigned type value is always >= 0. inline.cpp 1181
typedef uint16 ProfileId;
Func * Inline::BuildInlinee(Js::FunctionBody* funcBody, ....)
{
....
Js::ProfileId callSiteId = static_cast<Js::ProfileId>(....);
Assert(callSiteId >= 0);
....
}
In this and couple of other fragments the analyzer detected incorrect comparison of an unsigned
number with null:
 V547 Expression 'callSiteId >= 0' is always true. Unsigned type value is always >= 0. inline.cpp
2627
 V547 Expression 'callSiteId >= 0' is always true. Unsigned type value is always >= 0. inline.cpp
3657
Conclusion
Microsoft has a positive tendency to release their projects under free licenses. For us it is an additional
opportunity to test the analyzer on new projects and also a way to demonstrate usefulness and
effectiveness of static code analysis on the projects of such a large and well known software vendor.
You may be interested to see the full list of all scanned projects that includes other projects from
Microsoft, such as .NET CoreCLR, CoreFX .NET and Microsoft Code Contracts.

More Related Content

What's hot (20)

PDF
Checking the Source Code of FlashDevelop with PVS-Studio
PVS-Studio
 
PDF
Linux version of PVS-Studio couldn't help checking CodeLite
PVS-Studio
 
PDF
PVS-Studio is there to help CERN: analysis of Geant4 project
PVS-Studio
 
PDF
Dusting the globe: analysis of NASA World Wind project
PVS-Studio
 
PDF
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 1
PVS-Studio
 
PDF
A Slipshod Check of the Visual C++ 2013 Library (update 3)
Andrey Karpov
 
PDF
Safer JS Codebases with Flow
Valentin Agachi
 
PDF
A Spin-off: CryEngine 3 SDK Checked with CppCat
Andrey Karpov
 
PDF
Errors detected in the Visual C++ 2012 libraries
PVS-Studio
 
PDF
Checking OpenCV with PVS-Studio
PVS-Studio
 
PDF
Critical errors in CryEngine V code
PVS-Studio
 
PDF
Python and Ruby implementations compared by the error density
PVS-Studio
 
PDF
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
PVS-Studio
 
PDF
Picking Mushrooms after Cppcheck
Andrey Karpov
 
PDF
The Little Unicorn That Could
PVS-Studio
 
PDF
Checking Oracle VM VirtualBox. Part 1
Andrey Karpov
 
PDF
Documenting Bugs in Doxygen
PVS-Studio
 
PDF
Why Windows 8 drivers are buggy
Andrey Karpov
 
PDF
Checking the code of Valgrind dynamic analyzer by a static analyzer
PVS-Studio
 
PDF
Checking WinMerge with PVS-Studio for the second time
PVS-Studio
 
Checking the Source Code of FlashDevelop with PVS-Studio
PVS-Studio
 
Linux version of PVS-Studio couldn't help checking CodeLite
PVS-Studio
 
PVS-Studio is there to help CERN: analysis of Geant4 project
PVS-Studio
 
Dusting the globe: analysis of NASA World Wind project
PVS-Studio
 
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 1
PVS-Studio
 
A Slipshod Check of the Visual C++ 2013 Library (update 3)
Andrey Karpov
 
Safer JS Codebases with Flow
Valentin Agachi
 
A Spin-off: CryEngine 3 SDK Checked with CppCat
Andrey Karpov
 
Errors detected in the Visual C++ 2012 libraries
PVS-Studio
 
Checking OpenCV with PVS-Studio
PVS-Studio
 
Critical errors in CryEngine V code
PVS-Studio
 
Python and Ruby implementations compared by the error density
PVS-Studio
 
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
PVS-Studio
 
Picking Mushrooms after Cppcheck
Andrey Karpov
 
The Little Unicorn That Could
PVS-Studio
 
Checking Oracle VM VirtualBox. Part 1
Andrey Karpov
 
Documenting Bugs in Doxygen
PVS-Studio
 
Why Windows 8 drivers are buggy
Andrey Karpov
 
Checking the code of Valgrind dynamic analyzer by a static analyzer
PVS-Studio
 
Checking WinMerge with PVS-Studio for the second time
PVS-Studio
 

Viewers also liked (13)

PDF
Resume(Narendra)
Narendra Singh Parihar
 
PDF
García carlos el honor un valor imprescindible
Alicia Ramirez
 
PDF
Resume
Jacqueline Orr
 
PPTX
Taller de sistemas
Juanjose897
 
DOCX
Turismo de tnaturaleza en coloombia
nancy211213
 
PPTX
CRYO CORP
CRYO CORP
 
PDF
executives care.PDF
MD RUHUL QUDDUS
 
DOC
ONI Michael-CV 1 cem + foto
michael oni
 
PPT
La Contaminacion Ambiental
Oliver Cantuña
 
PDF
Academic record
Qhiniso Msomi
 
PDF
BRONSON_adv
Arno Wouters
 
DOCX
Vendryes Resume
Art Vendryes
 
PDF
Azure Securtity Pro
John Horn
 
Resume(Narendra)
Narendra Singh Parihar
 
García carlos el honor un valor imprescindible
Alicia Ramirez
 
Taller de sistemas
Juanjose897
 
Turismo de tnaturaleza en coloombia
nancy211213
 
CRYO CORP
CRYO CORP
 
executives care.PDF
MD RUHUL QUDDUS
 
ONI Michael-CV 1 cem + foto
michael oni
 
La Contaminacion Ambiental
Oliver Cantuña
 
Academic record
Qhiniso Msomi
 
BRONSON_adv
Arno Wouters
 
Vendryes Resume
Art Vendryes
 
Azure Securtity Pro
John Horn
 
Ad

Similar to ChakraCore: analysis of JavaScript-engine for Microsoft Edge (18)

PDF
100 bugs in Open Source C/C++ projects
Andrey Karpov
 
PDF
Headache from using mathematical software
PVS-Studio
 
PDF
"Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ...
PVS-Studio
 
PDF
Discussing Errors in Unity3D's Open-Source Components
PVS-Studio
 
PPTX
The operation principles of PVS-Studio static code analyzer
Andrey Karpov
 
PDF
Tesseract. Recognizing Errors in Recognition Software
Andrey Karpov
 
PDF
Re-checking the ReactOS project - a large report
PVS-Studio
 
PDF
Sony C#/.NET component set analysis
PVS-Studio
 
PDF
PVS-Studio team is about to produce a technical breakthrough, but for now let...
PVS-Studio
 
PDF
Why Windows 8 drivers are buggy
PVS-Studio
 
PDF
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
PVS-Studio
 
PDF
Checking Oracle VM VirtualBox. Part 2
Andrey Karpov
 
PDF
PVS-Studio vs Chromium. 3-rd Check
Andrey Karpov
 
PDF
The Unicorn's Travel to the Microcosm
Andrey Karpov
 
PDF
Analyzing the Dolphin-emu project
PVS-Studio
 
PDF
Rechecking TortoiseSVN with the PVS-Studio Code Analyzer
Andrey Karpov
 
PDF
Spring RTS Engine Checkup
PVS-Studio
 
PDF
Analysis of Microsoft Code Contracts
PVS-Studio
 
100 bugs in Open Source C/C++ projects
Andrey Karpov
 
Headache from using mathematical software
PVS-Studio
 
"Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ...
PVS-Studio
 
Discussing Errors in Unity3D's Open-Source Components
PVS-Studio
 
The operation principles of PVS-Studio static code analyzer
Andrey Karpov
 
Tesseract. Recognizing Errors in Recognition Software
Andrey Karpov
 
Re-checking the ReactOS project - a large report
PVS-Studio
 
Sony C#/.NET component set analysis
PVS-Studio
 
PVS-Studio team is about to produce a technical breakthrough, but for now let...
PVS-Studio
 
Why Windows 8 drivers are buggy
PVS-Studio
 
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
PVS-Studio
 
Checking Oracle VM VirtualBox. Part 2
Andrey Karpov
 
PVS-Studio vs Chromium. 3-rd Check
Andrey Karpov
 
The Unicorn's Travel to the Microcosm
Andrey Karpov
 
Analyzing the Dolphin-emu project
PVS-Studio
 
Rechecking TortoiseSVN with the PVS-Studio Code Analyzer
Andrey Karpov
 
Spring RTS Engine Checkup
PVS-Studio
 
Analysis of Microsoft Code Contracts
PVS-Studio
 
Ad

Recently uploaded (20)

PPTX
iaas vs paas vs saas :choosing your cloud strategy
CloudlayaTechnology
 
PPTX
Help for Correlations in IBM SPSS Statistics.pptx
Version 1 Analytics
 
PDF
Dipole Tech Innovations – Global IT Solutions for Business Growth
dipoletechi3
 
PDF
AI Prompts Cheat Code prompt engineering
Avijit Kumar Roy
 
PDF
The 5 Reasons for IT Maintenance - Arna Softech
Arna Softech
 
PDF
Open Chain Q2 Steering Committee Meeting - 2025-06-25
Shane Coughlan
 
PDF
MiniTool Power Data Recovery 8.8 With Crack New Latest 2025
bashirkhan333g
 
PPTX
Get Started with Maestro: Agent, Robot, and Human in Action – Session 5 of 5
klpathrudu
 
PDF
MiniTool Partition Wizard Free Crack + Full Free Download 2025
bashirkhan333g
 
PDF
Everything you need to know about pricing & licensing Microsoft 365 Copilot f...
Q-Advise
 
PDF
ERP Consulting Services and Solutions by Contetra Pvt Ltd
jayjani123
 
PPTX
Coefficient of Variance in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
PPTX
Agentic Automation Journey Series Day 2 – Prompt Engineering for UiPath Agents
klpathrudu
 
PDF
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
PDF
Generic or Specific? Making sensible software design decisions
Bert Jan Schrijver
 
PPTX
Function & Procedure: Function Vs Procedure in PL/SQL
Shani Tiwari
 
PDF
Empower Your Tech Vision- Why Businesses Prefer to Hire Remote Developers fro...
logixshapers59
 
PPTX
Homogeneity of Variance Test Options IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
PDF
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
PDF
4K Video Downloader Plus Pro Crack for MacOS New Download 2025
bashirkhan333g
 
iaas vs paas vs saas :choosing your cloud strategy
CloudlayaTechnology
 
Help for Correlations in IBM SPSS Statistics.pptx
Version 1 Analytics
 
Dipole Tech Innovations – Global IT Solutions for Business Growth
dipoletechi3
 
AI Prompts Cheat Code prompt engineering
Avijit Kumar Roy
 
The 5 Reasons for IT Maintenance - Arna Softech
Arna Softech
 
Open Chain Q2 Steering Committee Meeting - 2025-06-25
Shane Coughlan
 
MiniTool Power Data Recovery 8.8 With Crack New Latest 2025
bashirkhan333g
 
Get Started with Maestro: Agent, Robot, and Human in Action – Session 5 of 5
klpathrudu
 
MiniTool Partition Wizard Free Crack + Full Free Download 2025
bashirkhan333g
 
Everything you need to know about pricing & licensing Microsoft 365 Copilot f...
Q-Advise
 
ERP Consulting Services and Solutions by Contetra Pvt Ltd
jayjani123
 
Coefficient of Variance in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
Agentic Automation Journey Series Day 2 – Prompt Engineering for UiPath Agents
klpathrudu
 
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
Generic or Specific? Making sensible software design decisions
Bert Jan Schrijver
 
Function & Procedure: Function Vs Procedure in PL/SQL
Shani Tiwari
 
Empower Your Tech Vision- Why Businesses Prefer to Hire Remote Developers fro...
logixshapers59
 
Homogeneity of Variance Test Options IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
4K Video Downloader Plus Pro Crack for MacOS New Download 2025
bashirkhan333g
 

ChakraCore: analysis of JavaScript-engine for Microsoft Edge

  • 1. ChakraCore: analysis of JavaScript-engine for Microsoft Edge Author: Svyatoslav Razmyslov Date: 22.01.2016 On the JSConf US conference in December 2015 the developers announced that they were planning to make open the source code of Chakra key components, a JavaScript-engine, operating in Microsoft Edge. Recently the ChackraCore source code became available under the MIT license in the corresponding repository on GitHub. In this article you will find interesting code fragments that were detected with the help of PVS-Studio code analyzer. Introduction ChakraCore is the core part of Chakra, the high-performance JavaScript engine that powers Microsoft Edge and Windows applications written in HTML/CSS/JS. ChakraCore supports Just-in-time (JIT) compilation of JavaScript for x86/x64/ARM, garbage collection, and a wide range of the latest JavaScript features. PVS-Studio is a static analyzer for bug detection in the source code of programs, written in C, C++ and C#. PVS-Studio tool is designed for developers of contemporary applications and integrates into the Visual Studio environments of 2010-2015. In an article on an open source project check, we report only about a limited number of all of the warnings issued by the analyzer, therefore we recommend the authors of the project to run the analyzer on their code themselves and study complete analysis results. We also provide developers of open source projects with a temporary key.
  • 2. Various errors V501 There are identical sub-expressions 'this->propId == Js::PropertyIds::_superReferenceSymbol' to the left and to the right of the '||' operator. diagobjectmodel.cpp 123 IDiagObjectModelDisplay * ResolvedObject::CreateDisplay() { .... if (this->isConst || this->propId == Js::PropertyIds::_superReferenceSymbol || this->propId == Js::PropertyIds::_superReferenceSymbol) { pOMDisplay->SetDefaultTypeAttribute(....); } .... } There two similar checks in the condition. Probably, while writing the code, a programmer accidentally chose the same constant in the IntelliSense menu, for instance, instead of "Js::PropertyIds:: _superCtorReferenceSymbol". V501 There are identical sub-expressions 'GetVarSymID(srcIndexOpnd->GetStackSym())' to the left and to the right of the '==' operator. globopt.cpp 20795 void GlobOpt::EmitMemop(....) { .... IR::RegOpnd *srcBaseOpnd = nullptr; IR::RegOpnd *srcIndexOpnd = nullptr; IRType srcType; GetMemOpSrcInfo(...., srcBaseOpnd, srcIndexOpnd, srcType); Assert(GetVarSymID(srcIndexOpnd->GetStackSym()) == // <= GetVarSymID(srcIndexOpnd->GetStackSym())); // <= .... }
  • 3. Two more identical comparisons. Most likely "srcIndexOpnd->GetStackSym()" was meant to be compared with "srcBaseOpnd ->GetStackSym()" . V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 3220, 3231. lower.cpp 3220 bool Lowerer::GenerateFastBrSrEq(...., IR::RegOpnd * srcReg1, IR::RegOpnd * srcReg2, ....) { if (srcReg2 && IsConstRegOpnd(srcReg2)) { .... } else if (srcReg1 && IsConstRegOpnd(srcReg1)) { .... } else if (srcReg2 && (srcReg2->m_sym->m_isStrConst)) { .... } else if (srcReg1 && (srcReg1->m_sym->m_isStrConst)) // <= { .... } else if (srcReg2 && (srcReg2->m_sym->m_isStrEmpty)) { .... } else if (srcReg1 && (srcReg1->m_sym->m_isStrConst)) // <= { .... } return false; } The analyzer detected two similar checks in the cascade of conditional operators; as a result a code block in the last condition never gets control. Full code of the given example is very long and it's hard to notice a misprint. It is a good example, showing benefits from using a static code analyzer during the work with similar code, when the programmer gets quickly tired and lets his guard down. Most likely, last two conditions were meant to be like this: .... else if (srcReg2 && (srcReg2->m_sym->m_isStrEmpty)) { .... } else if (srcReg1 && (srcReg1->m_sym-> m_isStrEmpty)) // <= { .... }
  • 4. V713 The pointer scriptContext was utilized in the logical expression before it was verified against nullptr in the same logical expression. diaghelpermethodwrapper.cpp 214 template <bool doCheckParentInterpreterFrame> void HandleHelperOrLibraryMethodWrapperException(....) { .... if (!exceptionObject->IsDebuggerSkip() || exceptionObject == scriptContext->GetThreadContext()->.... || exceptionObject == scriptContext->GetThreadContext()->.... || !scriptContext) // <= { throw exceptionObject->CloneIfStaticExceptionObject(....); } .... } Dereference of "scriptContext" pointer is done before its validity is checked. It was luck that such a bug wasn't noticed and didn't affect the program. Such bugs can live in the code for a very long time and show up in rare atypical situations. V570 The 'this->isInlined' variable is assigned to itself. functioncodegenjittimedata.h 625 void SetupRecursiveInlineeChain( Recycler *const recycler, const ProfileId profiledCallSiteId) { if (!inlinees) { inlinees = RecyclerNewArrayZ(....); } inlinees[profiledCallSiteId] = this; inlineeCount++; this->isInlined = isInlined; // <= } It's very suspicious that the same value is stored in the 'isInlined' boolean variable. Most likely the programmer intended to write something else. Here is one more fragment, where the variable is assigned to itself:  V570 The 'sym->m_isTaggableIntConst' variable is assigned to itself. linearscan.cpp 3170 V590 Consider inspecting the 'sub[i] != '-' && sub[i] == '/'' expression. The expression is excessive or contains a misprint. rl.cpp 1388 const char * stristr ( const char * str, const char * sub ) { .... for (i = 0; i < len; i++) {
  • 5. if (tolower(str[i]) != tolower(sub[i])) { if ((str[i] != '/' && str[i] != '-') || (sub[i] != '-' && sub[i] == '/')) { / <= // if the mismatch is not between '/' and '-' break; } } } .... } The analyzer detected, that a part of the (sub[i] != '-') conditional expression doesn't influence the check result. To make sure, let's have a look at the truth table. Most likely there is a misprint here; it's hard to say how to write this code correctly. V603 The object was created but it is not being used. If you wish to call constructor, 'this- >StringCopyInfo::StringCopyInfo(....)' should be used. stringcopyinfo.cpp 64 void StringCopyInfo::InstantiateForceInlinedMembers() { AnalysisAssert(false); StringCopyInfo copyInfo; JavascriptString *const string = nullptr; wchar_t *const buffer = nullptr; (StringCopyInfo()); // <= (StringCopyInfo(string, buffer)); // <= copyInfo.SourceString(); copyInfo.DestinationBuffer(); } Programmers often make mistakes, trying to explicitly call the constructor to initialize the object. In this example we see new unnamed objects of "StringCopyInfo" type that get created and then immediately destroyed. As a result, the class fields are left uninitialized. The correct solution would be to create an initialization function and call it from the constructors in this fragment as well. V610 Undefined behavior. Check the shift operator '<<'. The left operand '-1' is negative. constants.h 39 class Constants { public: .... static const int Int31MinValue = -1 << 30; .... };
  • 6. According to the latest standard of the C++ language, a shift of a negative number results in undefined behavior. V557 Array overrun is possible. The value of 'i' index could reach 8. rl.cpp 2375 enum TestInfoKind::_TIK_COUNT = 9 const char * const TestInfoEnvLstFmt[] = { " TESTFILE="%s"", " BASELINE="%s"", " CFLAGS="%s"", " LFLAGS="%s"", NULL, NULL, NULL, NULL // <= TestInfoEnvLstFmt[7] }; void WriteEnvLst ( Test * pDir, TestList * pTestList ) { .... // print the other TIK_* for(int i=0;i < _TIK_COUNT; i++) { if (variants->testInfo.data[i] && TestInfoEnvLstFmt[i]){// <= LstFilesOut->Add(TestInfoEnvLstFmt[i], // <= variants->testInfo.data[i]); } .... } .... } The analyzer detected that array index is out of bounds. The things is that the for() loop performs 9 iterations, but there are only 8 elements in the "TestInfoEnvLstFmt[]" array. Perhaps, one more NULL was forgotten in the end: const char * const TestInfoEnvLstFmt[] = { " TESTFILE="%s"", " BASELINE="%s"", " CFLAGS="%s"", " LFLAGS="%s"", NULL, NULL, NULL, NULL // <= TestInfoEnvLstFmt[7] NULL // <= TestInfoEnvLstFmt[8] }; But there is a chance that some string is missing in the middle of the array!
  • 7. Dangerous pointers V595 diagnostic looks for such code fragments where the pointer is dereferenced before it is compared with null. Usually in the projects there are several of such warnings. Such an error holds the record in out error base according to the number of issues found (see examples). But in general V595 diagnostics are too boring to give a lot of examples from a project. Also the check and dereference of a pointer can be located quite far away from each other in the function, having dozens or even hundreds of strings between them; that makes the explanation of this bug more complicated in the scope of an article. That's why I'll provide several short examples of the code that most probably contain an error related to the pointer handling. V595 The 'instrLd' pointer was utilized before it was verified against nullptr. Check lines: 1823, 1831. flowgraph.cpp 1823 IR::Instr * FlowGraph::PeepTypedCm(IR::Instr *instr) { .... if (instrLd && !instrLd->GetSrc1()->IsEqual(instr->GetDst())) { return nullptr; } if(instrLd2 && !instrLd2->GetSrc1()->IsEqual(instrLd->GetDst())) { return nullptr; } .... } Have a look at the pointer with the name "instrLd". In the first case we see that it is dereferenced and compared with null, in the second case a programmer forgot to do so, that's why it can cause null pointer dereference. V595 The 'src2Val' pointer was utilized before it was verified against nullptr. Check lines: 9717, 9725. globopt.cpp 9717
  • 8. bool GlobOpt::TypeSpecializeIntBinary(....) { .... bool isIntConstMissingItem = src2Val->GetValueInfo()->.... if(isIntConstMissingItem) { isIntConstMissingItem = Js::SparseArraySegment<int>::.... } if (!src2Val || !(src2Val->GetValueInfo()->IsLikelyInt()) || isIntConstMissingItem) { return false; } .... } Pointer "Src2Val" is used at the beginning of the function, but then the developers actively began checking whether this pointer is equal to zero. V595 The 'm_lastInstr' pointer was utilized before it was verified against nullptr. Check lines: 214, 228. irbuilderasmjs.cpp 214 void IRBuilderAsmJs::AddInstr(IR::Instr * instr, uint32 offset) { m_lastInstr->InsertAfter(instr); // <= if (offset != Js::Constants::NoByteCodeOffset) { .... } else if (m_lastInstr) // <= { instr->SetByteCodeOffset(m_lastInstr->GetByteCodeOffset()); } m_lastInstr = instr; .... } One more example of careless use of a pointer that can potentially be a null pointer. A list of similar fragments:  V595 The 'arrayData' pointer was utilized before it was verified against nullptr. Check lines: 868, 870. immutablelist.h 868  V595 The 'pMembersList' pointer was utilized before it was verified against nullptr. Check lines: 2012, 2015. diagobjectmodel.cpp 2012  V595 The 'walkerRef' pointer was utilized before it was verified against nullptr. Check lines: 3191, 3193. diagobjectmodel.cpp 3191  V595 The 'block->loop' pointer was utilized before it was verified against nullptr. Check lines: 981, 1002. globopt.cpp 981  V595 The 'src2Val' pointer was utilized before it was verified against nullptr. Check lines: 12528, 12536. globopt.cpp 12528
  • 9.  V595 The 'symDst' pointer was utilized before it was verified against nullptr. Check lines: 1966, 1967. irbuilderasmjs.cpp 1966  V595 The 'symDst' pointer was utilized before it was verified against nullptr. Check lines: 2010, 2011. irbuilderasmjs.cpp 2010  V595 The 'symDst' pointer was utilized before it was verified against nullptr. Check lines: 2076, 2077. irbuilderasmjs.cpp 2076  V595 The 'symDst' pointer was utilized before it was verified against nullptr. Check lines: 3591, 3592. irbuilderasmjs.cpp 3591  V595 The 'symDst' pointer was utilized before it was verified against nullptr. Check lines: 4113, 4114. irbuilderasmjs.cpp 4113  V595 The 'symDst' pointer was utilized before it was verified against nullptr. Check lines: 4510, 4511. irbuilderasmjs.cpp 4510  V595 The 'm_lastInstr' pointer was utilized before it was verified against nullptr. Check lines: 1102, 1116. irbuilder.cpp 1102 This list shows some simplest and clearest examples. To examine all fragments like that, developers should have a look at the analysis result themselves. V522 Dereferencing of the null pointer 'tempNumberTracker' might take place. backwardpass.cpp 578 void BackwardPass::MergeSuccBlocksInfo(BasicBlock * block) { TempNumberTracker * tempNumberTracker = nullptr; // <= line 346 .... if (!block->isDead) { .... if(!IsCollectionPass()) { .... if (this->DoMarkTempNumbers()) { tempNumberTracker = JitAnew(....); // <= line 413 } .... .... if (blockSucc->tempNumberTracker != nullptr) { .... tempNumberTracker->MergeData(....); // <= line 578 if (deleteData) { blockSucc->tempNumberTracker = nullptr; } } .... } Example of another diagnostic which is also connected with the pointers. Here is a code fragment of the MergeSuccBlocksInfo() function, which is quite long - 707 strings. But with the help of static analysis we managed to find "tempNumberTracker" pointer, whose initialization can potentially fail due to several
  • 10. conditions. As a result, if the odds are against the programmer, there will be dereference of a null pointer. Stop! Check Assert! Assert, located in the program indicates that a programmer assumes that some expression is true for a correctly running program. But can these "successful checks be trusted"? V547 Expression 'srcIndex - src->left >= 0' is always true. Unsigned type value is always >= 0. sparsearraysegment.inl 355 class SparseArraySegmentBase { public: static const uint32 MaxLength; .... uint32 size; .... } template<typename T> SparseArraySegment<T>* SparseArraySegment<T>::CopySegment(...., uint32 srcIndex, ....) { .... AssertMsg(srcIndex - src->left >= 0, // <= "src->left > srcIndex resulting in negative indexing of src->elements"); js_memcpy_s(dst->elements + dstIndex - dst->left, sizeof(T) * inputLen, src->elements + srcIndex - src->left, sizeof(T) * inputLen); return dst; }
  • 11. Note the comparison "srcIndex-src-> left > = 0". Difference of two unsigned numbers will always be greater than or equal to zero. Further on this function is used for working with the memory. The result can be different from the one that the programmer expected. V547 Expression is always true. Probably the '&&' operator should be used here. bytecodegenerator.cpp 805 void ByteCodeGenerator::AssignRegister(Symbol *sym) { AssertMsg(sym->GetDecl() == nullptr || sym->GetDecl()->nop != knopConstDecl || // <= sym->GetDecl()->nop != knopLetDecl, "...."); // <= if (sym->GetLocation() == Js::Constants::NoRegister) { sym->SetLocation(NextVarRegister()); } } In this Assert testing of some values is done only partially. If the expression "sym->GetDecl() == nullptr" is false, then the following conditions are always true. You can check it by building a truth table. V547 Expression 'callSiteId >= 0' is always true. Unsigned type value is always >= 0. inline.cpp 1181 typedef uint16 ProfileId; Func * Inline::BuildInlinee(Js::FunctionBody* funcBody, ....) { .... Js::ProfileId callSiteId = static_cast<Js::ProfileId>(....); Assert(callSiteId >= 0); .... } In this and couple of other fragments the analyzer detected incorrect comparison of an unsigned number with null:  V547 Expression 'callSiteId >= 0' is always true. Unsigned type value is always >= 0. inline.cpp 2627  V547 Expression 'callSiteId >= 0' is always true. Unsigned type value is always >= 0. inline.cpp 3657 Conclusion Microsoft has a positive tendency to release their projects under free licenses. For us it is an additional opportunity to test the analyzer on new projects and also a way to demonstrate usefulness and effectiveness of static code analysis on the projects of such a large and well known software vendor. You may be interested to see the full list of all scanned projects that includes other projects from Microsoft, such as .NET CoreCLR, CoreFX .NET and Microsoft Code Contracts.