https://gcc.gnu.org/g:ccfcabc847eaeb6c1e0b0bec5a12c8af649c8de0
commit r17-627-gccfcabc847eaeb6c1e0b0bec5a12c8af649c8de0 Author: David Malcolm <[email protected]> Date: Wed May 20 10:24:40 2026 -0400 testsuite: add some libstdc++ -fanalyzer test coverage (PR 125236) This patch adds some test coverage for -fanalyzer's handling of basic usage of libstdc++ to g++.dg/analyzer/torture, providing end-to-end testing of the interaction of -fanalyzer and libstdc++ at various optimization levels. Currently this is rather minimal (to ensure the tests pass). I'm working on debugging -fanalyzer issues with other usage patterns and hope to extend this further as more start working. gcc/testsuite/ChangeLog: PR analyzer/125236 * g++.dg/analyzer/torture/README.txt: New. * g++.dg/analyzer/torture/std-string-ctor-large-literal.C: New test. * g++.dg/analyzer/torture/std-string-ctor-small-literal.C: New test. * g++.dg/analyzer/torture/std-string-default-ctor.C: New test. * g++.dg/analyzer/torture/std-unique-ptr-1.C: New test. Signed-off-by: David Malcolm <[email protected]> Diff: --- gcc/testsuite/g++.dg/analyzer/torture/README.txt | 16 +++++++++++ .../torture/std-string-ctor-large-literal.C | 23 +++++++++++++++ .../torture/std-string-ctor-small-literal.C | 22 +++++++++++++++ .../analyzer/torture/std-string-default-ctor.C | 19 +++++++++++++ .../g++.dg/analyzer/torture/std-unique-ptr-1.C | 33 ++++++++++++++++++++++ 5 files changed, 113 insertions(+) diff --git a/gcc/testsuite/g++.dg/analyzer/torture/README.txt b/gcc/testsuite/g++.dg/analyzer/torture/README.txt new file mode 100644 index 000000000000..88965beb8ab5 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/torture/README.txt @@ -0,0 +1,16 @@ +Various tests in this directory directly use the libstdc++ headers, +providing an end-to-end test of the interaction of -fanalyzer and +libstdc++ at various optimization levels. + +libstdc++-v3/doc/xml/manual/using.xml +(https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_macros.html) +notes that by default, glibcxx assertions are enabled at -O0, and +disabled at -O1 and above. + +We will explicitly disable them in some tests via: + // { dg-additional-options "-D_GLIBCXX_NO_ASSERTIONS" } + +With optimizations, many tests simplify to be within the analyzer's +normal limits, however at -O0 we may need to turn up + --param=analyzer-supernode-explosion-factor= +for the analyzer to fully explore the code. diff --git a/gcc/testsuite/g++.dg/analyzer/torture/std-string-ctor-large-literal.C b/gcc/testsuite/g++.dg/analyzer/torture/std-string-ctor-large-literal.C new file mode 100644 index 000000000000..8802c5337ce1 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/torture/std-string-ctor-large-literal.C @@ -0,0 +1,23 @@ +/* Verify that the analyzer is silent on correct usage of std::string, + using <string>. */ + +// { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } + +/* Leaving assertions at default: we seem to need assertions at -O0 + for the test to pass. */ + +// { dg-additional-options "--param=analyzer-supernode-explosion-factor=10" } + +#include "../../../gcc.dg/analyzer/analyzer-decls.h" +#include <string> + +void +test_ctor_large () +{ + std::string s {"0123456789012345678901234567890123456789" + "0123456789012345678901234567890123456789"}; + __analyzer_eval (s.length () == 80); // { dg-warning "TRUE" } + __analyzer_eval (s.size () == 80); // { dg-warning "TRUE" } + __analyzer_eval (__builtin_strlen (s.c_str ()) == 80); // { dg-warning "TRUE" "ideal" { xfail *-*-* } } + // { dg-bogus "UNKNOWN" "status quo" { xfail *-*-* } .-1 } +} diff --git a/gcc/testsuite/g++.dg/analyzer/torture/std-string-ctor-small-literal.C b/gcc/testsuite/g++.dg/analyzer/torture/std-string-ctor-small-literal.C new file mode 100644 index 000000000000..05a2f5882d79 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/torture/std-string-ctor-small-literal.C @@ -0,0 +1,22 @@ +/* Verify that the analyzer is silent on correct usage of std::string, + using <string>. */ + +// { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } + +/* Leaving assertions at default: we seem to need assertions at -O0 + for the test to pass. */ + +// { dg-additional-options "--param=analyzer-supernode-explosion-factor=10" } + +#include "../../../gcc.dg/analyzer/analyzer-decls.h" +#include <string> + +void +test_ctor_small () +{ + std::string s {"abc"}; + __analyzer_eval (s.length () == 3); // { dg-warning "TRUE" } + __analyzer_eval (s.size () == 3); // { dg-warning "TRUE" } + __analyzer_eval (__builtin_strlen (s.c_str ()) == 3); // { dg-warning "TRUE" "ideal" { xfail *-*-* } } + // { dg-bogus "UNKNOWN" "status quo" { xfail *-*-* } .-1 } +} diff --git a/gcc/testsuite/g++.dg/analyzer/torture/std-string-default-ctor.C b/gcc/testsuite/g++.dg/analyzer/torture/std-string-default-ctor.C new file mode 100644 index 000000000000..dd9ce32bf619 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/torture/std-string-default-ctor.C @@ -0,0 +1,19 @@ +/* Verify that the analyzer is silent on correct usage of std::string, + using <string>. */ + +// { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } + +/* Leaving assertions at default: we seem to need assertions at -O0 + for the test to pass. */ + +#include "../../../gcc.dg/analyzer/analyzer-decls.h" +#include <string> + +void +test_ctor_empty () +{ + std::string s; + __analyzer_eval (s.length () == 0); // { dg-warning "TRUE" } + __analyzer_eval (s.size () == 0); // { dg-warning "TRUE" } + __analyzer_eval (__builtin_strlen (s.c_str()) == 0); // { dg-warning "TRUE" } +} diff --git a/gcc/testsuite/g++.dg/analyzer/torture/std-unique-ptr-1.C b/gcc/testsuite/g++.dg/analyzer/torture/std-unique-ptr-1.C new file mode 100644 index 000000000000..0e37a6b9a6e6 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/torture/std-unique-ptr-1.C @@ -0,0 +1,33 @@ +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */ + +// { dg-additional-options "-D_GLIBCXX_NO_ASSERTIONS" } +// { dg-additional-options "--param=analyzer-supernode-explosion-factor=10" } + +#include "../../../gcc.dg/analyzer/analyzer-decls.h" +#include <memory> + +void +test_null_deref_1 () +{ + std::unique_ptr<int> p; + __analyzer_eval (*p == 42); // { dg-warning "null-dereference" } +} + +void +test_null_deref_2 () +{ + auto p = std::make_unique<int> (42); + __analyzer_eval (*p == 42); // { dg-warning "TRUE" } + p = nullptr; + __analyzer_eval (*p); // { dg-warning "null-dereference" } +} + +void +test_use_after_free () +{ + auto p = std::make_unique<int> (42); + __analyzer_eval (*p == 42); // { dg-warning "TRUE" } + int *ptr = p.get (); + p = nullptr; + __analyzer_eval (*ptr); // { dg-warning "use after 'delete'" } +}
