diff options
author | Akira Hatanaka <ahatanaka@apple.com> | 2018-04-17 19:13:41 +0000 |
---|---|---|
committer | Akira Hatanaka <ahatanaka@apple.com> | 2018-04-17 19:13:41 +0000 |
commit | 2be0441e770d0bf205af9b823d596583e84324fb (patch) | |
tree | afe12bbf68d0603193524ad01ce846cd566cab05 /clang/lib/Sema/SemaChecking.cpp | |
parent | 52a84e750a87d8d1d8fc41ce58e14f62af002850 (diff) | |
download | llvm-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.cpp | 111 |
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( |