C++: Fixes crash happening with invalid input
Fixes crash happening when a library with the wrong extension is passed to
cc_common.create_library_to_link().
Fixes #7136
RELNOTES:none
PiperOrigin-RevId: 232268610
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java
index 59fb92b..29c577d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java
@@ -14,6 +14,8 @@
package com.google.devtools.build.lib.rules.cpp;
+import static com.google.common.base.StandardSystemProperty.LINE_SEPARATOR;
+
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
@@ -358,17 +360,64 @@
Artifact interfaceLibrary = nullIfNone(interfaceLibraryObject, Artifact.class);
Artifact notNullArtifactForIdentifier = null;
+ StringBuilder extensionErrorsBuilder = new StringBuilder();
+ String extensionErrorMessage = "does not have any of the allowed extensions";
if (staticLibrary != null) {
+ String filename = staticLibrary.getFilename();
+ if (!Link.ARCHIVE_FILETYPES.matches(filename)
+ && (!alwayslink || !Link.LINK_LIBRARY_FILETYPES.matches(filename))) {
+ String extensions = Link.ARCHIVE_FILETYPES.toString();
+ if (alwayslink) {
+ extensions += ", " + Link.LINK_LIBRARY_FILETYPES;
+ }
+ extensionErrorsBuilder.append(
+ String.format("'%s' %s %s", filename, extensionErrorMessage, extensions));
+ extensionErrorsBuilder.append(LINE_SEPARATOR.value());
+ }
notNullArtifactForIdentifier = staticLibrary;
- } else if (picStaticLibrary != null) {
+ }
+ if (picStaticLibrary != null) {
+ String filename = picStaticLibrary.getFilename();
+ if (!Link.ARCHIVE_FILETYPES.matches(filename)
+ && (!alwayslink || !Link.LINK_LIBRARY_FILETYPES.matches(filename))) {
+ String extensions = Link.ARCHIVE_FILETYPES.toString();
+ if (alwayslink) {
+ extensions += ", " + Link.LINK_LIBRARY_FILETYPES;
+ }
+ extensionErrorsBuilder.append(
+ String.format("'%s' %s %s", filename, extensionErrorMessage, extensions));
+ extensionErrorsBuilder.append(LINE_SEPARATOR.value());
+ }
notNullArtifactForIdentifier = picStaticLibrary;
- } else if (dynamicLibrary != null) {
+ }
+ if (dynamicLibrary != null) {
+ String filename = dynamicLibrary.getFilename();
+ if (!Link.ONLY_SHARED_LIBRARY_FILETYPES.matches(filename)) {
+ extensionErrorsBuilder.append(
+ String.format(
+ "'%s' %s %s", filename, extensionErrorMessage, Link.ONLY_SHARED_LIBRARY_FILETYPES));
+ extensionErrorsBuilder.append(LINE_SEPARATOR.value());
+ }
notNullArtifactForIdentifier = dynamicLibrary;
- } else if (interfaceLibrary != null) {
+ }
+ if (interfaceLibrary != null) {
+ String filename = interfaceLibrary.getFilename();
+ if (!Link.ONLY_INTERFACE_LIBRARY_FILETYPES.matches(filename)) {
+ extensionErrorsBuilder.append(
+ String.format(
+ "'%s' %s %s",
+ filename, extensionErrorMessage, Link.ONLY_INTERFACE_LIBRARY_FILETYPES));
+ extensionErrorsBuilder.append(LINE_SEPARATOR.value());
+ }
notNullArtifactForIdentifier = interfaceLibrary;
- } else {
+ }
+ if (notNullArtifactForIdentifier == null) {
throw new EvalException(location, "Must pass at least one artifact");
}
+ String extensionErrors = extensionErrorsBuilder.toString();
+ if (!extensionErrors.isEmpty()) {
+ throw new EvalException(location, extensionErrors);
+ }
Artifact resolvedSymlinkDynamicLibrary = null;
Artifact resolvedSymlinkInterfaceLibrary = null;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java
index 54c0aca..a029a9d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java
@@ -40,6 +40,12 @@
CppFileTypes.VERSIONED_SHARED_LIBRARY,
CppFileTypes.INTERFACE_SHARED_LIBRARY);
+ public static final FileTypeSet ONLY_SHARED_LIBRARY_FILETYPES =
+ FileTypeSet.of(CppFileTypes.SHARED_LIBRARY, CppFileTypes.VERSIONED_SHARED_LIBRARY);
+
+ public static final FileTypeSet ONLY_INTERFACE_LIBRARY_FILETYPES =
+ FileTypeSet.of(CppFileTypes.INTERFACE_SHARED_LIBRARY);
+
public static final FileTypeSet ARCHIVE_LIBRARY_FILETYPES = FileTypeSet.of(
CppFileTypes.ARCHIVE,
CppFileTypes.PIC_ARCHIVE,
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTest.java
index 1fc345b..a9c598f 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTest.java
@@ -4676,4 +4676,34 @@
assertThat(toolchainResolutionEnabled()).isTrue();
}
+
+ @Test
+ public void testWrongExtensionThrowsError() throws Exception {
+ setUpCcLinkingContextTest();
+ scratch.file(
+ "foo/BUILD",
+ "load('//tools/build_defs/cc:rule.bzl', 'crule')",
+ "cc_binary(name='bin',",
+ " deps = [':a'],",
+ ")",
+ "crule(name='a',",
+ " static_library = 'a.o',",
+ " pic_static_library = 'a.pic.o',",
+ " dynamic_library = 'a.ifso',",
+ " interface_library = 'a.so',",
+ ")");
+ AssertionError e = assertThrows(AssertionError.class, () -> getConfiguredTarget("//foo:bin"));
+ assertThat(e)
+ .hasMessageThat()
+ .contains("'a.o' does not have any of the allowed extensions .a, .lib or .pic.a");
+ assertThat(e)
+ .hasMessageThat()
+ .contains("'a.pic.o' does not have any of the allowed extensions .a, .lib or .pic.a");
+ assertThat(e)
+ .hasMessageThat()
+ .contains("'a.ifso' does not have any of the allowed extensions .so, .dylib or .dll");
+ assertThat(e)
+ .hasMessageThat()
+ .contains("'a.so' does not have any of the allowed extensions .ifso, .tbd or .lib");
+ }
}