[PATCH] D28166: Properly merge K&R functions that have attributes

Aaron Ballman via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Tue Jan 3 10:24:17 PST 2017


aaron.ballman added a reviewer: majnemer.
aaron.ballman added a comment.

> I *think* the problem is that we gin up the function type for a non-prototyped function based on the function call expression argument types, and the literal `0` is getting the type `signed long long`.

I think this is because of `CodeGenFunction::getVarArgType()` and is specific to the Windows ABI.

  // 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.

This causes the 0 to be emit as a 64-bit value rather than a 32-bit value. Indeed, if you change your original example to pass `1` rather than `0` when calling `p`, you no longer get the UB:

  ; Function Attrs: noinline nounwind
  define void @f() #0 {
  entry:
    %0 = load void (...)*, void (...)** @p, align 8
    %callee.knr.cast = bitcast void (...)* %0 to void (i32)*
    call void %callee.knr.cast(i32 1)
    ret void
  }

However, when I test with MSVC 2015, I do not get the behavior that Clang produces. My test was:

  void h(int i, ...) {}
  void i(int i, int j, int k, int l, int m) {}
  
  void(*p)() = i;
  
  void f() {
    p(0, 1, 2, 3, 0);
    h(0, 1, 2, 3, 0);
    i(0, 1, 2, 3, 0);
  }

MSVC outputs:

  ; 8    :   p(0, 1, 2, 3, 0);
  
  	mov	DWORD PTR [rsp+32], 0
  	mov	r9d, 3
  	mov	r8d, 2
  	mov	edx, 1
  	xor	ecx, ecx
  	call	QWORD PTR p
  
  ; 9    :   h(0, 1, 2, 3, 0);
  
  	mov	QWORD PTR [rsp+32], 0
  	mov	r9d, 3
  	mov	r8d, 2
  	mov	edx, 1
  	xor	ecx, ecx
  	call	h
  
  ; 10   :   i(0, 1, 2, 3, 0);
  
  	mov	DWORD PTR [rsp+32], 0
  	mov	r9d, 3
  	mov	r8d, 2
  	mov	edx, 1
  	xor	ecx, ecx
  	call	i

Clang outputs:

  %callee.knr.cast = bitcast void (...)* %0 to void (i64, i32, i32, i32, i64)*
  call void %callee.knr.cast(i64 0, i32 1, i32 2, i32 3, i64 0)
  call void (i32, ...) @h(i32 0, i32 1, i32 2, i32 3, i64 0)
  call void @i(i32 0, i32 1, i32 2, i32 3, i32 0)

Note that the K&R call casts to i64 in Clang but uses a DWORD PTR in MSVC. Only the variadic call to `h()` uses the QWORD PTR. So I think the correct behavior is to only enable the vararg behavior when the function is variadic with an ellipsis rather than variadic due to a lack of prototype.

Thoughts?


https://reviews.llvm.org/D28166





More information about the cfe-commits mailing list