Bug 15417 – Wrong parameter passing for variadic nested functions within aggregate
Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2015-12-07T22:16:00Z
Last change time
2016-01-03T14:02:47Z
Keywords
industry, wrong-code
Assigned to
nobody
Creator
mathias.lang
Comments
Comment #0 by mathias.lang — 2015-12-07T22:16:03Z
```
import core.stdc.stdarg;
class C
{
private void method ()
{
void test (ulong c1, ...)
{
va_list ap;
va_start(ap, _argptr);
assert(char.init == va_arg!(char)(ap));
}
test(4242UL, char.init);
}
}
void main ()
{
auto c = new C;
c.method;
}
```
Result in a SEGV:
```
Program received signal SIGSEGV, Segmentation fault.
core.stdc.stdarg.va_arg!(char).va_arg(core.stdc.stdarg.__va_list_tag*, ref char) (parmn=@0x7fffffffd6c0: 255 '\377', apx=0x0)
at /usr/include/dmd/druntime/import/core/stdc/stdarg.d:233
233 if (ap.offset_regs < 6 * 8 && T.sizeof <= 8)
(gdb) bt
#0 core.stdc.stdarg.va_arg!(char).va_arg(core.stdc.stdarg.__va_list_tag*, ref char) (parmn=@0x7fffffffd6c0: 255 '\377', apx=0x0)
at /usr/include/dmd/druntime/import/core/stdc/stdarg.d:233
#1 0x000000000041f391 in core.stdc.stdarg.va_arg!(char).va_arg(core.stdc.stdarg.__va_list_tag*) (ap=0x0)
at /usr/include/dmd/druntime/import/core/stdc/stdarg.d:198
#2 0x000000000041f33b in vararg.C.method().test(ulong, ...) (
this=0x7ffff7eec000, _arguments_typeinfo=0x648360 <TypeInfo_B1a.init$>,
c1=4242) at vararg.d:11
#3 0x000000000041f2d7 in vararg.C.method() (this=0x7ffff7eec000)
at vararg.d:13
#4 0x000000000041f36a in D main () at vararg.d:20
```
Tested with struct too.
Tested with 2.066.1, 2.069, and master as of now (v2.069-devel-4afb98f)
Comment #1 by ibuclaw — 2015-12-08T10:16:24Z
If only dmd warned you against bad code:
---
$ gdc valist.d
valist.d: In function ‘test’:
valist.d:10:13: warning: second parameter of ‘va_start’ not last named argument [-Wvarargs]
va_start(ap, _argptr);
^
---
Use `va_start(ap, c1);'
Besides, if _argptr isn't initialized properly (it segfaults when you use it directly) that is a bug.
Comment #2 by mathias.lang — 2015-12-08T11:03:55Z
Oops :P
Well, using `c1` doesn't change a thing here (and va_start is not needed here according to the docs).
Test case closer to the original bug:
```
import std.stdio, core.stdc.stdarg;
class C
{
private void method ()
{
void test (ulong c1, ...)
{
check(c1, _argptr, _arguments);
}
test(4242UL, char.init);
}
}
void check (ulong c1, va_list arglist, TypeInfo[] ti)
{
assert(ti.length == 1);
assert(ti[0].toString() == "char");
writeln("Now Segv");
assert(char.init == va_arg!(char)(arglist));
}
void main ()
{
auto c = new C;
c.method;
}
```
This is technically a regression (worked in D1). And obviously it works with GDC :)
Comment #3 by bugzilla — 2015-12-20T05:52:15Z
_argptr and _arguments are there for "D style variadics". core.stdc.stdarg is for "C style variadics". I.e. using va_arg for C-style will not work.
Comment #4 by ibuclaw — 2015-12-26T10:12:13Z
(In reply to Walter Bright from comment #3)
> _argptr and _arguments are there for "D style variadics". core.stdc.stdarg
> is for "C style variadics". I.e. using va_arg for C-style will not work.
I beg your pardon?
The _argptr variable is computed from va_start, so is perfectly valid for use in va_arg. See for example, std.format.doFormat!()
Comment #5 by ibuclaw — 2015-12-26T10:21:47Z
(In reply to Mathias Lang from comment #2)
> assert(char.init == va_arg!(char)(arglist));
Is it the same if you do.
char buf;
va_arg(ap, arglist[0], &buf);
assert(char.init == buf);