Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 350204

Summary: va_list assignment in printfExtend__I is unsafe for 64-bit Linux targets
Product: [Technology] RTSC Reporter: Sasha Slijepcevic <sascha>
Component: RuntimeAssignee: Dave Russo <d-russo>
Status: CLOSED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: cring, d-russo, dfriedland
Version: unspecified   
Target Milestone: 3.30.2   
Hardware: All   
OS: All   
Whiteboard: target:3.30.02
Bug Depends on:    
Bug Blocks: 436105    

Description Sasha Slijepcevic CLA 2011-06-23 18:27:54 EDT
In printfExtend we have an assignment
va_list va = *pva;
where pva is a va_list pointer. This works on target where va_list is char*, so we assign (char*) *pva to char* va, which is valid.
However, on some targets va_list is struct Somestruct[1], so we have
struct someStruct va[1] = *pva,
where pva is a pointer to an array. This doesn't work because va[1] can be initialized only by a literal array.

We could check if va_copy is defined and use it, or try to remove the need for copying.

More info:
http://www.velocityreviews.com/forums/t437602-varargss-doubt.html
http://e2e.ti.com/support/embedded/f/355/p/118367/421343.aspx#421343
Comment 1 Dave Russo CLA 2014-05-20 21:24:05 EDT
It appears that 64-bit Linux targets require more than a simple pointer for va_list.  So, in the interest of performance, a va_list is often typedef'd to be an array consisting of a single element rather than a simple pointer.  Making it an array means that when passing a va_list to a function, only the address of the first element array is passed _not_ the array itself.

This also has the consequence that any function that's passed a va_list _must never_ take the address of this parameter thinking that they have a pointer to a va_list.  For example, the following code is broken

    void doPrint(char *fmt, va_list *pva)
    {
        /* use *pva as a va_list */
        ... va_arg(*pva, ...);
    }

    void vprint(char *fmt, va_list va)
    {
        /* BUG: if va_list is an array type, &va doesn't point to a va_list!! */
        doPrint(fmt, &va);
    }

For a nice discussion of the issue see comments 10-14 of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14557.

The accepted solution to the issue is to use the C99 macro va_copy() to initialize a new va_list, pass a pointer to the initialized va_list, _and_ call va_end() to finalize use of the new va_list.  For example, a portable vprint() can be written as follows:
    void vprint(char *fmt, va_list va)
    {
        va_list nva;
        va_copy(nva, va);
        doPrint(fmt, &nva);
        va_end(nva);
    }

However, if the reason for defining a doPrint() to take a va_list* is to enable it to modify the original va_list, there is no need to take it's address in the first place!  The code above can be written as just 

    void doPrint(char *fmt, va_list va)
    {
        /* updates callers va list!!!! */
        ... va_arg(va, ...);
    }

    void vprint(char *fmt, va_list va)
    {
        doPrint(fmt, va);
    }

Notice that the type signature of doPrint() has to change.
Comment 2 Dave Russo CLA 2014-05-30 01:54:24 EDT
fixed in xdc-A41 (to be included in xdctools 3.30.02)
Comment 3 Sasha Slijepcevic CLA 2014-06-06 19:10:30 EDT
First I replicated the problem with the target Linux86_64 by adding platformprod-t42 to the package path. I also used 4.4.6 Gnu compiler configured with 64-bit support. With that setup, XDCtools 3.30.01 reports the following error when building an example:
package/cfg/Mod_p86U.c: In function ‘xdc_runtime_System_printfExtend__I’:
package/cfg/Mod_p86U.c:766: error: invalid initializer
package/cfg/Mod_p86U.c:846: error: incompatible types when assigning to type ‘VaList’ from type ‘struct __va_list_tag *’
package/cfg/Mod_p86U.c:859: error: incompatible types when assigning to type ‘va_list’ from type ‘struct __va_list_tag *’
package/cfg/Mod_p86U.c:900: error: incompatible types when assigning to type ‘VaList’ from type ‘struct __va_list_tag *’

After switching to 3.30.02.44, with the same target and the same example, the build completes without errors.
Comment 4 Sasha Slijepcevic CLA 2014-08-11 18:43:34 EDT
- shipped in XDCtools 3.30.02.44