Thread overview
[Issue 5494] New: [patch,enh] Issues with std.stdarg
Jan 27, 2011
Rob Jacques
Feb 07, 2011
Brad Roberts
Feb 07, 2011
Rob Jacques
January 27, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5494

           Summary: [patch,enh] Issues with std.stdarg
           Product: D
           Version: D2
          Platform: Other
        OS/Version: Windows
            Status: NEW
          Keywords: patch
          Severity: enhancement
          Priority: P3
         Component: Phobos
        AssignedTo: nobody@puremagic.com
        ReportedBy: sandford@jhu.edu


--- Comment #0 from Rob Jacques <sandford@jhu.edu> 2011-01-26 23:56:47 PST ---
Currently, std.stdarg doesn't appear to be 64-bit safe (see Issue 4310) is extremely limited in functionality, and although mentioned in passing in the D-style Variadic Functions documentation, it isn't listed as a Phobos module. With regard to functionality, std.stdarg contains a single function ("va_arg") which interprets _argptr as a pointer to type T, returns a T and advances _argptr by T.sizeof adjusted to 32-bit alignment (see Issue 4310). This is unsafe, as _argptr may not actually be T* and therefore will be mis-aligned post va_arg. Given that D provides type safe Variadic Functions via the _arguments TypeInfo[], a better solution whould be to use the correct TypeInfo.tsize when advancing _argptr. Further more, there are use cases (std.boxer/std.variant, etc) which work with void*/TypeInfo directly and must currently maintain correct stack alignment manually. As a solution to these issues, I'm proposing the VariadicArguments range listed below. Note that switching the assert in get to enforce should allow all methods to be @trusted or @safe.


/** Iterates a set of D-style variadic function arguments in a safe manner.
 * Example:
 * --------
    void foo(...) {
        auto va_args = VariadicArguments(_arguments,_argptr) ;
        assert(va_args.length == 6);
        assert(va_args.get!uint   == 1); va_args.popFront;
        assert(va_args.get!int    == 2); va_args.popFront;
        assert(va_args.get!long   == 3); va_args.popFront;
        assert(va_args.get!float  == 4); va_args.popFront;
        assert(va_args.get!double == 5); va_args.popFront;
        assert(va_args.get!real   == 6); va_args.popFront;
    }
    foo(1u,2,3L,4f,5.0,6.0L);
 * --------
 */
struct VariadicArguments {
    private TypeInfo[] args;
    private void*      ptr;

    this(TypeInfo[] arguments, void* argptr) {
        args = arguments;
        ptr  = argptr;
    }

    /// Returns: true if there are no more arguments
    bool empty() const nothrow { return args.empty; }

    /// Returns: a copy of this.
          VariadicArguments  save()       nothrow { return this; }
    const(VariadicArguments) save() const nothrow { return this; } ///ditto

    /// Advances to the next argument
    void popFront() {
        ptr = ptr + ((args.front.tsize + size_t.sizeof - 1) & ~(size_t.sizeof -
1));
        args.popFront;
    }

    /// Returns: a tuple of an untyped pointer to the current argument and it's
TypeInfo.
    Tuple!(void*,TypeInfo) front() { return tuple(ptr,args.front); }


    /// Returns: the number of arguments
    size_t length() const nothrow { return args.length; }

    /// Returns: the current argument interpreted as type T
    T get(T)() nothrow {
        assert(typeid(T).toString() == args.front.toString(),
               "VariadicArguments.get: mis-matching types:
"~typeid(T).toString~" vs. "~args.front.toString);
        return *cast(T*)ptr;
    }
}

unittest {
    void foo(...) {
        auto va_args = VariadicArguments(_arguments,_argptr) ;
        assert(va_args.length == 6);
        assert(va_args.get!uint   == 1); va_args.popFront;
        assert(va_args.get!int    == 2); va_args.popFront;
        assert(va_args.get!long   == 3); va_args.popFront;
        assert(va_args.get!float  == 4); va_args.popFront;
        assert(va_args.get!double == 5); va_args.popFront;
        assert(va_args.get!real   == 6); va_args.popFront;
    }
    foo(1u,2,3L,4f,5.0,6.0L);
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 07, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5494


Brad Roberts <braddr@puremagic.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |braddr@puremagic.com


--- Comment #1 from Brad Roberts <braddr@puremagic.com> 2011-02-07 00:22:39 PST ---
I think this one can be closed with the next release.  druntime's vararg support has been updated to support the x86-64 c abi.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 07, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=5494



--- Comment #2 from Rob Jacques <sandford@jhu.edu> 2011-02-07 09:22:50 PST ---
Well, I think Issue 4310 can be closed, so long as std.stdarg gets depreciated in favor of core.stdarg. There is an API mismatch between the 32-bit and 64-bit core.stdarg, which should be fixed (I'd suggest making core.stdarg simply forward to core.stdc.stdarg, which is correct). Also, I think the idea of a range which wraps _arguments, _argptr and provides a simple and safe way to use variadic arguments would be a useful enhancement to dRuntime.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------