Skip to content

Commit 88af66c

Browse files
author
Dominik Helm
committed
Invalidate StringBuilder/Buffer arguments of unknown calls that might modify them
1 parent 71959bf commit 88af66c

File tree

10 files changed

+61
-29
lines changed

10 files changed

+61
-29
lines changed

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/string/StringInterpreter.scala

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ trait StringInterpreter {
5050

5151
protected[this] def computeFinalResult(p: StringFlowFunctionProperty)(implicit state: InterpretationState): Result =
5252
StringInterpreter.computeFinalResult(p)
53-
54-
protected[this] def isStringBuilderBufferCall(call: Call[V]): Boolean =
55-
(call.declaringClass eq ClassType.StringBuilder) || (call.declaringClass eq ClassType.StringBuffer)
5653
}
5754

5855
object StringInterpreter {
@@ -76,6 +73,32 @@ object StringInterpreter {
7673

7774
def computeFinalResult(p: StringFlowFunctionProperty)(implicit state: InterpretationState): Result =
7875
Result(FinalEP(InterpretationHandler.getEntity(state), p))
76+
77+
def invalidEntitiesForUnknownCall(call: Call[V], target: Option[PV] = None)(implicit
78+
state: InterpretationState
79+
): Set[PV] = {
80+
val relevantParameters = call.descriptor.parameterTypes.iterator.zipWithIndex.collect {
81+
case (p, index)
82+
if p.isClassType && ((p.asClassType eq ClassType.StringBuilder) || (p.asClassType eq ClassType.StringBuffer)) =>
83+
call.params(index)
84+
}
85+
val relevantReceiver = call.receiverOption.filter { _ => isStringBuilderBufferCall(call) }
86+
(relevantParameters ++ relevantReceiver).map(_.asVar.toPersistentForm(state.tac.stmts)).toSet ++ target
87+
}
88+
89+
def uninterpretedCall(call: Call[V], target: Option[PV] = None)(implicit
90+
state: InterpretationState,
91+
highSoundness: Boolean
92+
): Result = {
93+
val relevantEntities = invalidEntitiesForUnknownCall(call, target)
94+
val webs = relevantEntities.map(PDUWeb(state.pc, _))
95+
val flow = StringFlowFunctionProperty.constForEntities(state.pc, relevantEntities, failureTree)
96+
val p = StringFlowFunctionProperty(webs, flow)
97+
Result(FinalEP(InterpretationHandler.getEntity(state), p))
98+
}
99+
100+
def isStringBuilderBufferCall(call: Call[V]): Boolean =
101+
(call.declaringClass eq ClassType.StringBuilder) || (call.declaringClass eq ClassType.StringBuffer)
79102
}
80103

81104
/**

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/string/l0/interpretation/L0InterpretationHandler.scala

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,10 @@ class L0InterpretationHandler(implicit override val project: SomeProject) extend
3030
SimpleValueConstExprInterpreter.interpretExpr(stmt, expr)
3131
case stmt @ Assignment(_, _, expr: BinaryExpr[V]) => BinaryExprInterpreter().interpretExpr(stmt, expr)
3232

33-
case ExprStmt(_, expr: InstanceFunctionCall[V]) => StringInterpreter.failure(expr.receiver.asVar)
34-
35-
case vmc: VirtualMethodCall[V] => StringInterpreter.failure(vmc.receiver.asVar)
36-
case nvmc: NonVirtualMethodCall[V] => StringInterpreter.failure(nvmc.receiver.asVar)
37-
38-
// Static calls without return value usage are irrelevant
39-
case ExprStmt(_, _: StaticFunctionCall[V]) | _: StaticMethodCall[V] =>
40-
StringInterpreter.computeFinalResult(StringFlowFunctionProperty.identity)
33+
case ExprStmt(_, call: InstanceFunctionCall[V]) => StringInterpreter.uninterpretedCall(call)
34+
case Assignment(_, target, call: InstanceFunctionCall[V]) =>
35+
StringInterpreter.uninterpretedCall(call, Some(target.asVar.toPersistentForm(state.tac.stmts)))
36+
case call: MethodCall[V] => StringInterpreter.uninterpretedCall(call)
4137

4238
case Assignment(_, target, _) => StringInterpreter.failure(target)
4339

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/string/l1/interpretation/L1FunctionCallInterpreter.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,10 @@ trait L1FunctionCallInterpreter
105105
}
106106
}
107107

108-
tryComputeFinalResult
108+
computeResult
109109
}
110110

111-
private def tryComputeFinalResult(
111+
private def computeResult(
112112
implicit
113113
state: InterpretationState,
114114
callState: CallState
@@ -172,7 +172,7 @@ trait L1FunctionCallInterpreter
172172
case EUBP(_, _: StringConstancyProperty) =>
173173
val contextEPS = eps.asInstanceOf[EOptionP[VariableDefinition, StringConstancyProperty]]
174174
callState.updateReturnDependee(contextEPS.e.m, contextEPS)
175-
tryComputeFinalResult(state, callState)
175+
computeResult(state, callState)
176176

177177
case _ => throw new IllegalArgumentException(s"Encountered unknown eps: $eps")
178178
}

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/string/l1/interpretation/L1NonVirtualFunctionCallInterpreter.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ case class L1NonVirtualFunctionCallInterpreter()(
3535
val target = expr.receiver.asVar.toPersistentForm(state.tac.stmts)
3636
val calleeMethod = expr.resolveCallTarget(state.dm.definedMethod.classFile.thisType)
3737
if (calleeMethod.isEmpty) {
38-
return failure(target)
38+
return StringInterpreter.uninterpretedCall(
39+
expr,
40+
expr.receiverOption.map { _.asVar.toPersistentForm(state.tac.stmts) }
41+
)
3942
}
4043

4144
val m = calleeMethod.value

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/string/l1/interpretation/L1NonVirtualMethodCallInterpreter.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ case class L1NonVirtualMethodCallInterpreter()(
2828

2929
override def interpret(call: T)(implicit state: InterpretationState): ProperPropertyComputationResult = {
3030
call.name match {
31-
case "<init>" if isStringBuilderBufferCall(call) || (call.declaringClass eq ClassType.String) =>
31+
case "<init>"
32+
if StringInterpreter.isStringBuilderBufferCall(call) || (call.declaringClass eq ClassType.String) =>
3233
interpretInit(call)
3334
case _ =>
34-
computeFinalResult(StringFlowFunctionProperty.identity)
35+
StringInterpreter.uninterpretedCall(call)
3536
}
3637
}
3738

@@ -49,7 +50,7 @@ case class L1NonVirtualMethodCallInterpreter()(
4950
(env: StringTreeEnvironment) => env.update(pc, targetVar, env(pc, paramVar))
5051
)
5152
case _ =>
52-
failure(targetVar)
53+
StringInterpreter.uninterpretedCall(init)
5354
}
5455
}
5556
}

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/string/l1/interpretation/L1StaticFunctionCallInterpreter.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ case class L1StaticFunctionCallInterpreter()(
4848
case _
4949
if (call.descriptor.returnType eq ClassType.String) || (call.descriptor.returnType eq ClassType.Object) =>
5050
interpretArbitraryCall(target, call)
51-
case _ => failure(target)
51+
case _ => StringInterpreter.uninterpretedCall(call, Some(target))
5252
}
5353
}
5454
}
@@ -67,7 +67,7 @@ private[string] trait L1ArbitraryStaticFunctionCallInterpreter
6767
): ProperPropertyComputationResult = {
6868
val calleeMethod = call.resolveCallTarget(state.dm.definedMethod.classFile.thisType)
6969
if (calleeMethod.isEmpty) {
70-
return failure(target)
70+
return StringInterpreter.uninterpretedCall(call, Some(target))
7171
}
7272

7373
val m = calleeMethod.value

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/string/l1/interpretation/L1VirtualFunctionCallInterpreter.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ class L1VirtualFunctionCallInterpreter(
5252
val pt = call.receiver.asVar.toPersistentForm(state.tac.stmts)
5353

5454
call.name match {
55-
case "append" if isStringBuilderBufferCall(call) => interpretAppendCall(at, pt, call)
56-
case "toString" => interpretToStringCall(at, pt)
57-
case "replace" if isStringBuilderBufferCall(call) => interpretReplaceCall(pt)
55+
case "append" if StringInterpreter.isStringBuilderBufferCall(call) => interpretAppendCall(at, pt, call)
56+
case "toString" => interpretToStringCall(at, pt)
57+
case "replace" if StringInterpreter.isStringBuilderBufferCall(call) => interpretReplaceCall(pt)
5858
case "substring" if call.descriptor.returnType eq ClassType.String =>
5959
interpretSubstringCall(at, pt, call)
6060
case _ =>
@@ -76,7 +76,7 @@ class L1VirtualFunctionCallInterpreter(
7676
case _ if at.isDefined =>
7777
interpretArbitraryCall(at.get, call)
7878
case _ =>
79-
computeFinalResult(StringFlowFunctionProperty.identity)
79+
StringInterpreter.uninterpretedCall(call)
8080
}
8181
}
8282
}

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/string/l1/interpretation/L1VirtualMethodCallInterpreter.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ case class L1VirtualMethodCallInterpreter()(
3131
val pReceiver = call.receiver.asVar.toPersistentForm(state.tac.stmts)
3232

3333
call.name match {
34-
case "setLength" if isStringBuilderBufferCall(call) =>
34+
case "setLength" if StringInterpreter.isStringBuilderBufferCall(call) =>
3535
call.params.head.asVar.value match {
3636
case TheIntegerValue(intVal) if intVal == 0 =>
3737
computeFinalResult(StringFlowFunctionProperty.constForVariableAt(
@@ -63,7 +63,7 @@ case class L1VirtualMethodCallInterpreter()(
6363
}
6464

6565
case _ =>
66-
computeFinalResult(StringFlowFunctionProperty.identity)
66+
StringInterpreter.uninterpretedCall(call)
6767
}
6868
}
6969
}

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/string/l3/interpretation/L3FieldReadInterpreter.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,10 @@ class L3FieldReadInterpreter(
153153

154154
accessState.fieldAccessDependee = accessDependee
155155

156-
tryComputeFinalResult
156+
computeResult
157157
}
158158

159-
private def tryComputeFinalResult(implicit
159+
private def computeResult(implicit
160160
accessState: FieldReadState,
161161
state: InterpretationState
162162
): ProperPropertyComputationResult = {
@@ -214,7 +214,7 @@ class L3FieldReadInterpreter(
214214

215215
case UBP(_: StringConstancyProperty) =>
216216
accessState.updateAccessDependee(eps.asInstanceOf[EOptionP[VariableDefinition, StringConstancyProperty]])
217-
tryComputeFinalResult(accessState, state)
217+
computeResult(accessState, state)
218218

219219
case _ => throw new IllegalArgumentException(s"Encountered unknown eps: $eps")
220220
}

OPAL/tac/src/main/scala/org/opalj/tac/fpcf/properties/string/StringFlowFunction.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ object StringFlowFunctionProperty extends StringFlowFunctionPropertyMetaInformat
6464

6565
def constForAll(result: StringTreeNode): StringFlowFunctionProperty =
6666
StringFlowFunctionProperty(Set.empty[PDUWeb], ConstForAllFlow(result))
67+
68+
def constForEntities(pc: Int, entities: Iterable[PV], result: StringTreeNode): StringFlowFunction = {
69+
(env: StringTreeEnvironment) =>
70+
{
71+
var updatedEnv = env
72+
entities.foreach { p => updatedEnv = updatedEnv.update(pc, p, result) }
73+
updatedEnv
74+
}
75+
}
6776
}
6877

6978
trait StringFlowFunction extends (StringTreeEnvironment => StringTreeEnvironment)

0 commit comments

Comments
 (0)