Skip to content

Commit b5ba5d6

Browse files
authored
Added hack for non-null value field in strings (#165)
1 parent 1185f3b commit b5ba5d6

3 files changed

Lines changed: 51 additions & 0 deletions

File tree

usvm-jvm/src/main/kotlin/org/usvm/machine/interpreter/JcInterpreter.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import org.usvm.api.targets.JcTarget
5151
import org.usvm.collection.array.UArrayIndexLValue
5252
import org.usvm.collection.field.UFieldLValue
5353
import org.usvm.forkblacklists.UForkBlackList
54+
import org.usvm.isStaticHeapRef
5455
import org.usvm.machine.JcApplicationGraph
5556
import org.usvm.machine.JcConcreteMethodCallInst
5657
import org.usvm.machine.JcContext
@@ -295,6 +296,12 @@ class JcInterpreter(
295296
},
296297
)
297298

299+
// TODO usvm-sbft-merge: hack to prevent NPE for the `value` field in strings
300+
handleStringValueField(
301+
scope,
302+
method,
303+
) { stmt.arguments.first().asExpr(ctx.addressSort) }
304+
298305
scope.doWithState {
299306
addNewMethodCall(stmt, entryPoint)
300307
}
@@ -322,6 +329,32 @@ class JcInterpreter(
322329
}
323330
}
324331

332+
private fun handleStringValueField(scope: JcStepScope, method: JcMethod, stringRefBlock: () -> UHeapRef) {
333+
with(ctx) {
334+
if (method.isStatic || method.isConstructor) {
335+
return
336+
}
337+
338+
val type = method.enclosingClass.toType()
339+
if (type != stringType) {
340+
return
341+
}
342+
343+
val stringThisRef = stringRefBlock()
344+
if (isStaticHeapRef(stringThisRef)) {
345+
// For string literals we set `value` explicitly
346+
return
347+
}
348+
349+
val stringValueLValue = UFieldLValue(addressSort, stringThisRef, stringValueField.field)
350+
val stringValue = scope.calcOnState { memory.read(stringValueLValue) }
351+
352+
val notNullValueConstraint = mkEq(stringValue, nullRef).not()
353+
scope.assert(notNullValueConstraint)
354+
?: error("Cannot make `java.lang.String#value` not-null for string $stringThisRef")
355+
}
356+
}
357+
325358
private inline fun handleInnerClassMethodCall(
326359
scope: JcStepScope,
327360
enclosingType: JcClassType,

usvm-jvm/src/samples/java/org/usvm/samples/strings/StringExamples.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,4 +519,12 @@ public String equalsIgnoreCase(String s) {
519519
public String listToString() {
520520
return Arrays.asList("a", "b", "c").toString();
521521
}
522+
523+
public int getSymbolicLength(String s) {
524+
if (s == null) {
525+
return -1;
526+
}
527+
528+
return s.length();
529+
}
522530
}

usvm-jvm/src/test/kotlin/org/usvm/samples/strings/StringExamplesTest.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,4 +695,14 @@ internal class StringExamplesTest : JavaMethodTestRunner() {
695695
{ _, r -> r == "[a, b, c]" },
696696
)
697697
}
698+
699+
@Test
700+
fun testGetSymbolicLength() {
701+
checkDiscoveredProperties(
702+
StringExamples::getSymbolicLength,
703+
eq(2),
704+
{ _, s, r -> s == null && r == -1 },
705+
{ _, s, r -> s != null && r == s.length },
706+
)
707+
}
698708
}

0 commit comments

Comments
 (0)