Closed rpuxa closed 4 years ago
I found a way to get instance of Nothing class and created some puzzlers with it
1) Returning null from NotNull function
fun main() { println(thisFunctionNeverReturnsNull()) } fun thisFunctionNeverReturnsNull(): String { val unsafe = Class.forName("sun.misc.Unsafe") .declaredFields .first { it.name == "theUnsafe" } .apply { isAccessible = true } .get(null) as Unsafe unsafe.allocateInstance(Nothing::class.java) as Nothing }
2) Throwing java.lang.NPE in function (in this case "main") where nothing can thow NPE
fun main() { getNothing() } fun getNothing(): Nothing { val unsafe = Class.forName("sun.misc.Unsafe") .declaredFields .first { it.name == "theUnsafe" } .apply { isAccessible = true } .get(null) as Unsafe return unsafe.allocateInstance(Nothing::class.java) as Nothing }
3) Breaking compiler
fun main() { val unsafe = Class.forName("sun.misc.Unsafe") .declaredFields .first { it.name == "theUnsafe" } .apply { isAccessible = true } .get(null) as Unsafe val nothing = unsafe.allocateInstance(Nothing::class.java) as Nothing println(if (nothing) {}.toString()) }
this code throws java.lang.VerifyError. It means that Kotlin compiled wrong bytecode. Let's look on the wrong bytecode line:
CHECKCAST java/lang/Void ASTORE 1 ALOAD 1 INVOKEVIRTUAL kotlin/Unit.toString ()Ljava/lang/String;
As we can see, we try to invoke kotlin.Unit.toString() on java.lang.Void instance
Thanks, that's a fun one!
I found a way to get instance of Nothing class and created some puzzlers with it
1) Returning null from NotNull function
2) Throwing java.lang.NPE in function (in this case "main") where nothing can thow NPE
3) Breaking compiler
this code throws java.lang.VerifyError. It means that Kotlin compiled wrong bytecode. Let's look on the wrong bytecode line:
As we can see, we try to invoke kotlin.Unit.toString() on java.lang.Void instance