Skip to content

Commit 3d26899

Browse files
committed
Fixes for analysis of reflection and Unsafe
* Refactored the list of fields that can't be accessed via reflection to use the single rules for all cases (engine, concrete executor, codegen) * Updated this list for Java 11 classes * Added a check to avoid marking reflection-inaccessible static fields as meaningful (they can't be reflexively created by the codegen anyway) * Added `jdk.internal` to the list of system packages to avoid mocking, disabled mocking for classes that can't be accessed via reflection * Added a wrapper for `SecurityManager` and override for two related methods in [Class]
1 parent f20fafa commit 3d26899

File tree

18 files changed

+225
-26
lines changed

18 files changed

+225
-26
lines changed

utbot-core/src/main/kotlin/org/utbot/common/ReflectionUtil.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,4 @@ inline fun <reified R> Field.withAccessibility(block: () -> R): R {
7272
isAccessible = prevAccessibility
7373
setModifiers(this, prevModifiers)
7474
}
75-
}
75+
}

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,7 @@ open class FieldId(val declaringClass: ClassId, val name: String) {
922922
return result
923923
}
924924

925-
override fun toString() = safeJField.toString()
925+
override fun toString() = safeJField?.toString() ?: "[unresolved] $declaringClass.$name"
926926
}
927927

