[cxx-abi-dev] Passing non-trivial types through ...

Dennis Handly dhandly at cup.hp.com
Thu Aug 21 00:13:25 UTC 2014


>From: Jason Merrill <jason at redhat.com>
>On 08/13/2014 08:36 PM, Jason Merrill wrote:
>>>> From: John McCall <rjmccall at apple.com>
>>>> This is clearly the right way for any vendor who wants to accept non-POD
>>>> variadic arguments to do it:  no solution involving memcpy can be
>>>> correct for all types
>>
>> Yep.  The only question is whether it's better, for code that is in a
>> gray area of the standard, to stick with the broken historical practice
>> or do something more correct.

>Since there is incompatible existing practice and the code is only 
>conditionally-supported anyway, perhaps sticking with existing practice 
>is the right answer even though it breaks the object model.

>On the other hand, perhaps since the code is only 
>conditionally-supported, compatibility with existing practice isn't as 
>important.
Jason

I wrote a better test case to test both caller and callee sides and also
looked up the warning and found a test case from an important customer.
So someone is using it.  :-)

>From: John McCall <rjmccall at apple.com>
>> On the other hand, perhaps since the code is only conditionally-supported, compatibility with existing practice isn't as important.

>I'’m not sure we really do have “existing practice” on this.  Dennis, I
>apologize if I’m misunderstanding you, but it sounds like you consider
>this to be undefined behavior

Well the message indicates it.  And it won't work in all cases.  I.e.
if you put the address inside itself, that won't match.

But I did look up the warnings and found a test case from an important
customer.

(I'm not sure if there were other customers that had an actual but
different use of this?)

But looking real close at it, this won't be a problem, since used in
template metaprogramming:

char  tIsP(bool, tfoo);
char* tIsP(bool, ...);
template<class T>
struct tIsPtr {
 enum { tRet= (sizeof(tIsP(true,*(T*)0))== 1) };
};


>(which is an allowed interpretation  in fact,
>that was the explicit wording prior to C++11) and hence do not feel like
>you'’ve made a promise to support users relying on aCC’s current
>behavior.

Well for this customer we would have to.  :-)
I.e. At least not give an error, since not really called.

>In that case, we can adopt Jason’s proposal, and aCC can
>freely choose whether to continue its current practice indefinitely
>(since how they implement undefined behavior is their own business)
>or move to Jason's proposed rule (since doing so wouldn't break
>compatibility with well-defined programs).
John.

Sure.

Here is my test case and the results:
#include <stdio.h>
#include <stdarg.h>
struct foo {
   foo() : i(88) {
      printf("%p: foo ctor\n", this);
   }
   ~foo() {
      printf("%p: foo dtor\n", this);
   }
   foo(const foo &that) : i(that.i + 1) {
      printf("%p: foo cctor(%p)\n", this, &that);
   }
   int i;
};

int bar(int anchor, ...) {
   va_list ap;
   va_start(ap, anchor);

   foo b = va_arg(ap, foo);
   printf("bar's b.i is: %d\n", b.i);
   return anchor;
}

int main() {
   foo f;
   f.i = 99;
   printf("try this: %.16llx\n", f);
   return bar(0, f);
}

"class_vararg.c", line 20: warning #3291-D: a non-POD class type cannot be
          fetched by va_arg
     foo b = va_arg(ap, foo);
                        ^
"class_vararg.c", line 28: warning #3290-D: Passing a non-POD object to a
          function with variable arguments has undefined behavior.  Object
          will be copied onto the stack instead of using a constructor.
     printf("try this: %.16llx\n", f);
                                   ^
"class_vararg.c", line 28: warning #2181-D: argument is incompatible with
          corresponding format string conversion
     printf("try this: %.16llx\n", f);
                                   ^
"class_vararg.c", line 29: warning #3290-D: Passing a non-POD object to a
          function with variable arguments has undefined behavior.  Object
          will be copied onto the stack instead of using a constructor.
     return bar(0, f);
                   ^

$ a.out
7fffe7c0: foo ctor
try this: 0000006300000000
7fffe764: foo cctor(7fffe760)
bar's b.i is: 100
7fffe764: foo dtor
7fffe7c0: foo dtor

The ctors and dtors balance.


More information about the cxx-abi-dev mailing list