From dcf1c7e61d7647a95114ce7f007a0c614a670c4a Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Mon, 8 Jan 2024 14:04:22 +0100 Subject: [PATCH] [KLIB] API 4 ABI: Fail with adequate errors on non-existing/malformed KLIBs ^KT-64395 --- .../dump-abi/malformed/malformed-klib1.klib | 1 + .../malformed-klib2/default/no-manifest | 1 + .../malformed-klib3/default/manifest | 1 + .../malformed-klib4/default/manifest | 6 ++ .../library/abi/impl/LibraryAbiReaderImpl.kt | 16 +++-- .../library/abi/MalformedKlibAbiReaderTest.kt | 65 +++++++++++++++++++ .../kotlin/library/SingleFileResolve.kt | 2 +- 7 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/klib/dump-abi/malformed/malformed-klib1.klib create mode 100644 compiler/testData/klib/dump-abi/malformed/malformed-klib2/default/no-manifest create mode 100644 compiler/testData/klib/dump-abi/malformed/malformed-klib3/default/manifest create mode 100644 compiler/testData/klib/dump-abi/malformed/malformed-klib4/default/manifest create mode 100644 compiler/util-klib-abi/tests-gen/org/jetbrains/kotlin/library/abi/MalformedKlibAbiReaderTest.kt diff --git a/compiler/testData/klib/dump-abi/malformed/malformed-klib1.klib b/compiler/testData/klib/dump-abi/malformed/malformed-klib1.klib new file mode 100644 index 00000000000..4af8e7452e7 --- /dev/null +++ b/compiler/testData/klib/dump-abi/malformed/malformed-klib1.klib @@ -0,0 +1 @@ +this is a malformed klib diff --git a/compiler/testData/klib/dump-abi/malformed/malformed-klib2/default/no-manifest b/compiler/testData/klib/dump-abi/malformed/malformed-klib2/default/no-manifest new file mode 100644 index 00000000000..4af8e7452e7 --- /dev/null +++ b/compiler/testData/klib/dump-abi/malformed/malformed-klib2/default/no-manifest @@ -0,0 +1 @@ +this is a malformed klib diff --git a/compiler/testData/klib/dump-abi/malformed/malformed-klib3/default/manifest b/compiler/testData/klib/dump-abi/malformed/malformed-klib3/default/manifest new file mode 100644 index 00000000000..4af8e7452e7 --- /dev/null +++ b/compiler/testData/klib/dump-abi/malformed/malformed-klib3/default/manifest @@ -0,0 +1 @@ +this is a malformed klib diff --git a/compiler/testData/klib/dump-abi/malformed/malformed-klib4/default/manifest b/compiler/testData/klib/dump-abi/malformed/malformed-klib4/default/manifest new file mode 100644 index 00000000000..f98127328e6 --- /dev/null +++ b/compiler/testData/klib/dump-abi/malformed/malformed-klib4/default/manifest @@ -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 diff --git a/compiler/util-klib-abi/src/org/jetbrains/kotlin/library/abi/impl/LibraryAbiReaderImpl.kt b/compiler/util-klib-abi/src/org/jetbrains/kotlin/library/abi/impl/LibraryAbiReaderImpl.kt index 7a561ad8fcc..8c2a48b5957 100644 --- a/compiler/util-klib-abi/src/org/jetbrains/kotlin/library/abi/impl/LibraryAbiReaderImpl.kt +++ b/compiler/util-klib-abi/src/org/jetbrains/kotlin/library/abi/impl/LibraryAbiReaderImpl.kt @@ -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) { - 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 { 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 diff --git a/compiler/util-klib-abi/tests-gen/org/jetbrains/kotlin/library/abi/MalformedKlibAbiReaderTest.kt b/compiler/util-klib-abi/tests-gen/org/jetbrains/kotlin/library/abi/MalformedKlibAbiReaderTest.kt new file mode 100644 index 00000000000..cfdc0929491 --- /dev/null +++ b/compiler/util-klib-abi/tests-gen/org/jetbrains/kotlin/library/abi/MalformedKlibAbiReaderTest.kt @@ -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() + } + } + } +} diff --git a/compiler/util-klib/src/org/jetbrains/kotlin/library/SingleFileResolve.kt b/compiler/util-klib/src/org/jetbrains/kotlin/library/SingleFileResolve.kt index 068f714b9e7..e07cc415b0c 100644 --- a/compiler/util-klib/src/org/jetbrains/kotlin/library/SingleFileResolve.kt +++ b/compiler/util-klib/src/org/jetbrains/kotlin/library/SingleFileResolve.kt @@ -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 }