928928
inline fun <T> withReflection(block: () -> T): T {

utbot-framework/src/main/java/org/utbot/engine/overrides/Class.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,14 @@ public class Class {
77
public static boolean desiredAssertionStatus() {
88
return true;
99
}
10+
11+
private void checkMemberAccess(SecurityManager sm, int which,
12+
java.lang.Class<?> caller, boolean checkProxyInterfaces) {
13+
// Do nothing to allow everything
14+
}
15+
16+
private void checkPackageAccess(SecurityManager sm, final ClassLoader ccl,
17+
boolean checkProxyInterfaces) {
18+
// Do nothing to allow everything
19+
}
1020
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.utbot.engine.overrides.security;
2+
3+
import java.security.Permission;
4+
5+
/**
6+
* Overridden implementation for [java.lang.SecurityManager] class
7+
*/
8+
public class UtSecurityManager {
9+
public void checkPermission(Permission perm) {
10+
// Do nothing to allow everything
11+
}
12+
13+
public void checkPackageAccess(String pkg) {
14+
// Do nothing to allow everything
15+
}
16+
}

utbot-framework/src/main/kotlin/org/utbot/engine/MockStrategy.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ private val systemPackages = setOf(
4545
"sun.reflect", // we cannot mock Reflection since mockers are using it during the execution
4646
"java.awt",
4747
"sun.misc",
48+
"jdk.internal",
4849
"kotlin.jvm.internal",
4950
"kotlin.internal"
5051
)

utbot-framework/src/main/kotlin/org/utbot/engine/Mocks.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import kotlin.reflect.KFunction2
1919
import kotlin.reflect.KFunction5
2020
import kotlinx.collections.immutable.persistentListOf
2121
import org.utbot.engine.util.mockListeners.MockListenerController
22+
import org.utbot.framework.util.isInaccessibleViaReflection
2223
import soot.BooleanType
2324
import soot.RefType
2425
import soot.Scene
@@ -183,6 +184,7 @@ class Mocker(
183184
if (isUtMockAssume(mockInfo)) return false // never mock UtMock.assume invocation
184185
if (isUtMockAssumeOrExecuteConcretely(mockInfo)) return false // never mock UtMock.assumeOrExecuteConcretely invocation
185186
if (isOverriddenClass(type)) return false // never mock overriden classes
187+
if (type.isInaccessibleViaReflection) return false // never mock classes that we can't process with reflection
186188
if (isMakeSymbolic(mockInfo)) return true // support for makeSymbolic
187189
if (type.sootClass.isArtificialEntity) return false // never mock artificial types, i.e. Maps$lambda_computeValue_1__7
188190
if (!isEngineClass(type) && (type.sootClass.isInnerClass || type.sootClass.isLocal || type.sootClass.isAnonymous)) return false // there is no reason (and maybe no possibility) to mock such classes

utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import org.utbot.engine.overrides.collections.AssociativeArray
1313
import org.utbot.engine.overrides.collections.RangeModifiableUnlimitedArray
1414
import org.utbot.engine.overrides.collections.UtHashMap
1515
import org.utbot.engine.overrides.collections.UtHashSet
16+
import org.utbot.engine.overrides.security.UtSecurityManager
1617
import org.utbot.engine.overrides.strings.UtNativeString
1718
import org.utbot.engine.overrides.strings.UtString
1819
import org.utbot.engine.overrides.strings.UtStringBuffer
@@ -86,6 +87,8 @@ val classToWrapper: MutableMap<TypeToBeWrapped, WrapperType> =
8687
putSootClass(java.util.stream.BaseStream::class, UT_STREAM.className)
8788
putSootClass(java.util.stream.Stream::class, UT_STREAM.className)
8889
// TODO primitive streams https://github.com/UnitTestBot/UTBotJava/issues/146
90+
91+
putSootClass(java.lang.SecurityManager::class, utSecurityManagerClass)
8992
}
9093

9194
/**
@@ -187,6 +190,9 @@ private val wrappers = mapOf(
187190
wrap(java.util.stream.BaseStream::class) { _, addr -> objectValue(STREAM_TYPE, addr, CommonStreamWrapper()) },
188191
wrap(java.util.stream.Stream::class) { _, addr -> objectValue(STREAM_TYPE, addr, CommonStreamWrapper()) },
189192
// TODO primitive streams https://github.com/UnitTestBot/UTBotJava/issues/146
193+
194+
// Security-related wrappers
195+
wrap(SecurityManager::class) { type, addr -> objectValue(type, addr, SecurityManagerWrapper()) },
190196
).also {
191197
// check every `wrapped` class has a corresponding value in [classToWrapper]
192198
it.keys.all { key ->
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.utbot.engine
2+
3+
import org.utbot.engine.overrides.security.UtSecurityManager
4+
import org.utbot.framework.plugin.api.UtAssembleModel
5+
import org.utbot.framework.plugin.api.UtModel
6+
import org.utbot.framework.plugin.api.UtStatementModel
7+
import org.utbot.framework.plugin.api.classId
8+
import org.utbot.framework.util.nextModelName
9+
import soot.Scene
10+
import soot.SootClass
11+
import soot.SootMethod
12+
13+
val utSecurityManagerClass: SootClass
14+
get() = Scene.v().getSootClass(UtSecurityManager::class.qualifiedName)
15+
16+
class SecurityManagerWrapper : BaseOverriddenWrapper(utSecurityManagerClass.name) {
17+
private val baseModelName: String = "securityManager"
18+
19+
override fun Traverser.overrideInvoke(
20+
wrapper: ObjectValue,
21+
method: SootMethod,
22+
parameters: List<SymbolicValue>
23+
): List<InvokeResult>? {
24+
// We currently do not overload any [SecurityManager] method symbolically
25+
return null
26+
}
27+
28+
override fun value(resolver: Resolver, wrapper: ObjectValue): UtModel = resolver.run {
29+
val classId = wrapper.type.classId
30+
val addr = holder.concreteAddr(wrapper.addr)
31+
val modelName = nextModelName(baseModelName)
32+
33+
val instantiationChain = mutableListOf<UtStatementModel>()
34+
val modificationChain = mutableListOf<UtStatementModel>()
35+
return UtAssembleModel(addr, classId, modelName, instantiationChain, modificationChain)
36+
}
37+
}

utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ import org.utbot.framework.plugin.api.util.signature
9898
import org.utbot.framework.plugin.api.util.utContext
9999
import org.utbot.framework.util.executableId
100100
import org.utbot.framework.util.graph
101+
import org.utbot.framework.util.isInaccessibleViaReflection
101102
import java.lang.reflect.ParameterizedType
102103
import kotlin.collections.plus
103104
import kotlin.collections.plusAssign
@@ -631,7 +632,7 @@ class Traverser(
631632

632633
// so, we have to make an update for the local $r0
633634

634-
return if (stmt is JAssignStmt) {
635+
return if (stmt is JAssignStmt && stmt.leftOp is JimpleLocal) {
635636
val local = stmt.leftOp as JimpleLocal
636637

637638
localMemoryUpdate(local.variable to symbolicValue)
@@ -1798,6 +1799,8 @@ class Traverser(
17981799
*/
17991800
private fun isStaticFieldMeaningful(field: SootField) =
18001801
!Modifier.isSynthetic(field.modifiers) &&
1802+
// we don't want to set fields that cannot be set via reflection anyway
1803+
!field.fieldId.isInaccessibleViaReflection &&
18011804
// we don't want to set fields from library classes
18021805
!workaround(IGNORE_STATICS_FROM_TRUSTED_LIBRARIES) {
18031806
ignoreStaticsFromTrustedLibraries && field.declaringClass.isFromTrustedLibrary()

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ import org.utbot.framework.codegen.model.util.equalTo
7070
import org.utbot.framework.codegen.model.util.get
7171
import org.utbot.framework.codegen.model.util.inc
7272
import org.utbot.framework.codegen.model.util.isAccessibleFrom
73-
import org.utbot.framework.codegen.model.util.isInaccessible
7473
import org.utbot.framework.codegen.model.util.length
7574
import org.utbot.framework.codegen.model.util.lessThan
7675
import org.utbot.framework.codegen.model.util.nullLiteral
@@ -139,6 +138,7 @@ import org.utbot.framework.plugin.api.util.objectClassId
139138
import org.utbot.framework.plugin.api.util.stringClassId
140139
import org.utbot.framework.plugin.api.util.voidClassId
141140
import org.utbot.framework.plugin.api.util.wrapIfPrimitive
141+
import org.utbot.framework.util.isInaccessibleViaReflection
142142
import org.utbot.framework.util.isUnit
143143
import org.utbot.summary.SummarySentenceConstants.TAB
144144
import java.lang.reflect.InvocationTargetException
@@ -273,7 +273,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
273273
}
274274
}
275275

276-
private fun <E> Map<FieldId, E>.accessibleFields(): Map<FieldId, E> = filterKeys { !it.isInaccessible }
276+
private fun <E> Map<FieldId, E>.accessibleFields(): Map<FieldId, E> = filterKeys { !it.isInaccessibleViaReflection }
277277

278278
/**
279279
* @return expression for [java.lang.Class] of the given [classId]

0 commit comments

Comments
 (0)