[KLIB] API 4 ABI: Fail with adequate errors on non-existing/malformed KLIBs

^KT-64395
This commit is contained in:
Dmitriy Dolovov
2024-01-08 14:04:22 +01:00
committed by Space Team
parent dd85a81d45
commit dcf1c7e61d
7 changed files with 87 additions and 5 deletions
@@ -0,0 +1 @@
this is a malformed klib
@@ -0,0 +1 @@
this is a malformed klib
@@ -0,0 +1 @@
this is a malformed klib
@@ -0,0 +1,6 @@
abi_version=1.8.0
builtins_platform=JS
compiler_version=2.0.0
ir_signature_versions=1,2
metadata_version=1.4.1
unique_name=malformed-klib4
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.storage.CacheWithNotNullValues
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.DummyLogger
import org.jetbrains.kotlin.utils.*
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
import java.io.File
@@ -53,10 +54,14 @@ import org.jetbrains.kotlin.backend.common.serialization.IrFlags as ProtoFlags
@ExperimentalLibraryAbiReader
internal class LibraryAbiReaderImpl(libraryFile: File, filters: List<AbiReadingFilter>) {
private val library = resolveSingleFileKlib(
KFile(libraryFile.absolutePath),
strategy = ToolingSingleFileKlibResolveStrategy
)
private val library: KotlinLibrary = try {
ToolingSingleFileKlibResolveStrategy.tryResolve(KFile(libraryFile.absolutePath), DummyLogger)?.apply {
check(uniqueName.isNotEmpty()) { "Can't read unique name from manifest" }
check(hasIr) { "Library does not have IR" }
}
} catch (e: Exception) {
throw malformedLibrary(libraryFile, e)
} ?: error("Library not found: $libraryFile")
private val compositeFilter: AbiReadingFilter.Composite? = if (filters.isNotEmpty()) AbiReadingFilter.Composite(filters) else null
@@ -86,6 +91,9 @@ internal class LibraryAbiReaderImpl(libraryFile: File, filters: List<AbiReadingF
private fun readSupportedSignatureVersions(): Set<AbiSignatureVersion> {
return library.versions.irSignatureVersions.mapTo(hashSetOf()) { AbiSignatureVersions.resolveByVersionNumber(it.number) }
}
private fun malformedLibrary(libraryFile: File, cause: Exception): Nothing =
throw IllegalArgumentException("Malformed library: $libraryFile", cause)
}
@ExperimentalLibraryAbiReader
@@ -0,0 +1,65 @@
/*
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.library.abi
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue
import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import java.io.File
@ExperimentalLibraryAbiReader
class MalformedKlibAbiReaderTest {
private lateinit var testDataDir: File
@BeforeEach
fun setUp() {
testDataDir = File("compiler/testData/klib/dump-abi/malformed").absoluteFile
check(testDataDir.isDirectory) { "Test data dir does not exist: $testDataDir" }
}
@Test
fun testKlibDoesNotExist() {
val nonExistingLibraries = listOf(
"nonExistingLibrary", "nonExistingLibrary.klib"
).map(testDataDir::resolve)
nonExistingLibraries.forEach { nonExistingLibrary ->
assertInvalidKlib(nonExistingLibrary)
}
}
@Test
fun testMalformedKlib() {
val malformedLibraries = listOf(
"malformed-klib1.klib",
"malformed-klib2",
"malformed-klib3",
"malformed-klib4",
).map(testDataDir::resolve)
malformedLibraries.forEach { malformedLibrary ->
assertTrue(malformedLibrary.exists()) { "Library does not exist, check the test data: $malformedLibrary" }
assertInvalidKlib(malformedLibrary)
}
}
private fun assertInvalidKlib(libraryFile: File) {
try {
LibraryAbiReader.readAbiInfo(libraryFile)
fail { "Unexpectedly successful read from invalid library $libraryFile" }
} catch (e: Exception) {
val exceptionMessage = e.message.orEmpty()
assertTrue(libraryFile.path in exceptionMessage) {
"""
Exception message does not contain library path.
Message: $exceptionMessage
Library file: $libraryFile
""".trimIndent()
}
}
}
}
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.util.DummyLogger
import org.jetbrains.kotlin.util.Logger
interface SingleFileKlibResolveStrategy {
fun interface SingleFileKlibResolveStrategy {
fun resolve(libraryFile: File, logger: Logger): KotlinLibrary
}