Skip to content

Commit

Permalink
[jssrc2cpg] Make use of POSSIBLE_TYPES (#4426)
Browse files Browse the repository at this point in the history
With this PR we put all type information into `POSSIBLE_TYPES` instead of `TYPE_FULL_NAME` except for builtin types which is safe to do.
The type recovery (which is only ever run in Joern via `JavaScriptTypeRecovery`) simply adds entries from `POSSIBLE_TYPES` to its existing calculations based on `TYPE_FULL_NAME`.
  • Loading branch information
max-leuthaeuser authored Apr 8, 2024
1 parent 35cd824 commit 76c5d3c
Show file tree
Hide file tree
Showing 18 changed files with 329 additions and 210 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ class AstCreator(val config: Config, val global: Global, val parserResult: Parse
protected val dynamicInstanceTypeStack = new Stack[String]
protected val localAstParentStack = new Stack[NewBlock]()
protected val rootTypeDecl = new Stack[NewTypeDecl]()
protected val typeFullNameToPostfix = mutable.HashMap.empty[String, Int]
protected val functionNodeToNameAndFullName = mutable.HashMap.empty[BabelNodeInfo, (String, String)]
protected val usedVariableNames = mutable.HashMap.empty[String, Int]
protected val seenAliasTypes = mutable.HashSet.empty[NewTypeDecl]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ import io.joern.x2cpg.{Ast, ValidationMode}
import io.shiftleft.codepropertygraph.generated.nodes.*
import io.shiftleft.codepropertygraph.generated.{EdgeTypes, EvaluationStrategies}
import io.shiftleft.codepropertygraph.generated.nodes.File.PropertyDefaults
import io.shiftleft.passes.IntervalKeyPool
import ujson.Value

import scala.collection.{mutable, SortedMap}
import scala.util.{Success, Try}

trait AstCreatorHelper(implicit withSchemaValidation: ValidationMode) { this: AstCreator =>

private val anonClassKeyPool = new IntervalKeyPool(first = 0, last = Long.MaxValue)

protected def nextAnonClassName(): String = s"<anon-class>${anonClassKeyPool.next}"

protected def createBabelNodeInfo(json: Value): BabelNodeInfo = {
val c = code(json)
val ln = line(json)
Expand Down Expand Up @@ -211,21 +216,16 @@ trait AstCreatorHelper(implicit withSchemaValidation: ValidationMode) { this: As
*/
private def calcTypeName(classNode: BabelNodeInfo): String =
if (hasKey(classNode.json, "id") && !classNode.json("id").isNull) code(classNode.json("id"))
else "_anon_cdecl"
else nextAnonClassName()

protected def calcTypeNameAndFullName(
classNode: BabelNodeInfo,
preCalculatedName: Option[String] = None
): (String, String) = {
val name = preCalculatedName.getOrElse(calcTypeName(classNode))
val fullNamePrefix = s"${parserResult.filename}:${computeScopePath(scope.getScopeHead)}:"
val intendedFullName = s"$fullNamePrefix$name"
val postfix = typeFullNameToPostfix.getOrElse(intendedFullName, 0)
val resultingFullName =
if (postfix == 0) intendedFullName
else s"$intendedFullName$postfix"
typeFullNameToPostfix.put(intendedFullName, postfix + 1)
(name, resultingFullName)
val name = preCalculatedName.getOrElse(calcTypeName(classNode))
val fullNamePrefix = s"${parserResult.filename}:${computeScopePath(scope.getScopeHead)}:"
val fullName = s"$fullNamePrefix$name"
(name, fullName)
}

protected def createVariableReferenceLinks(): Unit = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,13 +339,14 @@ trait AstForDeclarationsCreator(implicit withSchemaValidation: ValidationMode) {
val declNodeInfo = createBabelNodeInfo(declarator)
val initNodeInfo = Try(createBabelNodeInfo(declarator("init"))).toOption
val declaratorCode = s"$kind ${code(declarator)}"
val typeFullName = typeFor(declNodeInfo)
val tpe = typeFor(declNodeInfo)
val typeFullName = if (Defines.isBuiltinType(tpe)) tpe else Defines.Any

val idName = idNodeInfo.node match {
case Identifier => idNodeInfo.json("name").str
case _ => idNodeInfo.code
}
val nLocalNode = localNode(declNodeInfo, idName, idName, typeFullName).order(0)
val nLocalNode = localNode(declNodeInfo, idName, idName, typeFullName).order(0).possibleTypes(Seq(tpe))
scope.addVariable(idName, nLocalNode, scopeType)
diffGraph.addEdge(localAstParentStack.head, nLocalNode, EdgeTypes.AST)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package io.joern.jssrc2cpg.astcreation
import io.joern.jssrc2cpg.parser.BabelAst.*
import io.joern.jssrc2cpg.parser.BabelNodeInfo
import io.joern.jssrc2cpg.passes.{Defines, EcmaBuiltins, GlobalBuiltins}
import io.joern.x2cpg.{Ast, ValidationMode, AstNodeBuilder}
import io.joern.x2cpg.{Ast, ValidationMode}
import io.joern.x2cpg.datastructures.Stack.*
import io.shiftleft.codepropertygraph.generated.nodes.NewNode
import io.shiftleft.codepropertygraph.generated.{DispatchTypes, EdgeTypes, Operators}
Expand Down Expand Up @@ -226,19 +226,23 @@ trait AstForExpressionsCreator(implicit withSchemaValidation: ValidationMode) {
}

protected def astForCastExpression(castExpr: BabelNodeInfo): Ast = {
val op = Operators.cast
val typ = typeFor(castExpr) match {
case t if GlobalBuiltins.builtins.contains(t) => s"__ecma.$t"
case t => t
}
val op = Operators.cast
val lhsNode = castExpr.json("typeAnnotation")
val lhsAst = Ast(literalNode(castExpr, code(lhsNode), None).dynamicTypeHintFullName(Seq(typ)))
val rhsAst = astForNodeWithFunctionReference(castExpr.json("expression"))
val node =
callNode(castExpr, castExpr.code, op, DispatchTypes.STATIC_DISPATCH)
.dynamicTypeHintFullName(Seq(typ))
val argAsts = List(lhsAst, rhsAst)
callAst(node, argAsts)
typeFor(castExpr) match {
case tpe if GlobalBuiltins.builtins.contains(tpe) || Defines.isBuiltinType(tpe) =>
val lhsAst = Ast(literalNode(castExpr, code(lhsNode), Option(tpe)))
val node =
callNode(castExpr, castExpr.code, op, DispatchTypes.STATIC_DISPATCH).dynamicTypeHintFullName(Seq(tpe))
val argAsts = List(lhsAst, rhsAst)
callAst(node, argAsts)
case t =>
val possibleTypes = Seq(t)
val lhsAst = Ast(literalNode(castExpr, code(lhsNode), None).possibleTypes(possibleTypes))
val node = callNode(castExpr, castExpr.code, op, DispatchTypes.STATIC_DISPATCH).possibleTypes(possibleTypes)
val argAsts = List(lhsAst, rhsAst)
callAst(node, argAsts)
}
}

protected def astForBinaryExpression(binExpr: BabelNodeInfo): Ast = {
Expand Down Expand Up @@ -404,7 +408,7 @@ trait AstForExpressionsCreator(implicit withSchemaValidation: ValidationMode) {
scope.popScope()
localAstParentStack.pop()

val blockChildrenAsts = if (elementsJsons.length > MAX_INITIALIZERS) {
val blockChildrenAsts = if (elementsJsons.sizeIs > MAX_INITIALIZERS) {
val placeholder = literalNode(arrExpr, "<too-many-initializers>", Defines.Any)
assignmentTmpArrayCallNode +: elementAsts :+ Ast(placeholder) :+ Ast(tmpArrayReturnNode)
} else { assignmentTmpArrayCallNode +: elementAsts :+ Ast(tmpArrayReturnNode) }
Expand Down
Loading

0 comments on commit 76c5d3c

Please sign in to comment.