Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ sealed trait SystemPropertiesPropertyMetaInformation extends PropertyMetaInforma
type Self = SystemProperties
}

// TODO Should probably use a data structure that allows retrieving only the latest entries (for use in continuations)
class SystemProperties(val properties: Map[String, Set[String]])
extends Property with SystemPropertiesPropertyMetaInformation {
final def key: PropertyKey[SystemProperties] = SystemProperties.key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class SystemPropertiesAnalysisScheduler private[analyses] (

var propertyMap: Map[String, Set[String]] = Map.empty

// TODO Should we be able to distinguish between the System properties and other properties objects?
for (stmt <- stmts) stmt match {
case VirtualFunctionCallStatement(call) if (call.name == "setProperty" || call.name == "put") && classHierarchy.isSubtypeOf(call.declaringClass, ObjectType("java/util/Properties")) =>
propertyMap = computeProperties(propertyMap, call.params, stmts)
Expand Down Expand Up @@ -123,6 +124,7 @@ class SystemPropertiesAnalysisScheduler private[analyses] (
def getPossibleStrings(
value: Expr[DUVar[ValueInformation]], stmts: Array[Stmt[DUVar[ValueInformation]]]
): Set[String] = {
// TODO Instead of only using String constants, use StringUtil to make use of points-to data if available
value.asVar.definedBy filter { index =>
index >= 0 && stmts(index).asAssignment.expr.isStringConst
} map { stmts(_).asAssignment.expr.asStringConst.value }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.opalj.br.ObjectType
import org.opalj.br.analyses.SomeProject
import org.opalj.br.FieldTypes
import org.opalj.br.fpcf.properties.Context
import org.opalj.br.ClassHierarchy

object MatcherUtil {

Expand Down Expand Up @@ -93,6 +94,7 @@ object MatcherUtil {
typeIterator: TypeIterator,
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy,
incompleteCallSites: IncompleteCallSites,
highSoundness: Boolean
): MethodMatcher = {
Expand Down Expand Up @@ -131,6 +133,7 @@ object MatcherUtil {
typeIterator: TypeIterator,
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy,
incompleteCallSites: IncompleteCallSites,
highSoundness: Boolean
): MethodMatcher = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ package analyses
package cg
package reflection

import org.opalj.fpcf.PropertyStore
import org.opalj.br.MethodDescriptor
import org.opalj.br.ObjectType
import org.opalj.br.ReferenceType
import org.opalj.br.VoidType
import org.opalj.br.analyses.SomeProject
import org.opalj.br.ClassHierarchy
import org.opalj.br.FieldType

object MethodHandlesUtil {
Expand Down Expand Up @@ -66,6 +68,11 @@ object MethodHandlesUtil {
isConstructor: Boolean,
stmts: Array[Stmt[V]],
project: SomeProject
)(
implicit
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy
): MethodMatcher = {
val descriptorsOpt =
if (descriptorOpt.isDefined) {
Expand Down Expand Up @@ -109,6 +116,11 @@ object MethodHandlesUtil {
value: Expr[V],
stmts: Array[Stmt[V]],
project: SomeProject
)(
implicit
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy
): Option[Iterator[MethodDescriptor]] = {

def isMethodType(expr: Expr[V]): Boolean = {
Expand Down Expand Up @@ -158,6 +170,11 @@ object MethodHandlesUtil {
descriptor: MethodDescriptor,
stmts: Array[Stmt[V]],
project: SomeProject
)(
implicit
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy
): Option[Iterator[MethodDescriptor]] = {
val returnTypesOpt = TypesUtil.getPossibleClasses(params.head, stmts, project)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ package cg
package reflection

import org.opalj.fpcf.Entity
import org.opalj.fpcf.EOptionP
import org.opalj.fpcf.PropertyStore
import org.opalj.fpcf.UBP
import org.opalj.br.ObjectType
import org.opalj.br.fpcf.properties.Context
import org.opalj.br.ClassHierarchy
import org.opalj.br.analyses.SomeProject
import org.opalj.br.fpcf.properties.SystemProperties

object StringUtil {

Expand All @@ -20,16 +25,17 @@ object StringUtil {
def getPossibleStrings[ContextType <: Context](
value: Expr[V],
stmts: Array[Stmt[V]]
)(
implicit
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy
): Option[Set[String]] = {
Some(value.asVar.definedBy.map[Set[String]] { index =>
if (index >= 0) {
getString(index, stmts) match {
case Some(v) => Set(v)
case _ =>
return None;
}
} else {
return None;
getString(index, stmts) match {
case Some(v) => Set(v)
case _ =>
return None;
}
}.flatten)
}
Expand All @@ -48,9 +54,10 @@ object StringUtil {
failure: () => Unit
)(
implicit
typeIterator: TypeIterator,
state: TypeIteratorState,
ps: PropertyStore
typeIterator: TypeIterator,
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy
): Set[String] = {
var strings = Set.empty[String]

Expand All @@ -68,11 +75,61 @@ object StringUtil {
strings
}

private[reflection] def getString(stringDefSite: Int, stmts: Array[Stmt[V]]): Option[String] = {
val expr = stmts(stringDefSite).asAssignment.expr
expr match {
case StringConst(_, v) => Some(v)
case _ => None
private[reflection] def getString(
stringDefSite: Int,
stmts: Array[Stmt[V]]
)(
implicit
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy
): Option[String] = {
if (stringDefSite >= 0) {
val expr = stmts(stringDefSite).asAssignment.expr
expr match {
case StringConst(_, v) => Some(v)
// TODO These don't return anything for now as the necessary dependency handling must be implemented first!
case VirtualFunctionCall(_, declaringClass, _, name, _, _, params) if (name == "getProperty" || name == "get") && classHierarchy.isSubtypeOf(declaringClass, ObjectType("java/util/Properties")) =>
getPossiblePropertyValues(params, stmts); None
case StaticFunctionCall(_, ObjectType.System, _, "getProperty", _, params) =>
getPossiblePropertyValues(params, stmts); None
case _ => None
}
} else {
None
}
}

private[this] def getPossiblePropertyValues(
params: Seq[Expr[V]],
stmts: Array[Stmt[V]]
)(
implicit
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy
): Option[Set[String]] = {
val possibleKeys = getPossibleStrings(params.head, stmts) // TODO Use points-to based method

if (possibleKeys.isDefined) {
val defaultValue = if (params.size == 2)
getPossibleStrings(params(1), stmts).getOrElse(Set.empty) // TODO Use points-to based method
else
Set.empty

val properties: EOptionP[SomeProject, SystemProperties] =
ps(ps.context(classOf[SomeProject]), SystemProperties.key)

if (properties.isRefinable)
state.addDependency(null /*TODO*/ , properties)

val propertyValues = properties match {
case UBP(ub) => possibleKeys.get.flatMap(key => ub.properties(key))
case _ => Set.empty
}

Some(propertyValues ++ defaultValue)
} else
None
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.opalj.br.Type
import org.opalj.br.VoidType
import org.opalj.br.analyses.SomeProject
import org.opalj.br.fpcf.properties.Context
import org.opalj.br.ClassHierarchy

object TypesUtil {

Expand All @@ -27,6 +28,11 @@ object TypesUtil {
stmts: Array[Stmt[V]],
project: SomeProject,
onlyObjectTypes: Boolean
)(
implicit
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy
): Option[Set[ObjectType]] = {
StringUtil.getPossibleStrings(className, stmts).map(_.flatMap { cls =>
try {
Expand Down Expand Up @@ -59,9 +65,10 @@ object TypesUtil {
onlyObjectTypes: Boolean
)(
implicit
typeIterator: TypeIterator,
state: TypeIteratorState,
ps: PropertyStore
typeIterator: TypeIterator,
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy
): Set[ObjectType] = {
StringUtil.getPossibleStrings(className, context, depender, stmts, failure).flatMap { cls =>
try {
Expand All @@ -84,6 +91,11 @@ object TypesUtil {
stmts: Array[Stmt[V]],
project: SomeProject,
onlyObjectTypes: Boolean
)(
implicit
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy
): Option[ObjectType] = {
StringUtil.getString(classNameDefSite, stmts).flatMap { cls =>
try {
Expand All @@ -108,6 +120,11 @@ object TypesUtil {
stmts: Array[Stmt[V]],
project: SomeProject,
onlyObjectTypes: Boolean = false
)(
implicit
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy
): Option[Iterator[Type]] = {

def isForName(expr: Expr[V]): Boolean = { // static call to Class.forName
Expand Down Expand Up @@ -194,9 +211,10 @@ object TypesUtil {
onlyObjectTypes: Boolean
)(
implicit
typeIterator: TypeIterator,
state: TypeIteratorState,
ps: PropertyStore
typeIterator: TypeIterator,
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy
): Set[Type] = {
var possibleTypes: Set[Type] = Set.empty

Expand Down Expand Up @@ -231,9 +249,10 @@ object TypesUtil {
onlyObjectTypes: Boolean
)(
implicit
typeIterator: TypeIterator,
state: TypeIteratorState,
ps: PropertyStore
typeIterator: TypeIterator,
state: TypeIteratorState,
ps: PropertyStore,
classHierarchy: ClassHierarchy
): Set[Type] = {
var possibleTypes: Set[Type] = Set.empty

Expand Down