Reject bytecode manipulating with uninitialized values on stack
NB this will break parcel-related tests in android-extensions compiler plugin
This commit is contained in:
+14
-2
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.coroutines
|
package org.jetbrains.kotlin.codegen.coroutines
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.insnText
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.*
|
import org.jetbrains.kotlin.codegen.optimization.common.*
|
||||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
|
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
@@ -76,7 +77,7 @@ class UninitializedStoresProcessor(private val methodNode: MethodNode, private v
|
|||||||
private val isInSpecialMethod = methodNode.name == "<init>" || methodNode.name == "<clinit>"
|
private val isInSpecialMethod = methodNode.name == "<init>" || methodNode.name == "<clinit>"
|
||||||
|
|
||||||
fun run() {
|
fun run() {
|
||||||
val interpreter = UninitializedNewValueMarkerInterpreter()
|
val interpreter = UninitializedNewValueMarkerInterpreter(methodNode.instructions)
|
||||||
|
|
||||||
val frames = CustomFramesMethodAnalyzer(
|
val frames = CustomFramesMethodAnalyzer(
|
||||||
"fake", methodNode, interpreter,
|
"fake", methodNode, interpreter,
|
||||||
@@ -190,7 +191,7 @@ class UninitializedStoresProcessor(private val methodNode: MethodNode, private v
|
|||||||
|
|
||||||
private fun AbstractInsnNode.isConstructorCall() = this is MethodInsnNode && this.name == "<init>"
|
private fun AbstractInsnNode.isConstructorCall() = this is MethodInsnNode && this.name == "<init>"
|
||||||
|
|
||||||
private class UninitializedNewValueMarkerInterpreter : OptimizationBasicInterpreter() {
|
private class UninitializedNewValueMarkerInterpreter(private val instructions: InsnList) : OptimizationBasicInterpreter() {
|
||||||
val uninitializedValuesToCopyUsages = hashMapOf<AbstractInsnNode, MutableSet<AbstractInsnNode>>()
|
val uninitializedValuesToCopyUsages = hashMapOf<AbstractInsnNode, MutableSet<AbstractInsnNode>>()
|
||||||
override fun newOperation(insn: AbstractInsnNode): BasicValue? {
|
override fun newOperation(insn: AbstractInsnNode): BasicValue? {
|
||||||
if (insn.opcode == Opcodes.NEW) {
|
if (insn.opcode == Opcodes.NEW) {
|
||||||
@@ -202,6 +203,7 @@ class UninitializedStoresProcessor(private val methodNode: MethodNode, private v
|
|||||||
|
|
||||||
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? {
|
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? {
|
||||||
if (value is UninitializedNewValue) {
|
if (value is UninitializedNewValue) {
|
||||||
|
checkUninitializedObjectCopy(value.newInsn, insn)
|
||||||
uninitializedValuesToCopyUsages[value.newInsn]!!.add(insn)
|
uninitializedValuesToCopyUsages[value.newInsn]!!.add(insn)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
@@ -225,5 +227,15 @@ class UninitializedStoresProcessor(private val methodNode: MethodNode, private v
|
|||||||
|
|
||||||
return super.merge(v, w)
|
return super.merge(v, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkUninitializedObjectCopy(newInsn: TypeInsnNode, usageInsn: AbstractInsnNode) {
|
||||||
|
when (usageInsn.opcode) {
|
||||||
|
Opcodes.DUP, Opcodes.ASTORE, Opcodes.ALOAD -> {}
|
||||||
|
else -> error("Unexpected copy instruction for ${newInsn.debugText}: ${usageInsn.debugText}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val AbstractInsnNode.debugText
|
||||||
|
get() = "${instructions.indexOf(this)}: $insnText"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user