From fb27bb07920650ca396009b4cc4e99333fc973a5 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 10 Oct 2014 00:05:45 +0000 Subject: [PATCH] Promote null pointer constants used as arguments to variadic functions Make it possible to pass NULL through variadic functions on 64-bit Windows targets. The Visual C++ headers define NULL to 0, when they should define it to 0LL on Win64 so that NULL is a pointer-sized integer. Fixes PR20949. Reviewers: thakis, rsmith Differential Revision: http://reviews.llvm.org/D5480 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219456 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGCall.cpp | 23 +++++++++++++++++++++++ lib/CodeGen/CodeGenFunction.h | 4 +++- test/CodeGen/variadic-null-win64.c | 17 +++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 test/CodeGen/variadic-null-win64.c diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index b40fa9d93d..4c82e90cc0 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -2728,6 +2728,24 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, args.add(EmitAnyExprToTemp(E), type); } +QualType CodeGenFunction::getVarArgType(const Expr *Arg) { + // System headers on Windows define NULL to 0 instead of 0LL on Win64. MSVC + // implicitly widens null pointer constants that are arguments to varargs + // functions to pointer-sized ints. + if (!getTarget().getTriple().isOSWindows()) + return Arg->getType(); + + if (Arg->getType()->isIntegerType() && + getContext().getTypeSize(Arg->getType()) < + getContext().getTargetInfo().getPointerWidth(0) && + Arg->isNullPointerConstant(getContext(), + Expr::NPC_ValueDependentIsNotNull)) { + return getContext().getIntPtrType(); + } + + return Arg->getType(); +} + // In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC // optimizer it can aggressively ignore unwind edges. void @@ -3023,6 +3041,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, else V = Builder.CreateLoad(RV.getAggregateAddr()); + // We might have to widen integers, but we should never truncate. + if (ArgInfo.getCoerceToType() != V->getType() && + V->getType()->isIntegerTy()) + V = Builder.CreateZExt(V, ArgInfo.getCoerceToType()); + // If the argument doesn't match, perform a bitcast to coerce it. This // can happen due to trivial type mismatches. if (FirstIRArg < IRFuncTy->getNumParams() && diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 11d2b04709..1c5111a598 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2752,7 +2752,7 @@ public: // If we still have any arguments, emit them using the type of the argument. for (; Arg != ArgEnd; ++Arg) - ArgTypes.push_back(Arg->getType()); + ArgTypes.push_back(getVarArgType(*Arg)); EmitCallArgs(Args, ArgTypes, ArgBeg, ArgEnd, CalleeDecl, ParamsToSkip, ForceColumnInfo); @@ -2765,6 +2765,8 @@ public: unsigned ParamsToSkip = 0, bool ForceColumnInfo = false); private: + QualType getVarArgType(const Expr *Arg); + const TargetCodeGenInfo &getTargetHooks() const { return CGM.getTargetCodeGenInfo(); } diff --git a/test/CodeGen/variadic-null-win64.c b/test/CodeGen/variadic-null-win64.c new file mode 100644 index 0000000000..4f57e7b39f --- /dev/null +++ b/test/CodeGen/variadic-null-win64.c @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-windows-msvc | FileCheck %s --check-prefix=WINDOWS +// RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-linux | FileCheck %s --check-prefix=LINUX + +// Make it possible to pass NULL through variadic functions on platforms where +// NULL has an integer type that is more narrow than a pointer. On such +// platforms we widen null pointer constants to a pointer-sized integer. + +#define NULL 0 + +void v(const char *f, ...); +void f(const char *f) { + v(f, 1, 2, 3, NULL); +} +// WINDOWS: define void @f(i8* %f) +// WINDOWS: call void (i8*, ...)* @v(i8* {{.*}}, i32 1, i32 2, i32 3, i64 0) +// LINUX: define void @f(i8* %f) +// LINUX: call void (i8*, ...)* @v(i8* {{.*}}, i32 1, i32 2, i32 3, i32 0) -- 2.40.0