#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/NSAPI.h"
+#include "clang/AST/NonTrivialTypeVisitor.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/TemplateBase.h"
return QualType();
}
+namespace {
+
+struct SearchNonTrivialToInitializeField
+ : DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField> {
+ using Super =
+ DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField>;
+
+ SearchNonTrivialToInitializeField(const Expr *E, Sema &S) : E(E), S(S) {}
+
+ void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT,
+ SourceLocation SL) {
+ if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) {
+ asDerived().visitArray(PDIK, AT, SL);
+ return;
+ }
+
+ Super::visitWithKind(PDIK, FT, SL);
+ }
+
+ void visitARCStrong(QualType FT, SourceLocation SL) {
+ S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1);
+ }
+ void visitARCWeak(QualType FT, SourceLocation SL) {
+ S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1);
+ }
+ void visitStruct(QualType FT, SourceLocation SL) {
+ for (const FieldDecl *FD : FT->castAs<RecordType>()->getDecl()->fields())
+ visit(FD->getType(), FD->getLocation());
+ }
+ void visitArray(QualType::PrimitiveDefaultInitializeKind PDIK,
+ const ArrayType *AT, SourceLocation SL) {
+ visit(getContext().getBaseElementType(AT), SL);
+ }
+ void visitTrivial(QualType FT, SourceLocation SL) {}
+
+ static void diag(QualType RT, const Expr *E, Sema &S) {
+ SearchNonTrivialToInitializeField(E, S).visitStruct(RT, SourceLocation());
+ }
+
+ ASTContext &getContext() { return S.getASTContext(); }
+
+ const Expr *E;
+ Sema &S;
+};
+
+struct SearchNonTrivialToCopyField
+ : CopiedTypeVisitor<SearchNonTrivialToCopyField, false> {
+ using Super = CopiedTypeVisitor<SearchNonTrivialToCopyField, false>;
+
+ SearchNonTrivialToCopyField(const Expr *E, Sema &S) : E(E), S(S) {}
+
+ void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType FT,
+ SourceLocation SL) {
+ if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) {
+ asDerived().visitArray(PCK, AT, SL);
+ return;
+ }
+
+ Super::visitWithKind(PCK, FT, SL);
+ }
+
+ void visitARCStrong(QualType FT, SourceLocation SL) {
+ S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
+ }
+ void visitARCWeak(QualType FT, SourceLocation SL) {
+ S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
+ }
+ void visitStruct(QualType FT, SourceLocation SL) {
+ for (const FieldDecl *FD : FT->castAs<RecordType>()->getDecl()->fields())
+ visit(FD->getType(), FD->getLocation());
+ }
+ void visitArray(QualType::PrimitiveCopyKind PCK, const ArrayType *AT,
+ SourceLocation SL) {
+ visit(getContext().getBaseElementType(AT), SL);
+ }
+ void preVisit(QualType::PrimitiveCopyKind PCK, QualType FT,
+ SourceLocation SL) {}
+ void visitTrivial(QualType FT, SourceLocation SL) {}
+ void visitVolatileTrivial(QualType FT, SourceLocation SL) {}
+
+ static void diag(QualType RT, const Expr *E, Sema &S) {
+ SearchNonTrivialToCopyField(E, S).visitStruct(RT, SourceLocation());
+ }
+
+ ASTContext &getContext() { return S.getASTContext(); }
+
+ const Expr *E;
+ Sema &S;
+};
+
+}
+
/// \brief Check for dangerous or invalid arguments to memset().
///
/// This issues warnings on known problematic, dangerous or unspecified
PDiag(diag::warn_arc_object_memaccess)
<< ArgIdx << FnName << PointeeTy
<< Call->getCallee()->getSourceRange());
- else
+ else if (const auto *RT = PointeeTy->getAs<RecordType>()) {
+ if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) &&
+ RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize()) {
+ DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_cstruct_memaccess)
+ << ArgIdx << FnName << PointeeTy << 0);
+ SearchNonTrivialToInitializeField::diag(PointeeTy, Dest, *this);
+ } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) &&
+ RT->getDecl()->isNonTrivialToPrimitiveCopy()) {
+ DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_cstruct_memaccess)
+ << ArgIdx << FnName << PointeeTy << 1);
+ SearchNonTrivialToCopyField::diag(PointeeTy, Dest, *this);
+ } else {
+ continue;
+ }
+ } else
continue;
DiagRuntimeBehavior(
--- /dev/null
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime-has-weak -x objective-c -fobjc-arc -verify %s
+
+void *memset(void *, int, __SIZE_TYPE__);
+void bzero(void *, __SIZE_TYPE__);
+void *memcpy(void *, const void *, __SIZE_TYPE__);
+void *memmove(void *, const void *, __SIZE_TYPE__);
+
+struct Trivial {
+ int f0;
+ volatile int f1;
+};
+
+struct NonTrivial0 {
+ int f0;
+ __weak id f1; // expected-note 2 {{non-trivial to default-initialize}} expected-note 2 {{non-trivial to copy}}
+ volatile int f2;
+ id f3[10]; // expected-note 2 {{non-trivial to default-initialize}} expected-note 2 {{non-trivial to copy}}
+};
+
+struct NonTrivial1 {
+ id f0; // expected-note 2 {{non-trivial to default-initialize}} expected-note 2 {{non-trivial to copy}}
+ int f1;
+ struct NonTrivial0 f2;
+};
+
+void testTrivial(struct Trivial *d, struct Trivial *s) {
+ memset(d, 0, sizeof(struct Trivial));
+ bzero(d, sizeof(struct Trivial));
+ memcpy(d, s, sizeof(struct Trivial));
+ memmove(d, s, sizeof(struct Trivial));
+}
+
+void testNonTrivial1(struct NonTrivial1 *d, struct NonTrivial1 *s) {
+ memset(d, 0, sizeof(struct NonTrivial1)); // expected-warning {{that is not trivial to primitive-default-initialize}} expected-note {{explicitly cast the pointer to silence}}
+ memset((void *)d, 0, sizeof(struct NonTrivial1));
+ bzero(d, sizeof(struct NonTrivial1)); // expected-warning {{that is not trivial to primitive-default-initialize}} expected-note {{explicitly cast the pointer to silence}}
+ memcpy(d, s, sizeof(struct NonTrivial1)); // expected-warning {{that is not trivial to primitive-copy}} expected-note {{explicitly cast the pointer to silence}}
+ memmove(d, s, sizeof(struct NonTrivial1)); // expected-warning {{that is not trivial to primitive-copy}} expected-note {{explicitly cast the pointer to silence}}
+}