From 3591f84a5062b837a93d4eede377eaea7bac8408 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 29 Jan 2025 18:11:23 +0000 Subject: [PATCH] C++: Add lots of tests for CWE-119 involving unions and structs. --- .../semmle/tests/OverflowBuffer.expected | 52 +++++++ .../semmle/tests/UnboundedWrite.expected | 24 +-- .../CWE/CWE-119/semmle/tests/tests.cpp | 142 ++++++++++++++++++ 3 files changed, 206 insertions(+), 12 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowBuffer.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowBuffer.expected index 78adaebd052..a564077d347 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowBuffer.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowBuffer.expected @@ -53,6 +53,58 @@ | tests.cpp:712:3:712:8 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:693:16:693:16 | c | destination buffer | | tests.cpp:716:3:716:8 | call to memset | This 'memset' operation accesses 24 bytes but the $@ is only 16 bytes. | tests.cpp:692:16:692:16 | b | destination buffer | | tests.cpp:727:2:727:7 | call to memset | This 'memset' operation accesses 24 bytes but the $@ is only 8 bytes. | tests.cpp:693:16:693:16 | c | destination buffer | +| tests.cpp:746:5:746:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:734:20:734:22 | a_1 | destination buffer | +| tests.cpp:749:5:749:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:734:20:734:22 | a_1 | destination buffer | +| tests.cpp:753:5:753:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:735:20:735:22 | b_1 | destination buffer | +| tests.cpp:754:5:754:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:735:20:735:22 | b_1 | destination buffer | +| tests.cpp:756:5:756:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:735:20:735:22 | b_1 | destination buffer | +| tests.cpp:757:5:757:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:735:20:735:22 | b_1 | destination buffer | +| tests.cpp:760:5:760:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 4 bytes. | tests.cpp:736:20:736:22 | c_1 | destination buffer | +| tests.cpp:761:5:761:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 4 bytes. | tests.cpp:736:20:736:22 | c_1 | destination buffer | +| tests.cpp:762:5:762:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:736:20:736:22 | c_1 | destination buffer | +| tests.cpp:763:5:763:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 4 bytes. | tests.cpp:736:20:736:22 | c_1 | destination buffer | +| tests.cpp:764:5:764:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 4 bytes. | tests.cpp:736:20:736:22 | c_1 | destination buffer | +| tests.cpp:767:5:767:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:739:20:739:22 | a_2 | destination buffer | +| tests.cpp:768:5:768:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:739:20:739:22 | a_2 | destination buffer | +| tests.cpp:770:5:770:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:739:20:739:22 | a_2 | destination buffer | +| tests.cpp:771:5:771:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:739:20:739:22 | a_2 | destination buffer | +| tests.cpp:774:5:774:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 4 bytes. | tests.cpp:740:20:740:22 | b_2 | destination buffer | +| tests.cpp:775:5:775:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 4 bytes. | tests.cpp:740:20:740:22 | b_2 | destination buffer | +| tests.cpp:776:5:776:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:740:20:740:22 | b_2 | destination buffer | +| tests.cpp:777:5:777:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 4 bytes. | tests.cpp:740:20:740:22 | b_2 | destination buffer | +| tests.cpp:778:5:778:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 4 bytes. | tests.cpp:740:20:740:22 | b_2 | destination buffer | +| tests.cpp:793:5:793:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:787:18:787:18 | a | destination buffer | +| tests.cpp:795:5:795:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:790:16:790:16 | b | destination buffer | +| tests.cpp:814:5:814:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 12 bytes. | tests.cpp:800:16:800:16 | a | destination buffer | +| tests.cpp:815:5:815:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 12 bytes. | tests.cpp:800:16:800:16 | a | destination buffer | +| tests.cpp:817:5:817:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 12 bytes. | tests.cpp:800:16:800:16 | a | destination buffer | +| tests.cpp:819:5:819:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 12 bytes. | tests.cpp:800:16:800:16 | a | destination buffer | +| tests.cpp:822:5:822:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 8 bytes. | tests.cpp:801:16:801:16 | b | destination buffer | +| tests.cpp:823:5:823:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 8 bytes. | tests.cpp:801:16:801:16 | b | destination buffer | +| tests.cpp:824:5:824:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 8 bytes. | tests.cpp:801:16:801:16 | b | destination buffer | +| tests.cpp:825:5:825:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 8 bytes. | tests.cpp:801:16:801:16 | b | destination buffer | +| tests.cpp:827:5:827:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 8 bytes. | tests.cpp:801:16:801:16 | b | destination buffer | +| tests.cpp:830:5:830:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:802:16:802:16 | c | destination buffer | +| tests.cpp:831:5:831:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 4 bytes. | tests.cpp:802:16:802:16 | c | destination buffer | +| tests.cpp:832:5:832:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 4 bytes. | tests.cpp:802:16:802:16 | c | destination buffer | +| tests.cpp:833:5:833:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:802:16:802:16 | c | destination buffer | +| tests.cpp:834:5:834:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:802:16:802:16 | c | destination buffer | +| tests.cpp:835:5:835:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:802:16:802:16 | c | destination buffer | +| tests.cpp:838:5:838:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 16 bytes. | tests.cpp:806:14:806:18 | inner | destination buffer | +| tests.cpp:841:5:841:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 16 bytes. | tests.cpp:806:14:806:18 | inner | destination buffer | +| tests.cpp:843:5:843:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 16 bytes. | tests.cpp:806:14:806:18 | inner | destination buffer | +| tests.cpp:846:5:846:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:807:16:807:16 | x | destination buffer | +| tests.cpp:847:5:847:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 4 bytes. | tests.cpp:807:16:807:16 | x | destination buffer | +| tests.cpp:848:5:848:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 4 bytes. | tests.cpp:807:16:807:16 | x | destination buffer | +| tests.cpp:849:5:849:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:807:16:807:16 | x | destination buffer | +| tests.cpp:850:5:850:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:807:16:807:16 | x | destination buffer | +| tests.cpp:851:5:851:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:807:16:807:16 | x | destination buffer | +| tests.cpp:862:5:862:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer | +| tests.cpp:863:5:863:10 | call to memset | This 'memset' operation accesses 16 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer | +| tests.cpp:864:5:864:10 | call to memset | This 'memset' operation accesses 12 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer | +| tests.cpp:865:5:865:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer | +| tests.cpp:866:5:866:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer | +| tests.cpp:867:5:867:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:812:12:812:12 | u | destination buffer | | tests_restrict.c:12:2:12:7 | call to memcpy | This 'memcpy' operation accesses 2 bytes but the $@ is only 1 byte. | tests_restrict.c:7:6:7:13 | smallbuf | source buffer | | unions.cpp:26:2:26:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:21:10:21:11 | mu | destination buffer | | unions.cpp:30:2:30:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:15:7:15:11 | small | destination buffer | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected index 82b5412dd4c..575229672a8 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected @@ -27,8 +27,8 @@ edges | main.cpp:9:29:9:32 | *argv | tests_restrict.c:15:41:15:44 | *argv | provenance | | | main.cpp:9:29:9:32 | tests_restrict_main output argument | main.cpp:10:20:10:23 | **argv | provenance | | | main.cpp:9:29:9:32 | tests_restrict_main output argument | main.cpp:10:20:10:23 | *argv | provenance | | -| main.cpp:10:20:10:23 | **argv | tests.cpp:730:32:730:35 | **argv | provenance | | -| main.cpp:10:20:10:23 | *argv | tests.cpp:730:32:730:35 | *argv | provenance | | +| main.cpp:10:20:10:23 | **argv | tests.cpp:872:32:872:35 | **argv | provenance | | +| main.cpp:10:20:10:23 | *argv | tests.cpp:872:32:872:35 | *argv | provenance | | | overflowdestination.cpp:23:45:23:48 | **argv | overflowdestination.cpp:23:45:23:48 | **argv | provenance | | | overflowdestination.cpp:23:45:23:48 | **argv | overflowdestination.cpp:23:45:23:48 | *argv | provenance | | | test_buffer_overrun.cpp:32:46:32:49 | **argv | test_buffer_overrun.cpp:32:46:32:49 | **argv | provenance | | @@ -41,12 +41,12 @@ edges | tests.cpp:628:14:628:14 | *s [*home] | tests.cpp:628:14:628:19 | *home | provenance | | | tests.cpp:628:14:628:14 | *s [*home] | tests.cpp:628:16:628:19 | *home | provenance | | | tests.cpp:628:16:628:19 | *home | tests.cpp:628:14:628:19 | *home | provenance | | -| tests.cpp:730:32:730:35 | **argv | tests.cpp:755:9:755:15 | *access to array | provenance | | -| tests.cpp:730:32:730:35 | **argv | tests.cpp:756:9:756:15 | *access to array | provenance | | -| tests.cpp:730:32:730:35 | *argv | tests.cpp:755:9:755:15 | *access to array | provenance | | -| tests.cpp:730:32:730:35 | *argv | tests.cpp:756:9:756:15 | *access to array | provenance | | -| tests.cpp:755:9:755:15 | *access to array | tests.cpp:613:19:613:24 | *source | provenance | | -| tests.cpp:756:9:756:15 | *access to array | tests.cpp:622:19:622:24 | *source | provenance | | +| tests.cpp:872:32:872:35 | **argv | tests.cpp:897:9:897:15 | *access to array | provenance | | +| tests.cpp:872:32:872:35 | **argv | tests.cpp:898:9:898:15 | *access to array | provenance | | +| tests.cpp:872:32:872:35 | *argv | tests.cpp:897:9:897:15 | *access to array | provenance | | +| tests.cpp:872:32:872:35 | *argv | tests.cpp:898:9:898:15 | *access to array | provenance | | +| tests.cpp:897:9:897:15 | *access to array | tests.cpp:613:19:613:24 | *source | provenance | | +| tests.cpp:898:9:898:15 | *access to array | tests.cpp:622:19:622:24 | *source | provenance | | | tests_restrict.c:15:41:15:44 | **argv | tests_restrict.c:15:41:15:44 | **argv | provenance | | | tests_restrict.c:15:41:15:44 | *argv | tests_restrict.c:15:41:15:44 | *argv | provenance | | nodes @@ -80,10 +80,10 @@ nodes | tests.cpp:628:14:628:14 | *s [*home] | semmle.label | *s [*home] | | tests.cpp:628:14:628:19 | *home | semmle.label | *home | | tests.cpp:628:16:628:19 | *home | semmle.label | *home | -| tests.cpp:730:32:730:35 | **argv | semmle.label | **argv | -| tests.cpp:730:32:730:35 | *argv | semmle.label | *argv | -| tests.cpp:755:9:755:15 | *access to array | semmle.label | *access to array | -| tests.cpp:756:9:756:15 | *access to array | semmle.label | *access to array | +| tests.cpp:872:32:872:35 | **argv | semmle.label | **argv | +| tests.cpp:872:32:872:35 | *argv | semmle.label | *argv | +| tests.cpp:897:9:897:15 | *access to array | semmle.label | *access to array | +| tests.cpp:898:9:898:15 | *access to array | semmle.label | *access to array | | tests_restrict.c:15:41:15:44 | **argv | semmle.label | **argv | | tests_restrict.c:15:41:15:44 | **argv | semmle.label | **argv | | tests_restrict.c:15:41:15:44 | *argv | semmle.label | *argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/tests.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/tests.cpp index bcaf2a38d86..7ab88b8ec41 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/tests.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/tests.cpp @@ -727,6 +727,148 @@ void test36() { memset(&hsf.c, 0, sizeof(HasSomeFields) - offsetof(HasSomeFields, a)); // BAD } +struct AnonUnionInStruct +{ + union { + struct { + unsigned int a_1; + unsigned int b_1; + unsigned int c_1; + }; + struct { + unsigned int a_2; + unsigned int b_2; + }; + }; + unsigned int d; + + void test37() { + memset(&a_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_1)); // GOOD [FALSE POSITIVE] + memset(&a_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_1)); // GOOD + memset(&a_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, c_1)); // GOOD + memset(&a_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_2)); // GOOD + memset(&a_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_2)); // GOOD + memset(&a_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, d)); // GOOD + + memset(&b_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_1)); // BAD + memset(&b_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_1)); // GOOD [FALSE POSITIVE] + memset(&b_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, c_1)); // GOOD + memset(&b_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_2)); // BAD + memset(&b_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_2)); // GOOD [FALSE POSITIVE] + memset(&b_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, d)); // GOOD + + memset(&c_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_1)); // BAD + memset(&c_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_1)); // BAD + memset(&c_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, c_1)); // GOOD [FALSE POSITIVE] + memset(&c_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_2)); // BAD + memset(&c_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_2)); // GOOD [FALSE POSITIVE] + memset(&c_1, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, d)); // GOOD + + memset(&a_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_1)); // GOOD [FALSE POSITIVE] + memset(&a_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_1)); // GOOD [FALSE POSITIVE] + memset(&a_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, c_1)); // GOOD + memset(&a_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_2)); // GOOD [FALSE POSITIVE] + memset(&a_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_2)); // GOOD [FALSE POSITIVE] + memset(&a_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, d)); // GOOD + + memset(&b_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_1)); // BAD + memset(&b_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_1)); // GOOD [FALSE POSITIVE] + memset(&b_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, c_1)); // GOOD [FALSE POSITIVE] + memset(&b_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, a_2)); // BAD + memset(&b_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, b_2)); // GOOD [FALSE POSITIVE] + memset(&b_2, 0, sizeof(AnonUnionInStruct) - offsetof(AnonUnionInStruct, d)); // GOOD + }; +}; + +struct UnionWithoutStruct +{ + union + { + unsigned int a; + }; + + unsigned int b; + + void test37() { + memset(&a, 0, sizeof(UnionWithoutStruct) - offsetof(UnionWithoutStruct, a)); // GOOD [FALSE POSITIVE] + memset(&a, 0, sizeof(UnionWithoutStruct) - offsetof(UnionWithoutStruct, b)); // GOOD + memset(&b, 0, sizeof(UnionWithoutStruct) - offsetof(UnionWithoutStruct, a)); // BAD + }; +}; + +struct ThreeUInts { + unsigned int a; + unsigned int b; + unsigned int c; +}; + +struct FourUInts { + ThreeUInts inner; + unsigned int x; +}; + +struct S2 { + FourUInts f; + unsigned u; + void test38() { + memset(&f.inner.a, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // GOOD [FALSE POSITIVE] + memset(&f.inner.a, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // GOOD [FALSE POSITIVE] + memset(&f.inner.a, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // GOOD + memset(&f.inner.a, 0, sizeof(S2) - offsetof(FourUInts, inner)); // GOOD [FALSE POSITIVE] + memset(&f.inner.a, 0, sizeof(S2) - offsetof(FourUInts, x)); // GOOD + memset(&f.inner.a, 0, sizeof(S2) - offsetof(S2, f)); // GOOD [FALSE POSITIVE] + memset(&f.inner.a, 0, sizeof(S2) - offsetof(S2, u)); // GOOD + + memset(&f.inner.b, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // BAD + memset(&f.inner.b, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // GOOD [FALSE POSITIVE] + memset(&f.inner.b, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // GOOD [FALSE POSITIVE] + memset(&f.inner.b, 0, sizeof(S2) - offsetof(FourUInts, inner)); // BAD + memset(&f.inner.b, 0, sizeof(S2) - offsetof(FourUInts, x)); // GOOD + memset(&f.inner.b, 0, sizeof(S2) - offsetof(S2, f)); // BAD + memset(&f.inner.b, 0, sizeof(S2) - offsetof(S2, u)); // GOOD + + memset(&f.inner.c, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // BAD + memset(&f.inner.c, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // BAD + memset(&f.inner.c, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // GOOD [FALSE POSITIVE] + memset(&f.inner.c, 0, sizeof(S2) - offsetof(FourUInts, inner)); // BAD + memset(&f.inner.c, 0, sizeof(S2) - offsetof(FourUInts, x)); // GOOD [FALSE POSITIVE] + memset(&f.inner.c, 0, sizeof(S2) - offsetof(S2, f)); // BAD + memset(&f.inner.c, 0, sizeof(S2) - offsetof(S2, u)); // GOOD + + memset(&f.inner, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // GOOD [FALSE POSITIVE] + memset(&f.inner, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // GOOD + memset(&f.inner, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // GOOD + memset(&f.inner, 0, sizeof(S2) - offsetof(FourUInts, inner)); // GOOD [FALSE POSITIVE] + memset(&f.inner, 0, sizeof(S2) - offsetof(FourUInts, x)); // GOOD + memset(&f.inner, 0, sizeof(S2) - offsetof(S2, f)); // GOOD [FALSE POSITIVE] + memset(&f.inner, 0, sizeof(S2) - offsetof(S2, u)); // GOOD + + memset(&f.x, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // BAD + memset(&f.x, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // BAD + memset(&f.x, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // BAD + memset(&f.x, 0, sizeof(S2) - offsetof(FourUInts, inner)); // BAD + memset(&f.x, 0, sizeof(S2) - offsetof(FourUInts, x)); // GOOD [FALSE POSITIVE] + memset(&f.x, 0, sizeof(S2) - offsetof(S2, f)); // GOOD [FALSE POSITIVE] + memset(&f.x, 0, sizeof(S2) - offsetof(S2, u)); // GOOD [FALSE POSITIVE] + + memset(&f, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // GOOD + memset(&f, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // GOOD + memset(&f, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // GOOD + memset(&f, 0, sizeof(S2) - offsetof(FourUInts, inner)); // GOOD + memset(&f, 0, sizeof(S2) - offsetof(FourUInts, x)); // GOOD + memset(&f, 0, sizeof(S2) - offsetof(S2, f)); // GOOD + memset(&f, 0, sizeof(S2) - offsetof(S2, u)); // GOOD + + memset(&u, 0, sizeof(S2) - offsetof(ThreeUInts, a)); // BAD + memset(&u, 0, sizeof(S2) - offsetof(ThreeUInts, b)); // BAD + memset(&u, 0, sizeof(S2) - offsetof(ThreeUInts, c)); // BAD + memset(&u, 0, sizeof(S2) - offsetof(FourUInts, inner)); // BAD + memset(&u, 0, sizeof(S2) - offsetof(FourUInts, x)); // BAD + memset(&u, 0, sizeof(S2) - offsetof(S2, f)); // BAD + memset(&u, 0, sizeof(S2) - offsetof(S2, u)); // GOOD + } +}; + int tests_main(int argc, char *argv[]) { long long arr17[19];