mirror of
https://github.com/ReVanced/revanced-patcher.git
synced 2024-11-13 02:14:27 +01:00
fix: nullable signature members (#10)
This commit will allow "partial" signatures, basically we will be allowed to exclude members to match for the signature
This commit is contained in:
parent
00c6ab7faf
commit
8db8893ab1
3 changed files with 51 additions and 55 deletions
|
@ -56,7 +56,7 @@ internal class MethodResolver(private val classList: List<ClassNode>, private va
|
||||||
companion object {
|
companion object {
|
||||||
fun resolveMethod(classNode: ClassNode, signature: Signature): PatchData? {
|
fun resolveMethod(classNode: ClassNode, signature: Signature): PatchData? {
|
||||||
for (method in classNode.methods) {
|
for (method in classNode.methods) {
|
||||||
val (r, sr) = cmp(method, signature, true)
|
val (r, sr) = cmp(method, signature)
|
||||||
if (!r || sr == null) continue
|
if (!r || sr == null) continue
|
||||||
return PatchData(
|
return PatchData(
|
||||||
classNode,
|
classNode,
|
||||||
|
@ -67,52 +67,55 @@ internal class MethodResolver(private val classList: List<ClassNode>, private va
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cmp(method: MethodNode, signature: Signature, search: Boolean = false): Pair<Boolean, ScanResult?> {
|
private fun cmp(method: MethodNode, signature: Signature): Pair<Boolean, ScanResult?> {
|
||||||
val returns = Type.getReturnType(method.desc).convertObject()
|
signature.returns?.let { _ ->
|
||||||
if (signature.returns != returns) {
|
val methodReturns = Type.getReturnType(method.desc).convertObject()
|
||||||
logger.debug {
|
if (signature.returns != methodReturns) {
|
||||||
"""
|
logger.debug {
|
||||||
Comparing sig ${signature.name}: invalid return type:
|
"""
|
||||||
expected ${signature.returns}},
|
Comparing sig ${signature.name}: invalid return type:
|
||||||
got $returns
|
expected ${signature.returns},
|
||||||
""".trimIndent()
|
got $methodReturns
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
return@cmp false to null
|
||||||
}
|
}
|
||||||
return false to null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signature.accessors != method.access) {
|
signature.accessors?.let { _ ->
|
||||||
logger.debug {
|
if (signature.accessors != method.access) {
|
||||||
"""
|
logger.debug {
|
||||||
Comparing sig ${signature.name}: invalid accessors:
|
"""
|
||||||
expected ${signature.accessors}},
|
Comparing sig ${signature.name}: invalid accessors:
|
||||||
got ${method.access}
|
expected ${signature.accessors},
|
||||||
""".trimIndent()
|
got ${method.access}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
return@cmp false to null
|
||||||
}
|
}
|
||||||
return false to null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val parameters = Type.getArgumentTypes(method.desc).convertObjects()
|
signature.parameters?.let { _ ->
|
||||||
if (!signature.parameters.contentEquals(parameters)) {
|
val parameters = Type.getArgumentTypes(method.desc).convertObjects()
|
||||||
logger.debug {
|
if (!signature.parameters.contentEquals(parameters)) {
|
||||||
"""
|
logger.debug {
|
||||||
Comparing sig ${signature.name}: invalid parameter types:
|
"""
|
||||||
expected ${signature.parameters.joinToString()}},
|
Comparing sig ${signature.name}: invalid parameter types:
|
||||||
got ${parameters.joinToString()}
|
expected ${signature.parameters.joinToString()}},
|
||||||
""".trimIndent()
|
got ${parameters.joinToString()}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
return@cmp false to null
|
||||||
}
|
}
|
||||||
return false to null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!search) {
|
signature.opcodes?.let { _ ->
|
||||||
if (signature.opcodes.isEmpty()) {
|
|
||||||
throw IllegalArgumentException("Opcode list for signature ${signature.name} is empty. This is not allowed for non-search signatures.")
|
|
||||||
}
|
|
||||||
val result = method.instructions.scanFor(signature.opcodes)
|
val result = method.instructions.scanFor(signature.opcodes)
|
||||||
if (!result.found) {
|
if (!result.found) {
|
||||||
logger.debug { "Comparing sig ${signature.name}: invalid opcode pattern" }
|
logger.debug { "Comparing sig ${signature.name}: invalid opcode pattern" }
|
||||||
return false to null
|
return@cmp false to null
|
||||||
}
|
}
|
||||||
return true to result
|
return@cmp true to result
|
||||||
}
|
}
|
||||||
|
|
||||||
return true to ScanResult(true)
|
return true to ScanResult(true)
|
||||||
|
|
|
@ -9,21 +9,19 @@ import org.objectweb.asm.Type
|
||||||
* Do not use the actual method name, instead try to guess what the method name originally was.
|
* Do not use the actual method name, instead try to guess what the method name originally was.
|
||||||
* If you are unable to guess a method name, doing something like "patch-name-1" is fine too.
|
* If you are unable to guess a method name, doing something like "patch-name-1" is fine too.
|
||||||
* For example: "override-codec-1".
|
* For example: "override-codec-1".
|
||||||
* This method name will be used to find the corresponding patch.
|
* This method name will be mapped to the method matching the signature.
|
||||||
* Even though this is technically not needed for the `findParentMethod` method,
|
* Even though this is technically not needed for the `findParentMethod` method,
|
||||||
* it is still recommended giving the method a name, so it can be identified easily.
|
* it is still recommended giving the method a name, so it can be identified easily.
|
||||||
* @param returns The return type/signature of the method.
|
* @param returns The return type/signature of the method.
|
||||||
* @param accessors The accessors of the method.
|
* @param accessors The accessors of the method.
|
||||||
* @param parameters The parameter types of the method.
|
* @param parameters The parameter types of the method.
|
||||||
* @param opcodes The opcode pattern of the method, used to find the method by pattern scanning.
|
* @param opcodes The opcode pattern of the method, used to find the method by pattern scanning.
|
||||||
* ***Only if*** **you are using **`findParentMethod`** are you allowed to specify an empty array.**
|
|
||||||
* This parameter will be ignored when using the `findParentMethod` method.
|
|
||||||
*/
|
*/
|
||||||
@Suppress("ArrayInDataClass")
|
@Suppress("ArrayInDataClass")
|
||||||
data class Signature(
|
data class Signature(
|
||||||
val name: String,
|
val name: String,
|
||||||
val returns: Type,
|
val returns: Type?,
|
||||||
val accessors: Int,
|
val accessors: Int?,
|
||||||
val parameters: Array<Type>,
|
val parameters: Array<Type>?,
|
||||||
val opcodes: Array<Int>
|
val opcodes: Array<Int>?
|
||||||
)
|
)
|
|
@ -9,13 +9,12 @@ import net.revanced.patcher.util.ExtraTypes
|
||||||
import net.revanced.patcher.util.TestUtil
|
import net.revanced.patcher.util.TestUtil
|
||||||
import net.revanced.patcher.writer.ASMWriter.insertAt
|
import net.revanced.patcher.writer.ASMWriter.insertAt
|
||||||
import net.revanced.patcher.writer.ASMWriter.setAt
|
import net.revanced.patcher.writer.ASMWriter.setAt
|
||||||
import org.junit.jupiter.api.assertThrows
|
import org.junit.jupiter.api.assertDoesNotThrow
|
||||||
import org.objectweb.asm.Opcodes.*
|
import org.objectweb.asm.Opcodes.*
|
||||||
import org.objectweb.asm.Type
|
import org.objectweb.asm.Type
|
||||||
import org.objectweb.asm.tree.*
|
import org.objectweb.asm.tree.*
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
|
||||||
|
|
||||||
internal class PatcherTest {
|
internal class PatcherTest {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -149,25 +148,21 @@ internal class PatcherTest {
|
||||||
//}
|
//}
|
||||||
|
|
||||||
@Test()
|
@Test()
|
||||||
fun `should raise an exception because opcodes is empty`() {
|
fun `should not raise an exception if any signature member except the name is missing`() {
|
||||||
val sigName = "testMethod"
|
val sigName = "testMethod"
|
||||||
val e = assertThrows<IllegalArgumentException>("Should raise an exception because opcodes is empty") {
|
|
||||||
|
assertDoesNotThrow("Should raise an exception because opcodes is empty") {
|
||||||
Patcher(
|
Patcher(
|
||||||
PatcherTest::class.java.getResourceAsStream("/test1.jar")!!,
|
PatcherTest::class.java.getResourceAsStream("/test1.jar")!!,
|
||||||
arrayOf(
|
arrayOf(
|
||||||
Signature(
|
Signature(
|
||||||
sigName,
|
sigName,
|
||||||
Type.VOID_TYPE,
|
null,
|
||||||
ACC_PUBLIC or ACC_STATIC,
|
null,
|
||||||
arrayOf(ExtraTypes.ArrayAny),
|
null,
|
||||||
emptyArray() // this is not allowed for non-search signatures!
|
null
|
||||||
)
|
))
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
assertEquals(
|
|
||||||
"Opcode list for signature $sigName is empty. This is not allowed for non-search signatures.",
|
|
||||||
e.message
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue