aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
authorAkira Hatanaka <ahatanaka@apple.com>2018-04-17 19:13:41 +0000
committerAkira Hatanaka <ahatanaka@apple.com>2018-04-17 19:13:41 +0000
commit2be0441e770d0bf205af9b823d596583e84324fb (patch)
treeafe12bbf68d0603193524ad01ce846cd566cab05 /clang/lib/Sema/SemaChecking.cpp
parent52a84e750a87d8d1d8fc41ce58e14f62af002850 (diff)
downloadllvm-2be0441e770d0bf205af9b823d596583e84324fb.zip
llvm-2be0441e770d0bf205af9b823d596583e84324fb.tar.gz
llvm-2be0441e770d0bf205af9b823d596583e84324fb.tar.bz2
[Sema] Warn about memcpy'ing non-trivial C structs.
Issue a warning when non-trivial C structs are copied or initialized by calls to memset, bzero, memcpy, or memmove. rdar://problem/36124208 Differential Revision: https://reviews.llvm.org/D45310 llvm-svn: 330202
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r--clang/lib/Sema/SemaChecking.cpp111
1 files changed, 110 insertions, 1 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 70e98e22b..bbeccf2 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -28,6 +28,7 @@
#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"
@@ -7378,6 +7379,98 @@ static QualType getSizeOfArgType(const Expr *E) {
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
@@ -7543,7 +7636,23 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
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(