Index: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -49,6 +49,7 @@ #include "StringLiteralWithEmbeddedNulCheck.h" #include "SuspiciousEnumUsageCheck.h" #include "SuspiciousIncludeCheck.h" +#include "SuspiciousMemoryComparisonCheck.h" #include "SuspiciousMemsetUsageCheck.h" #include "SuspiciousMissingCommaCheck.h" #include "SuspiciousSemicolonCheck.h" @@ -151,6 +152,8 @@ "bugprone-suspicious-enum-usage"); CheckFactories.registerCheck( "bugprone-suspicious-include"); + CheckFactories.registerCheck( + "bugprone-suspicious-memory-comparison"); CheckFactories.registerCheck( "bugprone-suspicious-memset-usage"); CheckFactories.registerCheck( Index: clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -44,6 +44,7 @@ StringLiteralWithEmbeddedNulCheck.cpp SuspiciousEnumUsageCheck.cpp SuspiciousIncludeCheck.cpp + SuspiciousMemoryComparisonCheck.cpp SuspiciousMemsetUsageCheck.cpp SuspiciousMissingCommaCheck.cpp SuspiciousSemicolonCheck.cpp Index: clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.h @@ -0,0 +1,35 @@ +//===--- SuspiciousMemoryComparisonCheck.h - clang-tidy ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSMEMORYCOMPARISONCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSMEMORYCOMPARISONCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Finds potentially incorrect calls to ``memcmp()`` based on properties of the +/// arguments. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-memory-comparison.html +class SuspiciousMemoryComparisonCheck : public ClangTidyCheck { +public: + SuspiciousMemoryComparisonCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSMEMORYCOMPARISONCHECK_H Index: clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp @@ -0,0 +1,85 @@ +//===--- SuspiciousMemoryComparisonCheck.cpp - clang-tidy -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SuspiciousMemoryComparisonCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +static llvm::Optional tryEvaluateSizeExpr(const Expr *SizeExpr, + const ASTContext &Ctx) { + Expr::EvalResult Result; + if (SizeExpr->EvaluateAsRValue(Result, Ctx)) + return Ctx.toBits( + CharUnits::fromQuantity(Result.Val.getInt().getExtValue())); + return None; +} + +void SuspiciousMemoryComparisonCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + callExpr(allOf(callee(namedDecl( + anyOf(hasName("::memcmp"), hasName("::std::memcmp")))), + unless(isInstantiationDependent()))) + .bind("call"), + this); +} + +void SuspiciousMemoryComparisonCheck::check( + const MatchFinder::MatchResult &Result) { + const ASTContext &Ctx = *Result.Context; + const auto *CE = Result.Nodes.getNodeAs("call"); + + const Expr *SizeExpr = CE->getArg(2); + assert(SizeExpr != nullptr && "Third argument of memcmp is mandatory."); + llvm::Optional ComparedBits = tryEvaluateSizeExpr(SizeExpr, Ctx); + + for (unsigned int ArgIndex = 0; ArgIndex < 2; ++ArgIndex) { + const Expr *ArgExpr = CE->getArg(ArgIndex); + QualType ArgType = ArgExpr->IgnoreImplicit()->getType(); + const Type *PointeeType = ArgType->getPointeeOrArrayElementType(); + assert(PointeeType != nullptr && "PointeeType should always be available."); + QualType PointeeQualifiedType(PointeeType, 0); + + if (PointeeType->isRecordType()) { + if (const RecordDecl *RD = + PointeeType->getAsRecordDecl()->getDefinition()) { + if (const auto *CXXDecl = dyn_cast(RD)) { + if (!CXXDecl->isStandardLayout()) { + diag(CE->getBeginLoc(), + "comparing object representation of non-standard-layout type " + "%0; consider using a comparison operator instead") + << PointeeQualifiedType; + break; + } + } + } + } + + if (!PointeeType->isIncompleteType()) { + uint64_t PointeeSize = Ctx.getTypeSize(PointeeType); + if (ComparedBits.hasValue() && *ComparedBits >= PointeeSize && + !Ctx.hasUniqueObjectRepresentations(PointeeQualifiedType)) { + diag(CE->getBeginLoc(), + "comparing object representation of type %0 which does not have a " + "unique object representation; consider comparing %select{the " + "values|the members of the object}1 manually") + << PointeeQualifiedType << (PointeeType->isRecordType() ? 1 : 0); + break; + } + } + } +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp +++ clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp @@ -13,6 +13,7 @@ #include "../bugprone/ReservedIdentifierCheck.h" #include "../bugprone/SignedCharMisuseCheck.h" #include "../bugprone/SpuriouslyWakeUpFunctionsCheck.h" +#include "../bugprone/SuspiciousMemoryComparisonCheck.h" #include "../bugprone/UnhandledSelfAssignmentCheck.h" #include "../google/UnnamedNamespaceInHeaderCheck.h" #include "../misc/NewDeleteOverloadsCheck.h" @@ -96,8 +97,13 @@ "cert-dcl37-c"); // ENV CheckFactories.registerCheck("cert-env33-c"); + // EXP + CheckFactories.registerCheck( + "cert-exp42-c"); // FLP CheckFactories.registerCheck("cert-flp30-c"); + CheckFactories.registerCheck( + "cert-flp37-c"); // FIO CheckFactories.registerCheck("cert-fio38-c"); // ERR Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -91,6 +91,11 @@ Finds structs that are inefficiently packed or aligned, and recommends packing and/or aligning of said structs as needed. +- New :doc:`bugprone-suspicious-memory-comparison + ` check. + + Finds potentially incorrect calls to ``memcmp()`` based on properties of the arguments. + - New :doc:`cppcoreguidelines-prefer-member-initializer ` check. @@ -111,6 +116,16 @@ Flags functions with Cognitive Complexity metric exceeding the configured limit. +- New alias :doc:`cert-exp42-c + ` to + :doc:`bugprone-suspicious-memory-comparison + ` was added. + +- New alias :doc:`cert-flp37-c + ` to + :doc:`bugprone-suspicious-memory-comparison + ` was added. + Changes in existing checks ^^^^^^^^^^^^^^^^^^^^^^^^^^ Index: clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-memory-comparison.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-memory-comparison.rst @@ -0,0 +1,31 @@ +.. title:: clang-tidy - bugprone-suspicious-memory-comparison + +bugprone-suspicious-memory-comparison +===================================== + +Finds potentially incorrect calls to ``memcmp()`` based on properties of the +arguments. The following cases are covered: + +**Case 1: Non-standard-layout type** + +Comparing the object representaions of non-standard-layout objects may not +properly compare the value representations. + +**Case 2: Types with no unique object representation** + +Objects with the same value may not have the same object representaion. +This may be caused by padding or floating-point types. + +See also: +`EXP42-C. Do not compare padding data +`_ +and +`FLP37-C. Do not use object representations to compare floating-point values +`_ + +This check is also related to and partially overlaps the CERT C++ Coding Standard rules +`OOP57-CPP. Prefer special member functions and overloaded operators to C Standard Library functions +`_ +and +`EXP62-CPP. Do not access the bits of an object representation that are not part of the object's value representation +`_ Index: clang-tools-extra/docs/clang-tidy/checks/cert-exp42-c.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/cert-exp42-c.rst @@ -0,0 +1,8 @@ +.. meta:: + :http-equiv=refresh: 5;URL=bugprone-suspicious-memory-comparison.html + +cert-exp42-c +============ + +The cert-exp42-c check is an alias, please see +`bugprone-suspicious-memory-comparison `_ for more information. Index: clang-tools-extra/docs/clang-tidy/checks/cert-flp37-c.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/cert-flp37-c.rst @@ -0,0 +1,8 @@ +.. meta:: + :http-equiv=refresh: 5;URL=bugprone-suspicious-memory-comparison.html + +cert-flp37-c +============ + +The cert-flp37-c check is an alias, please see +`bugprone-suspicious-memory-comparison `_ for more information. Index: clang-tools-extra/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -86,6 +86,7 @@ `bugprone-string-literal-with-embedded-nul `_, `bugprone-suspicious-enum-usage `_, `bugprone-suspicious-include `_, + `bugprone-suspicious-memory-comparison `_, `bugprone-suspicious-memset-usage `_, "Yes" `bugprone-suspicious-missing-comma `_, `bugprone-suspicious-semicolon `_, "Yes" @@ -109,7 +110,9 @@ `cert-err52-cpp `_, `cert-err58-cpp `_, `cert-err60-cpp `_, + `cert-exp42-c `_, `cert-flp30-c `_, + `cert-flp37-c `_, `cert-mem57-cpp `_, `cert-msc50-cpp `_, `cert-msc51-cpp `_, Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-suspicious-memory-comparison-32bits.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-suspicious-memory-comparison-32bits.cpp @@ -0,0 +1,33 @@ +// RUN: %check_clang_tidy %s bugprone-suspicious-memory-comparison %t \ +// RUN: -- -- -target i386-unknown-unknown + +static_assert(sizeof(int *) == sizeof(int)); + +namespace std { +typedef __SIZE_TYPE__ size_t; +int memcmp(const void *lhs, const void *rhs, size_t count); +} // namespace std + +namespace no_padding_on_32bit { +struct S { + int x; + int *y; +}; + +void test() { + S a, b; + std::memcmp(&a, &b, sizeof(S)); +} +} // namespace no_padding_on_32bit + +namespace inner_padding { +struct S { + char x; + int y; +}; +void test() { + S a, b; + std::memcmp(&a, &b, sizeof(S)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'inner_padding::S' which does not have a unique object representation; consider comparing the members of the object manually +} +} // namespace inner_padding Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-suspicious-memory-comparison.c =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-suspicious-memory-comparison.c @@ -0,0 +1,294 @@ +// RUN: %check_clang_tidy %s bugprone-suspicious-memory-comparison %t \ +// RUN: -- -- -target x86_64-unknown-unknown -std=c99 + +typedef __SIZE_TYPE__ size_t; +int memcmp(const void *lhs, const void *rhs, size_t count); + +// Examples from cert rule exp42-c + +struct S { + char c; + int i; + char buffer[13]; +}; + +void exp42_c_noncompliant(const struct S *left, const struct S *right) { + if ((left && right) && (0 == memcmp(left, right, sizeof(struct S)))) { + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: comparing object representation of type 'struct S' which does not have a unique object representation; consider comparing the members of the object manually + } +} + +void exp42_c_compliant(const struct S *left, const struct S *right) { + if ((left && right) && (left->c == right->c) && (left->i == right->i) && + (0 == memcmp(left->buffer, right->buffer, 13))) { + } +} + +#pragma pack(push, 1) +struct Packed_S { + char c; + int i; + char buffer[13]; +}; +#pragma pack(pop) + +void compliant_packed(const struct Packed_S *left, + const struct Packed_S *right) { + if ((left && right) && (0 == memcmp(left, right, sizeof(struct Packed_S)))) { + // no-warning + } +} + +// Examples from cert rule flp37-c + +struct S2 { + int i; + float f; +}; + +int flp37_c_noncompliant(const struct S2 *s1, const struct S2 *s2) { + if (!s1 && !s2) + return 1; + else if (!s1 || !s2) + return 0; + return 0 == memcmp(s1, s2, sizeof(struct S2)); + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: comparing object representation of type 'struct S2' which does not have a unique object representation; consider comparing the members of the object manually +} + +int flp37_c_compliant(const struct S2 *s1, const struct S2 *s2) { + if (!s1 && !s2) + return 1; + else if (!s1 || !s2) + return 0; + return s1->i == s2->i && s1->f == s2->f; + // no-warning +} + +void Test_Float() { + float a, b; + memcmp(&a, &b, sizeof(float)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'float' which does not have a unique object representation; consider comparing the values manually +} + +void TestArray_Float() { + float a[3], b[3]; + memcmp(a, b, sizeof(a)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'float' which does not have a unique object representation; consider comparing the values manually +} + +struct PredeclaredType; + +void Test_PredeclaredType(const struct PredeclaredType *lhs, + const struct PredeclaredType *rhs) { + memcmp(lhs, rhs, 1); // no-warning: predeclared type +} + +struct NoPadding { + int x; + int y; +}; + +void Test_NoPadding() { + struct NoPadding a, b; + memcmp(&a, &b, sizeof(struct NoPadding)); +} + +void TestArray_NoPadding() { + struct NoPadding a[3], b[3]; + memcmp(a, b, 3 * sizeof(struct NoPadding)); +} + +struct TrailingPadding { + int i; + char c; +}; + +void Test_TrailingPadding() { + struct TrailingPadding a, b; + memcmp(&a, &b, sizeof(struct TrailingPadding)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct TrailingPadding' which does not have a unique object representation; consider comparing the members of the object manually + memcmp(&a, &b, sizeof(int)); // no-warning: not comparing entire object + memcmp(&a, &b, 2 * sizeof(int)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct TrailingPadding' which does not have a unique object representation; consider comparing the members of the object manually +} + +struct TrailingPadding2 { + int i[2]; + char c; +}; + +void Test_TrailingPadding2() { + struct TrailingPadding2 a, b; + memcmp(&a, &b, 2 * sizeof(int)); // no-warning: not comparing entire object + memcmp(&a, &b, sizeof(struct TrailingPadding2)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct TrailingPadding2' which does not have a unique object representation; consider comparing the members of the object manually +} + +void Test_UnknownCount(size_t count) { + struct TrailingPadding a, b; + memcmp(&a, &b, count); // no-warning: unknown count value +} + +void Test_ExplicitVoidCast() { + struct TrailingPadding a, b; + memcmp((void *)&a, (void *)&b, + sizeof(struct TrailingPadding)); // no-warning: explicit cast +} + +void TestArray_TrailingPadding() { + struct TrailingPadding a[3], b[3]; + memcmp(a, b, 3 * sizeof(struct TrailingPadding)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct TrailingPadding' which does not have a unique object representation; consider comparing the members of the object manually +} + +struct InnerPadding { + char c; + int i; +}; + +void Test_InnerPadding() { + struct InnerPadding a, b; + memcmp(&a, &b, sizeof(struct InnerPadding)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct InnerPadding' which does not have a unique object representation; consider comparing the members of the object manually +} + +struct Bitfield_TrailingPaddingBytes { + int x : 10; + int y : 6; +}; + +void Test_Bitfield_TrailingPaddingBytes() { + struct Bitfield_TrailingPaddingBytes a, b; + memcmp(&a, &b, sizeof(struct S)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct Bitfield_TrailingPaddingBytes' which does not have a unique object representation; consider comparing the members of the object manually +} + +struct Bitfield_TrailingPaddingBits { + int x : 10; + int y : 20; +}; + +void Test_Bitfield_TrailingPaddingBits() { + struct Bitfield_TrailingPaddingBits a, b; + memcmp(&a, &b, sizeof(struct Bitfield_TrailingPaddingBits)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct Bitfield_TrailingPaddingBits' which does not have a unique object representation; consider comparing the members of the object manually +} + +struct Bitfield_InnerPaddingBits { + char x : 2; + int : 0; + char y : 8; +}; + +void Test_Bitfield_InnerPaddingBits() { + struct Bitfield_InnerPaddingBits a, b; + memcmp(&a, &b, sizeof(struct Bitfield_InnerPaddingBits)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct Bitfield_InnerPaddingBits' which does not have a unique object representation; consider comparing the members of the object manually +} + +struct Bitfield_NoPadding { + int i : 10; + int j : 10; + int k : 10; + int l : 2; +}; +_Static_assert(sizeof(struct Bitfield_NoPadding) == sizeof(int), + "Bit-fields should line up perfectly"); + +void Test_Bitfield_NoPadding() { + struct Bitfield_NoPadding a, b; + memcmp(&a, &b, sizeof(struct Bitfield_NoPadding)); // no-warning +} + +struct Bitfield_TrailingUnnamed { + int i[2]; + int : 0; +}; + +void Bitfield_TrailingUnnamed() { + struct Bitfield_TrailingUnnamed a, b; + memcmp(&a, &b, 2 * sizeof(int)); // no-warning + memcmp(&a, &b, sizeof(struct Bitfield_TrailingUnnamed)); // no-warning +} + +struct PaddingAfterUnion { + union { + unsigned short a; + short b; + } x; + + int y; +}; + +void Test_PaddingAfterUnion() { + struct PaddingAfterUnion a, b; + memcmp(&a, &b, sizeof(struct PaddingAfterUnion)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct PaddingAfterUnion' which does not have a unique object representation; consider comparing the members of the object manually +} + +struct Union_NoPadding { + union { + int a; + unsigned int b; + } x; + + int y; +}; + +void Test_Union_NoPadding() { + struct Union_NoPadding a, b; + memcmp(&a, &b, 2 * sizeof(int)); + memcmp(&a, &b, sizeof(struct Union_NoPadding)); +} + +union UnionWithPaddingInNestedStruct { + int i; + + struct { + int i; + char c; + } x; +}; + +void Test_UnionWithPaddingInNestedStruct() { + union UnionWithPaddingInNestedStruct a, b; + memcmp(&a, &b, sizeof(union UnionWithPaddingInNestedStruct)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'union UnionWithPaddingInNestedStruct' which does not have a unique object representation; consider comparing the members of the object manually +} + +struct PaddingInNested { + struct TrailingPadding x; + char y; +}; + +void Test_PaddingInNested() { + struct PaddingInNested a, b; + memcmp(&a, &b, sizeof(struct PaddingInNested)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct PaddingInNested' which does not have a unique object representation; consider comparing the members of the object manually +} + +struct PaddingAfterNested { + struct { + char a; + char b; + } x; + int y; +}; + +void Test_PaddingAfterNested() { + struct PaddingAfterNested a, b; + memcmp(&a, &b, sizeof(struct PaddingAfterNested)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct PaddingAfterNested' which does not have a unique object representation; consider comparing the members of the object manually +} + +struct AtomicMember { + _Atomic(int) x; +}; + +void Test_AtomicMember() { + // FIXME: this is a false positive as the list of objects with unique object + // representations is incomplete. + struct AtomicMember a, b; + memcmp(&a, &b, sizeof(struct AtomicMember)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct AtomicMember' which does not have a unique object representation; consider comparing the members of the object manually +} Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-suspicious-memory-comparison.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-suspicious-memory-comparison.cpp @@ -0,0 +1,231 @@ +// RUN: %check_clang_tidy %s bugprone-suspicious-memory-comparison %t \ +// RUN: -- -- -target x86_64-unknown-unknown + +namespace std { +typedef __SIZE_TYPE__ size_t; +int memcmp(const void *lhs, const void *rhs, size_t count); +} // namespace std + +namespace sei_cert_example_oop57_cpp { +class C { + int i; + +public: + virtual void f(); +}; + +void f(C &c1, C &c2) { + if (!std::memcmp(&c1, &c2, sizeof(C))) { + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: comparing object representation of non-standard-layout type 'sei_cert_example_oop57_cpp::C'; consider using a comparison operator instead + } +} +} // namespace sei_cert_example_oop57_cpp + +namespace inner_padding_64bit_only { +struct S { + int x; + int *y; +}; + +void test() { + S a, b; + std::memcmp(&a, &b, sizeof(S)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'inner_padding_64bit_only::S' which does not have a unique object representation; consider comparing the members of the object manually +} +} // namespace inner_padding_64bit_only + +namespace padding_in_base { +class Base { + char c; + int i; +}; + +class Derived : public Base {}; + +class Derived2 : public Derived {}; + +void testDerived() { + Derived a, b; + std::memcmp(&a, &b, sizeof(Base)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'padding_in_base::Derived' which does not have a unique object representation; consider comparing the members of the object manually + std::memcmp(&a, &b, sizeof(Derived)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'padding_in_base::Derived' which does not have a unique object representation; consider comparing the members of the object manually +} + +void testDerived2() { + Derived2 a, b; + std::memcmp(&a, &b, sizeof(Base)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'padding_in_base::Derived2' which does not have a unique object representation; consider comparing the members of the object manually + std::memcmp(&a, &b, sizeof(Derived2)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'padding_in_base::Derived2' which does not have a unique object representation; consider comparing the members of the object manually +} + +} // namespace padding_in_base + +namespace no_padding_in_base { +class Base { + int a, b; +}; + +class Derived : public Base {}; + +class Derived2 : public Derived {}; + +void testDerived() { + Derived a, b; + std::memcmp(&a, &b, sizeof(Base)); + std::memcmp(&a, &b, sizeof(Derived)); +} + +void testDerived2() { + Derived2 a, b; + std::memcmp(&a, &b, sizeof(char)); + std::memcmp(&a, &b, sizeof(Base)); + std::memcmp(&a, &b, sizeof(Derived2)); +} +} // namespace no_padding_in_base + +namespace non_standard_layout { +class C { +private: + int x; + +public: + int y; +}; + +void test() { + C a, b; + std::memcmp(&a, &b, sizeof(C)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of non-standard-layout type 'non_standard_layout::C'; consider using a comparison operator instead +} + +} // namespace non_standard_layout + +namespace static_ignored { +struct S { + static char c; + int i; +}; + +void test() { + S a, b; + std::memcmp(&a, &b, sizeof(S)); +} +} // namespace static_ignored + +namespace operator_void_ptr { +struct S { + operator void *() const; +}; + +void test() { + S s; + std::memcmp(s, s, sizeof(s)); +} +} // namespace operator_void_ptr + +namespace empty_struct { +struct S {}; + +void test() { + S a, b; + std::memcmp(&a, &b, sizeof(S)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'empty_struct::S' which does not have a unique object representation; consider comparing the members of the object manually +} +} // namespace empty_struct + +namespace empty_field { +struct Empty {}; +struct S { + Empty e; +}; + +void test() { + S a, b; + std::memcmp(&a, &b, sizeof(S)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'empty_field::S' which does not have a unique object representation; consider comparing the members of the object manually +} +} // namespace empty_field + +namespace no_unique_address_attribute { +struct Empty {}; + +namespace no_padding { +struct S { + char c; + [[no_unique_address]] Empty e; +}; + +void test() { + S a, b; + std::memcmp(&a, &b, sizeof(S)); +} + +} // namespace no_padding + +namespace multiple_empties_same_type { +struct S { + char c; + [[no_unique_address]] Empty e1, e2; +}; + +void test() { + S a, b; + std::memcmp(&a, &b, sizeof(S)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'no_unique_address_attribute::multiple_empties_same_type::S' which does not have a unique object representation; consider comparing the members of the object manually +} + +} // namespace multiple_empties_same_type + +namespace multiple_empties_different_types { +struct Empty2 {}; + +struct S { + char c; + [[no_unique_address]] Empty e1; + [[no_unique_address]] Empty2 e2; +}; + +void test() { + S a, b; + std::memcmp(&a, &b, sizeof(S)); +} +} // namespace multiple_empties_different_types +} // namespace no_unique_address_attribute + +namespace alignment { +struct S { + char x; + alignas(sizeof(int)) char y[sizeof(int)]; +}; + +void test() { + S a, b; + std::memcmp(&a, &b, sizeof(S)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'alignment::S' which does not have a unique object representation; consider comparing the members of the object manually +} +} // namespace alignment + +namespace no_warning_in_template { +template int compare(const T *l, const T *r) { + return std::memcmp(l, r, sizeof(T)); +} + +void test() { + int a, b; + compare(&a, &b); +} +} // namespace no_warning_in_template + +namespace warning_in_template { +template int compare(const T *l, const T *r) { + return std::memcmp(l, r, sizeof(T)); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: comparing object representation of type 'float' which does not have a unique object representation; consider comparing the values manually +} + +void test() { + float a, b; + compare(&a, &b); +} +} // namespace warning_in_template