llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Aviral Goel (aviralg) <details> <summary>Changes</summary> This patch introduces `clang-ssaf-analyzer`, a new SSAF tool that runs whole-program analyses over an `LUSummary` and writes the resulting `WPASuite` to an output file. --- Patch is 35.71 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/196124.diff 22 Files Affected: - (modified) clang/lib/ScalableStaticAnalysisFramework/Tool/Utils.cpp (+4) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-badext.txt (+1) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-corrupt.json (+1) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-noext (+1) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-tags-only.json (+44) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-wrong-type.json (+1) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu.json (+126) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/all.json (+90) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/both.json (+81) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/pairs.json (+70) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/tags.json (+56) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/analyzer.test (+141) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/cli-errors.test (+53) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/help.test (+23) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/lit.local.cfg (+4) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/validation-errors-permissions.test (+28) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/validation-errors.test (+45) - (added) clang/test/Analysis/Scalable/ssaf-analyzer/version.test (+5) - (modified) clang/test/CMakeLists.txt (+1) - (modified) clang/tools/CMakeLists.txt (+1) - (added) clang/tools/clang-ssaf-analyzer/CMakeLists.txt (+25) - (added) clang/tools/clang-ssaf-analyzer/SSAFAnalyzer.cpp (+134) ``````````diff diff --git a/clang/lib/ScalableStaticAnalysisFramework/Tool/Utils.cpp b/clang/lib/ScalableStaticAnalysisFramework/Tool/Utils.cpp index 6a78620b757e6..f14f34eb3bbb0 100644 --- a/clang/lib/ScalableStaticAnalysisFramework/Tool/Utils.cpp +++ b/clang/lib/ScalableStaticAnalysisFramework/Tool/Utils.cpp @@ -136,6 +136,10 @@ llvm::StringRef clang::ssaf::getToolName() { return ToolName; } void clang::ssaf::loadPlugins(llvm::ArrayRef<std::string> Paths) { for (const std::string &PluginPath : Paths) { + if (!fs::exists(PluginPath)) { + fail(ErrorMessages::FailedToLoadPlugin, PluginPath, + ErrorMessages::PathDoesNotExist); + } std::string ErrMsg; if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(PluginPath.c_str(), &ErrMsg)) { diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-badext.txt b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-badext.txt new file mode 100644 index 0000000000000..0967ef424bce6 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-badext.txt @@ -0,0 +1 @@ +{} diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-corrupt.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-corrupt.json new file mode 100644 index 0000000000000..b22e81a41ba54 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-corrupt.json @@ -0,0 +1 @@ +{ this is not valid json } diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-noext b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-noext new file mode 100644 index 0000000000000..0967ef424bce6 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-noext @@ -0,0 +1 @@ +{} diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-tags-only.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-tags-only.json new file mode 100644 index 0000000000000..c562a25f3c55d --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-tags-only.json @@ -0,0 +1,44 @@ +{ + "data": [ + { + "summary_name": "TagsEntitySummary", + "summary_data": [ + { + "entity_id": 0, + "entity_summary": { + "tags": ["important", "public"] + } + } + ] + } + ], + "id_table": [ + { + "id": 0, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@foo#" + } + } + ], + "linkage_table": [ + { + "id": 0, + "linkage": { + "type": "External" + } + } + ], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ] +} diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-wrong-type.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-wrong-type.json new file mode 100644 index 0000000000000..b5d8bb58d9bc3 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu-wrong-type.json @@ -0,0 +1 @@ +[1, 2, 3] diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu.json new file mode 100644 index 0000000000000..9c30fefc55dd5 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Inputs/lu.json @@ -0,0 +1,126 @@ +{ + "data": [ + { + "summary_name": "TagsEntitySummary", + "summary_data": [ + { + "entity_id": 0, + "entity_summary": { + "tags": ["important", "public"] + } + }, + { + "entity_id": 1, + "entity_summary": { + "tags": ["internal", "deprecated", "important"] + } + }, + { + "entity_id": 2, + "entity_summary": { + "tags": ["public"] + } + } + ] + }, + { + "summary_name": "PairsEntitySummary", + "summary_data": [ + { + "entity_id": 0, + "entity_summary": { + "pairs": [ + {"first": {"@": 1}, "second": {"@": 2}} + ] + } + }, + { + "entity_id": 1, + "entity_summary": { + "pairs": [ + {"first": {"@": 0}, "second": {"@": 2}}, + {"first": {"@": 2}, "second": {"@": 0}} + ] + } + }, + { + "entity_id": 2, + "entity_summary": { + "pairs": [ + {"first": {"@": 0}, "second": {"@": 1}}, + {"first": {"@": 1}, "second": {"@": 0}}, + {"first": {"@": 0}, "second": {"@": 0}} + ] + } + } + ] + } + ], + "id_table": [ + { + "id": 0, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@foo#" + } + }, + { + "id": 1, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@bar#" + } + }, + { + "id": 2, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@baz#" + } + } + ], + "linkage_table": [ + { + "id": 0, + "linkage": { + "type": "External" + } + }, + { + "id": 1, + "linkage": { + "type": "External" + } + }, + { + "id": 2, + "linkage": { + "type": "External" + } + } + ], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ] +} diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/all.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/all.json new file mode 100644 index 0000000000000..d408b64d05af3 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/all.json @@ -0,0 +1,90 @@ +{ + "id_table": [ + { + "id": 1, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@bar#" + } + }, + { + "id": 2, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@baz#" + } + }, + { + "id": 0, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@foo#" + } + } + ], + "results": [ + { + "analysis_name": "PairsAnalysisResult", + "result": { + "pair_counts": [ + { + "count": 1, + "entity_id": { + "@": 0 + } + }, + { + "count": 2, + "entity_id": { + "@": 1 + } + }, + { + "count": 3, + "entity_id": { + "@": 2 + } + } + ] + } + }, + { + "analysis_name": "TagsAnalysisResult", + "result": { + "tags": [ + "deprecated", + "important", + "internal", + "public" + ] + } + }, + { + "analysis_name": "TagsPairsAnalysisResult", + "result": { + "entity_count": 3, + "max_pairs_per_entity": 3, + "total_pair_count": 6, + "unique_tag_count": 4 + } + } + ] +} diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/both.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/both.json new file mode 100644 index 0000000000000..e5f7170814295 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/both.json @@ -0,0 +1,81 @@ +{ + "id_table": [ + { + "id": 1, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@bar#" + } + }, + { + "id": 2, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@baz#" + } + }, + { + "id": 0, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@foo#" + } + } + ], + "results": [ + { + "analysis_name": "PairsAnalysisResult", + "result": { + "pair_counts": [ + { + "count": 1, + "entity_id": { + "@": 0 + } + }, + { + "count": 2, + "entity_id": { + "@": 1 + } + }, + { + "count": 3, + "entity_id": { + "@": 2 + } + } + ] + } + }, + { + "analysis_name": "TagsAnalysisResult", + "result": { + "tags": [ + "deprecated", + "important", + "internal", + "public" + ] + } + } + ] +} diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/pairs.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/pairs.json new file mode 100644 index 0000000000000..3f52b0acfd900 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/pairs.json @@ -0,0 +1,70 @@ +{ + "id_table": [ + { + "id": 1, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@bar#" + } + }, + { + "id": 2, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@baz#" + } + }, + { + "id": 0, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@foo#" + } + } + ], + "results": [ + { + "analysis_name": "PairsAnalysisResult", + "result": { + "pair_counts": [ + { + "count": 1, + "entity_id": { + "@": 0 + } + }, + { + "count": 2, + "entity_id": { + "@": 1 + } + }, + { + "count": 3, + "entity_id": { + "@": 2 + } + } + ] + } + } + ] +} diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/tags.json b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/tags.json new file mode 100644 index 0000000000000..aa41194746ea9 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-analyzer/Outputs/tags.json @@ -0,0 +1,56 @@ +{ + "id_table": [ + { + "id": 1, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@bar#" + } + }, + { + "id": 2, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@baz#" + } + }, + { + "id": 0, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "test.exe" + } + ], + "suffix": "", + "usr": "c:@F@foo#" + } + } + ], + "results": [ + { + "analysis_name": "TagsAnalysisResult", + "result": { + "tags": [ + "deprecated", + "important", + "internal", + "public" + ] + } + } + ] +} diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/analyzer.test b/clang/test/Analysis/Scalable/ssaf-analyzer/analyzer.test new file mode 100644 index 0000000000000..0abdcef15a449 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-analyzer/analyzer.test @@ -0,0 +1,141 @@ +// Tests for clang-ssaf-analyzer that require plugin support. + +// REQUIRES: plugins + +// RUN: rm -rf %t +// RUN: mkdir -p %t + +// ============================================================================ +// Error: unknown analysis name +// ============================================================================ + +// RUN: not %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/unknown.json -a NoSuchAnalysis 2>&1 \ +// RUN: | FileCheck %s --check-prefix=UNKNOWN +// UNKNOWN: no analysis registered for 'AnalysisName(NoSuchAnalysis)' + +// ============================================================================ +// Error: valid analysis name but LUSummary lacks entity data for it +// ============================================================================ + +// RUN: not %clang-ssaf-analyzer-with-plugin %S/Inputs/lu-tags-only.json \ +// RUN: -o %t/missing-data.json -a PairsAnalysisResult 2>&1 \ +// RUN: | FileCheck %s --check-prefix=MISSING-DATA +// MISSING-DATA: no data for analysis 'AnalysisName(PairsAnalysisResult)' in LUSummary + +// ============================================================================ +// Success: run TagsAnalysisResult only (single analysis) +// ============================================================================ + +// RUN: %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/tags.json -a TagsAnalysisResult +// RUN: diff %S/Outputs/tags.json %t/tags.json + +// ============================================================================ +// Success: run PairsAnalysisResult only (single analysis) +// ============================================================================ + +// RUN: %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/pairs.json -a PairsAnalysisResult +// RUN: diff %S/Outputs/pairs.json %t/pairs.json + +// ============================================================================ +// Success: run two summary analyses +// ============================================================================ + +// RUN: %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/both.json -a TagsAnalysisResult -a PairsAnalysisResult +// RUN: diff %S/Outputs/both.json %t/both.json + +// ============================================================================ +// Success: reversed order produces the same result (order-independent) +// ============================================================================ + +// RUN: %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/both-rev.json -a PairsAnalysisResult -a TagsAnalysisResult +// RUN: diff %S/Outputs/both.json %t/both-rev.json + +// ============================================================================ +// Success: duplicate analysis name is deduplicated +// ============================================================================ + +// RUN: %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/tags-dup.json -a TagsAnalysisResult -a TagsAnalysisResult +// RUN: diff %S/Outputs/tags.json %t/tags-dup.json + +// ============================================================================ +// Success: derived analysis pulls dependencies automatically +// ============================================================================ + +// RUN: %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/all.json -a TagsPairsAnalysisResult +// RUN: diff %S/Outputs/all.json %t/all.json + +// ============================================================================ +// Success: derived + one explicit dep (redundant dep is deduplicated) +// ============================================================================ + +// RUN: %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/all-partial-dup.json -a TagsPairsAnalysisResult -a TagsAnalysisResult +// RUN: diff %S/Outputs/all.json %t/all-partial-dup.json + +// ============================================================================ +// Success: derived + both explicit deps (all redundant, deduplicated) +// ============================================================================ + +// RUN: %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/all-full-dup.json \ +// RUN: -a TagsPairsAnalysisResult -a TagsAnalysisResult -a PairsAnalysisResult +// RUN: diff %S/Outputs/all.json %t/all-full-dup.json + +// ============================================================================ +// Success: run all example-plugin analyses explicitly +// ============================================================================ + +// RUN: %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/all-default.json \ +// RUN: -a TagsAnalysisResult -a PairsAnalysisResult -a TagsPairsAnalysisResult +// RUN: diff %S/Outputs/all.json %t/all-default.json + +// ============================================================================ +// Success: --analysis alias for -a +// ============================================================================ + +// RUN: %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/analysis-alias.json --analysis TagsAnalysisResult +// RUN: diff %S/Outputs/tags.json %t/analysis-alias.json + +// ============================================================================ +// Success: -l alias for --load +// ============================================================================ + +// RUN: clang-ssaf-analyzer -l %llvmshlibdir/SSAFExamplePlugin%pluginext \ +// RUN: %S/Inputs/lu.json -o %t/load-alias.json -a PairsAnalysisResult +// RUN: diff %S/Outputs/pairs.json %t/load-alias.json + +// ============================================================================ +// Error: mix of valid and invalid analysis names (partial failure) +// ============================================================================ + +// RUN: not %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/mixed.json -a TagsAnalysisResult -a NoSuchAnalysis -a PairsAnalysisResult 2>&1 \ +// RUN: | FileCheck %s --check-prefix=MIXED +// MIXED: no analysis registered for 'AnalysisName(NoSuchAnalysis)' + +// ============================================================================ +// Success: -o specified twice (last value wins) +// ============================================================================ + +// RUN: %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/ignored.json -o %t/last-wins.json -a TagsAnalysisResult +// RUN: diff %S/Outputs/tags.json %t/last-wins.json + +// ============================================================================ +// Round-trip: analyze then read back with ssaf-format +// ============================================================================ + +// RUN: %clang-ssaf-analyzer-with-plugin %S/Inputs/lu.json \ +// RUN: -o %t/roundtrip.json -a TagsPairsAnalysisResult +// RUN: clang-ssaf-format --type wpa --load %llvmshlibdir/SSAFExamplePlugin%pluginext \ +// RUN: %t/roundtrip.json -o %t/roundtrip-copy.json +// RUN: diff %S/Outputs/all.json %t/roundtrip-copy.json diff --git a/clang/test/Analysis/Scalable/ssaf-analyzer/cli-errors.test b/clang/test/Analysis/Scalable/ssaf-analyzer/cli-errors.test new file mode 100644 index 0000000000000..0367ba8b8c484 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-analyzer/cli-errors.test @@ -0,0 +1,53 @@ +// Tests for clang-ssaf-analyzer CLI errors that do not require plugins. + +// RUN: rm -rf %t +// RUN: mkdir -p %t + +// ============================================================================ +// CLI error: no arguments +// ============================================================================ + +// RUN: not clang-ssaf-analyzer 2>&1 \ +// RUN: | FileCheck %s --check-prefix=NO-ARGS +// NO-ARGS: clang-ssaf-analyzer{{(\.exe)?}}: Not enough positional command line arguments spec... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/196124 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
