Skip to content

Commit

Permalink
Promote null pointer constants used as arguments to variadic functions
Browse files Browse the repository at this point in the history
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

llvm-svn: 219456
  • Loading branch information
rnk committed Oct 10, 2014
1 parent df782e4 commit 79b0fd7
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 1 deletion.
23 changes: 23 additions & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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() &&
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -2752,7 +2752,7 @@ class CodeGenFunction : public CodeGenTypeCache {

// 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);
Expand All @@ -2765,6 +2765,8 @@ class CodeGenFunction : public CodeGenTypeCache {
unsigned ParamsToSkip = 0, bool ForceColumnInfo = false);

private:
QualType getVarArgType(const Expr *Arg);

const TargetCodeGenInfo &getTargetHooks() const {
return CGM.getTargetCodeGenInfo();
}
Expand Down
17 changes: 17 additions & 0 deletions clang/test/CodeGen/variadic-null-win64.c
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit 79b0fd7

Please sign in to comment.