angryziber / kotlin-puzzlers

A collection of Kotlin Puzzlers
419 stars 58 forks source link

Puzzlers with instance of Nothing class #56

Closed rpuxa closed 4 years ago

rpuxa commented 5 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

angryziber commented 4 years ago

Thanks, that's a fun one!