mirror of
https://github.com/ReVanced/revanced-patcher.git
synced 2024-11-10 01:02:22 +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
bbb2c547aa
commit
674461f08d
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 {
|
||||
fun resolveMethod(classNode: ClassNode, signature: Signature): PatchData? {
|
||||
for (method in classNode.methods) {
|
||||
val (r, sr) = cmp(method, signature, true)
|
||||
val (r, sr) = cmp(method, signature)
|
||||
if (!r || sr == null) continue
|
||||
return PatchData(
|
||||
classNode,
|
||||
|
@ -67,52 +67,55 @@ internal class MethodResolver(private val classList: List<ClassNode>, private va
|
|||
return null
|
||||
}
|
||||
|
||||
private fun cmp(method: MethodNode, signature: Signature, search: Boolean = false): Pair<Boolean, ScanResult?> {
|
||||
val returns = Type.getReturnType(method.desc).convertObject()
|
||||
if (signature.returns != returns) {
|
||||
logger.debug {
|
||||
"""
|
||||
Comparing sig ${signature.name}: invalid return type:
|
||||
expected ${signature.returns}},
|
||||
got $returns
|
||||
""".trimIndent()
|
||||
private fun cmp(method: MethodNode, signature: Signature): Pair<Boolean, ScanResult?> {
|
||||
signature.returns?.let { _ ->
|
||||
val methodReturns = Type.getReturnType(method.desc).convertObject()
|
||||
if (signature.returns != methodReturns) {
|
||||
logger.debug {
|
||||
"""
|
||||
Comparing sig ${signature.name}: invalid return type:
|
||||
expected ${signature.returns},
|
||||
got $methodReturns
|
||||
""".trimIndent()
|
||||
}
|
||||
return@cmp false to null
|
||||
}
|
||||
return false to null
|
||||
}
|
||||
|
||||
if (signature.accessors != method.access) {
|
||||
logger.debug {
|
||||
"""
|
||||
Comparing sig ${signature.name}: invalid accessors:
|
||||
expected ${signature.accessors}},
|
||||
got ${method.access}
|
||||
""".trimIndent()
|
||||
signature.accessors?.let { _ ->
|
||||
if (signature.accessors != method.access) {
|
||||
logger.debug {
|
||||
"""
|
||||
Comparing sig ${signature.name}: invalid accessors:
|
||||
expected ${signature.accessors},
|
||||
got ${method.access}
|
||||
""".trimIndent()
|
||||
}
|
||||
return@cmp false to null
|
||||
}
|
||||
return false to null
|
||||
}
|
||||
|
||||
val parameters = Type.getArgumentTypes(method.desc).convertObjects()
|
||||
if (!signature.parameters.contentEquals(parameters)) {
|
||||
logger.debug {
|
||||
"""
|
||||
Comparing sig ${signature.name}: invalid parameter types:
|
||||
expected ${signature.parameters.joinToString()}},
|
||||
got ${parameters.joinToString()}
|
||||
""".trimIndent()
|
||||
signature.parameters?.let { _ ->
|
||||
val parameters = Type.getArgumentTypes(method.desc).convertObjects()
|
||||
if (!signature.parameters.contentEquals(parameters)) {
|
||||
logger.debug {
|
||||
"""
|
||||
Comparing sig ${signature.name}: invalid parameter types:
|
||||
expected ${signature.parameters.joinToString()}},
|
||||
got ${parameters.joinToString()}
|
||||
""".trimIndent()
|
||||
}
|
||||
return@cmp false to null
|
||||
}
|
||||
return false to null
|
||||
}
|
||||
|
||||
if (!search) {
|
||||
if (signature.opcodes.isEmpty()) {
|
||||
throw IllegalArgumentException("Opcode list for signature ${signature.name} is empty. This is not allowed for non-search signatures.")
|
||||
}
|
||||
signature.opcodes?.let { _ ->
|
||||
val result = method.instructions.scanFor(signature.opcodes)
|
||||
if (!result.found) {
|
||||
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)
|
||||
|
|
|
@ -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.
|
||||
* If you are unable to guess a method name, doing something like "patch-name-1" is fine too.
|
||||
* 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,
|
||||
* 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 accessors The accessors 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.
|
||||
* ***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")
|
||||
data class Signature(
|
||||
val name: String,
|
||||
val returns: Type,
|
||||
val accessors: Int,
|
||||
val parameters: Array<Type>,
|
||||
val opcodes: Array<Int>
|
||||
val returns: Type?,
|
||||
val accessors: Int?,
|
||||
val parameters: Array<Type>?,
|
||||
val opcodes: Array<Int>?
|
||||
)
|
|
@ -9,13 +9,12 @@ import net.revanced.patcher.util.ExtraTypes
|
|||
import net.revanced.patcher.util.TestUtil
|
||||
import net.revanced.patcher.writer.ASMWriter.insertAt
|
||||
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.Type
|
||||
import org.objectweb.asm.tree.*
|
||||
import java.io.PrintStream
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class PatcherTest {
|
||||
companion object {
|
||||
|
@ -149,25 +148,21 @@ internal class PatcherTest {
|
|||
//}
|
||||
|
||||
@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 e = assertThrows<IllegalArgumentException>("Should raise an exception because opcodes is empty") {
|
||||
|
||||
assertDoesNotThrow("Should raise an exception because opcodes is empty") {
|
||||
Patcher(
|
||||
PatcherTest::class.java.getResourceAsStream("/test1.jar")!!,
|
||||
arrayOf(
|
||||
Signature(
|
||||
sigName,
|
||||
Type.VOID_TYPE,
|
||||
ACC_PUBLIC or ACC_STATIC,
|
||||
arrayOf(ExtraTypes.ArrayAny),
|
||||
emptyArray() // this is not allowed for non-search signatures!
|
||||
)
|
||||
)
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
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