Author: rsmith Date: Thu Sep 13 15:47:33 2018 New Revision: 342192 URL: http://llvm.org/viewvc/llvm-project?rev=342192&view=rev Log: Fix crash on call to __builtin_memcpy with a null pointer to an incomplete type.
Also improve the diagnostics for similar situations. Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td cfe/trunk/lib/AST/APValue.cpp cfe/trunk/lib/AST/ExprConstant.cpp cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp cfe/trunk/test/SemaCXX/constexpr-string.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=342192&r1=342191&r2=342192&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Thu Sep 13 15:47:33 2018 @@ -163,6 +163,10 @@ def note_constexpr_unsupported_unsized_a def note_constexpr_unsized_array_indexed : Note< "indexing of array without known bound is not allowed " "in a constant expression">; +def note_constexpr_memcpy_null : Note< + "%select{source|destination}2 of " + "'%select{%select{memcpy|wmemcpy}1|%select{memmove|wmemmove}1}0' " + "is %3">; def note_constexpr_memcpy_type_pun : Note< "cannot constant evaluate '%select{memcpy|memmove}0' from object of " "type %1 to object of type %2">; Modified: cfe/trunk/lib/AST/APValue.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/APValue.cpp?rev=342192&r1=342191&r2=342192&view=diff ============================================================================== --- cfe/trunk/lib/AST/APValue.cpp (original) +++ cfe/trunk/lib/AST/APValue.cpp Thu Sep 13 15:47:33 2018 @@ -416,18 +416,26 @@ void APValue::printPretty(raw_ostream &O << GetApproxValue(getComplexFloatImag()) << "i"; return; case APValue::LValue: { - LValueBase Base = getLValueBase(); - if (!Base) { - Out << "0"; - return; - } - bool IsReference = Ty->isReferenceType(); QualType InnerTy = IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType(); if (InnerTy.isNull()) InnerTy = Ty; + LValueBase Base = getLValueBase(); + if (!Base) { + if (isNullPointer()) { + Out << (Ctx.getLangOpts().CPlusPlus11 ? "nullptr" : "0"); + } else if (IsReference) { + Out << "*(" << InnerTy.stream(Ctx.getPrintingPolicy()) << "*)" + << getLValueOffset().getQuantity(); + } else { + Out << "(" << Ty.stream(Ctx.getPrintingPolicy()) << ")" + << getLValueOffset().getQuantity(); + } + return; + } + if (!hasLValuePath()) { // No lvalue path: just print the offset. CharUnits O = getLValueOffset(); Modified: cfe/trunk/lib/AST/ExprConstant.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=342192&r1=342191&r2=342192&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp (original) +++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Sep 13 15:47:33 2018 @@ -6191,12 +6191,12 @@ bool PointerExprEvaluator::VisitBuiltinC BuiltinOp == Builtin::BI__builtin_wmemmove; // The result of mem* is the first argument. - if (!Visit(E->getArg(0)) || Result.Designator.Invalid) + if (!Visit(E->getArg(0))) return false; LValue Dest = Result; LValue Src; - if (!EvaluatePointer(E->getArg(1), Src, Info) || Src.Designator.Invalid) + if (!EvaluatePointer(E->getArg(1), Src, Info)) return false; APSInt N; @@ -6209,6 +6209,20 @@ bool PointerExprEvaluator::VisitBuiltinC if (!N) return true; + // Otherwise, if either of the operands is null, we can't proceed. Don't + // try to determine the type of the copied objects, because there aren't + // any. + if (!Src.Base || !Dest.Base) { + APValue Val; + (!Src.Base ? Src : Dest).moveInto(Val); + Info.FFDiag(E, diag::note_constexpr_memcpy_null) + << Move << WChar << !!Src.Base + << Val.getAsString(Info.Ctx, E->getArg(0)->getType()); + return false; + } + if (Src.Designator.Invalid || Dest.Designator.Invalid) + return false; + // We require that Src and Dest are both pointers to arrays of // trivially-copyable type. (For the wide version, the designator will be // invalid if the designated object is not a wchar_t.) Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=342192&r1=342191&r2=342192&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original) +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Thu Sep 13 15:47:33 2018 @@ -253,7 +253,7 @@ namespace FunctionPointers { static_assert(1 + Apply(Select(4), 5) + Apply(Select(3), 7) == 42, ""); - constexpr int Invalid = Apply(Select(0), 0); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'Apply(0, 0)'}} + constexpr int Invalid = Apply(Select(0), 0); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'Apply(nullptr, 0)'}} } Modified: cfe/trunk/test/SemaCXX/constexpr-string.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-string.cpp?rev=342192&r1=342191&r2=342192&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/constexpr-string.cpp (original) +++ cfe/trunk/test/SemaCXX/constexpr-string.cpp Thu Sep 13 15:47:33 2018 @@ -317,6 +317,23 @@ namespace MemcpyEtc { static_assert(test_wmemmove(0, 3, 2) == 4234); // expected-error {{constant}} expected-note {{in call}} static_assert(test_wmemmove(2, 0, 3) == 4234); // expected-error {{constant}} expected-note {{in call}} +#define fold(x) (__builtin_constant_p(0) ? (x) : (x)) + + wchar_t global; + constexpr wchar_t *null = 0; + static_assert(__builtin_memcpy(&global, null, sizeof(wchar_t))); // expected-error {{}} expected-note {{source of 'memcpy' is nullptr}} + static_assert(__builtin_memmove(&global, null, sizeof(wchar_t))); // expected-error {{}} expected-note {{source of 'memmove' is nullptr}} + static_assert(__builtin_wmemcpy(&global, null, sizeof(wchar_t))); // expected-error {{}} expected-note {{source of 'wmemcpy' is nullptr}} + static_assert(__builtin_wmemmove(&global, null, sizeof(wchar_t))); // expected-error {{}} expected-note {{source of 'wmemmove' is nullptr}} + static_assert(__builtin_memcpy(null, &global, sizeof(wchar_t))); // expected-error {{}} expected-note {{destination of 'memcpy' is nullptr}} + static_assert(__builtin_memmove(null, &global, sizeof(wchar_t))); // expected-error {{}} expected-note {{destination of 'memmove' is nullptr}} + static_assert(__builtin_wmemcpy(null, &global, sizeof(wchar_t))); // expected-error {{}} expected-note {{destination of 'wmemcpy' is nullptr}} + static_assert(__builtin_wmemmove(null, &global, sizeof(wchar_t))); // expected-error {{}} expected-note {{destination of 'wmemmove' is nullptr}} + static_assert(__builtin_memcpy(&global, fold((wchar_t*)123), sizeof(wchar_t))); // expected-error {{}} expected-note {{source of 'memcpy' is (void *)123}} + static_assert(__builtin_memcpy(fold(reinterpret_cast<wchar_t*>(123)), &global, sizeof(wchar_t))); // expected-error {{}} expected-note {{destination of 'memcpy' is (void *)123}} + constexpr struct Incomplete *null_incomplete = 0; + static_assert(__builtin_memcpy(null_incomplete, null_incomplete, sizeof(wchar_t))); // expected-error {{}} expected-note {{source of 'memcpy' is nullptr}} + // Copying is permitted for any trivially-copyable type. struct Trivial { char k; short s; constexpr bool ok() { return k == 3 && s == 4; } }; constexpr bool test_trivial() { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits