https://bugs.winehq.org/show_bug.cgi?id=47285
Bug ID: 47285 Summary: widl generates incorrect format strings when using -Oicf flag Product: Wine Version: 4.9 Hardware: x86 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: tools Assignee: wine-bugs@winehq.org Reporter: richard@torproject.org Distribution: ---
Assuming the following idl snippet:
interface type_format_bug { void get_string_list( [in] long clientCount, [out, size_is(,clientCount), length_is(,*serverCount)] BSTR **strings, [out, retval] long *serverCount); }
The generated format strings have at least two crash-causing issues. Here's the generated proc and type format strings when using -Oicf flag. I've inlined two changes which fix things.
static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString = { 0, { /* 0 (procedure marshal_bug::get_string_list) */ 0x32, /* FC_BIND_PRIMITIVE */ 0x48, NdrFcLong(0x0), NdrFcShort(0x0), /* method 0 */ NdrFcShort(0xc), /* stack size = 12 */ NdrFcShort(0x8), /* client buffer = 8 */ NdrFcShort(0x8), /* server buffer = 8 */ 0x41, 0x03, /* 3 params */ 0x08, 0x00, NdrFcShort(0x0), NdrFcShort(0x0), NdrFcShort(0x0), /* 24 (parameter clientCount) */ NdrFcShort(0x48), /* flags: in, base type */ NdrFcShort(0x0), /* stack offset = 0 */ 0x08, /* FC_LONG */ 0x0, /* 30 (parameter strings) */ NdrFcShort(0x2113), /* flags: must size, must free, out, simple ref, srv size=8 */ NdrFcShort(0x4), /* stack offset = 4 */ /** ORIGINAL **/ // NdrFcShort(0x36), /* type offset = 54 */ /** FIXED: without this change the server process fails while attempting to call BSTR_UserMarshal; the passed in source BSTR is some stack pointer **/ NdrFcShort(58), /* type offset = 58 */ /* 36 (parameter serverCount) */ NdrFcShort(0x2150), /* flags: out, base type, simple ref, srv size=8 */ NdrFcShort(0x8), /* stack offset = 8 */ 0x08, /* FC_LONG */ 0x0, 0x0 } };
static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString = { 0, { NdrFcShort(0x0), /* 2 (unsigned short[]) */ 0x1b, /* FC_CARRAY */ 0x1, /* 1 */ NdrFcShort(0x2), /* 2 */ 0x9, /* Corr desc: field clSize, FC_ULONG */ 0x0, /* no operators */ NdrFcShort(0xfffc), /* offset = -4 */ 0x06, /* FC_SHORT */ 0x5b, /* FC_END */ /* 12 (FLAGGED_WORD_BLOB) */ 0x17, /* FC_CSTRUCT */ 0x3, /* 3 */ NdrFcShort(0x8), /* 8 */ NdrFcShort(0xfff2), /* Offset= -14 (2) */ 0x08, /* FC_LONG */ 0x08, /* FC_LONG */ 0x5c, /* FC_PAD */ 0x5b, /* FC_END */ /* 22 (wireBSTR) */ 0x12, 0x0, /* FC_UP */ NdrFcShort(0xfff4), /* Offset= -12 (12) */ /* 26 (BSTR) */ 0xb4, /* FC_USER_MARSHAL */ 0x83, /* Alignment= 3, Flags= 80 */ NdrFcShort(0x0), /* Function offset= 0 */ NdrFcShort(0x4), /* 4 */ NdrFcShort(0x0), /* 0 */ NdrFcShort(0xfff4), /* Offset= -12 (22) */ /* 36 (BSTR *) */ 0x21, /* FC_BOGUS_ARRAY */ 0x3, /* 3 */ NdrFcShort(0x0), /* 0 */ 0x28, /* Corr desc: parameter clientCount, FC_LONG */ 0x0, /* no operators */ NdrFcShort(0x0), /* offset = 0 */ 0x28, /* Corr desc: parameter serverCount, FC_LONG */ 0x54, /* FC_DEREFERENCE */ NdrFcShort(0x8), /* offset = 8 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ 0x0, NdrFcShort(0xffe8), /* Offset= -24 (26) */ 0x5c, /* FC_PAD */ 0x5b, /* FC_END */ /* 54 */ 0x12, 0x0, /* FC_UP */ NdrFcShort(0xffec), /* Offset= -20 (36) */ /* 58 (BSTR **) */ /** ORIGINAL **/ // 0x11, 0x10, /* FC_RP [pointer_deref] */ /** FIXED: without this change (but with the previous change in the proc type string) the server crashes during cleanup attempting to free the 'strings' pointer which is stack alllocated **/ 0x11, 0x14, /* FC_RP [alloced_on_stack] [pointer_deref] */ NdrFcShort(0xfffa), /* Offset= -6 (54) */ /* 62 (LONG *) */ 0x11, 0x8, /* FC_RP [simple_pointer] */ 0x08, /* FC_LONG */ 0x5c, /* FC_PAD */ 0x0 } };
Format strings without -Oicf:
static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString = { 0, { /* 0 (parameter clientCount) */ 0x4e, /* FC_IN_PARAM_BASETYPE */ 0x08, /* FC_LONG */ /* 2 (parameter strings) */ 0x51, /* FC_OUT_PARAM */ 0x01, NdrFcShort(0x3a), /* type offset = 58 */ /* 6 (parameter serverCount) */ 0x51, /* FC_OUT_PARAM */ 0x01, NdrFcShort(0x3e), /* type offset = 62 */ /* 10 (void) */ 0x5b, /* FC_END */ 0x5c, /* FC_PAD */ 0x0 } };
static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString = { 0, { NdrFcShort(0x0), /* 2 (unsigned short[]) */ 0x1b, /* FC_CARRAY */ 0x1, /* 1 */ NdrFcShort(0x2), /* 2 */ 0x9, /* Corr desc: field clSize, FC_ULONG */ 0x0, /* no operators */ NdrFcShort(0xfffc), /* offset = -4 */ 0x06, /* FC_SHORT */ 0x5b, /* FC_END */ /* 12 (FLAGGED_WORD_BLOB) */ 0x17, /* FC_CSTRUCT */ 0x3, /* 3 */ NdrFcShort(0x8), /* 8 */ NdrFcShort(0xfff2), /* Offset= -14 (2) */ 0x08, /* FC_LONG */ 0x08, /* FC_LONG */ 0x5c, /* FC_PAD */ 0x5b, /* FC_END */ /* 22 (wireBSTR) */ 0x12, 0x0, /* FC_UP */ NdrFcShort(0xfff4), /* Offset= -12 (12) */ /* 26 (BSTR) */ 0xb4, /* FC_USER_MARSHAL */ 0x83, /* Alignment= 3, Flags= 80 */ NdrFcShort(0x0), /* Function offset= 0 */ NdrFcShort(0x4), /* 4 */ NdrFcShort(0x0), /* 0 */ NdrFcShort(0xfff4), /* Offset= -12 (22) */ /* 36 (BSTR *) */ 0x21, /* FC_BOGUS_ARRAY */ 0x3, /* 3 */ NdrFcShort(0x0), /* 0 */ 0x28, /* Corr desc: parameter clientCount, FC_LONG */ 0x0, /* no operators */ NdrFcShort(0x0), /* offset = 0 */ 0x28, /* Corr desc: parameter serverCount, FC_LONG */ 0x54, /* FC_DEREFERENCE */ NdrFcShort(0x8), /* offset = 8 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ 0x0, NdrFcShort(0xffe8), /* Offset= -24 (26) */ 0x5c, /* FC_PAD */ 0x5b, /* FC_END */ /* 54 */ 0x12, 0x0, /* FC_UP */ NdrFcShort(0xffec), /* Offset= -20 (36) */ /* 58 (BSTR **) */ 0x11, 0x14, /* FC_RP [allocated_on_stack] [pointer_deref] */ NdrFcShort(0xfffa), /* Offset= -6 (54) */ /* 62 (LONG *) */ 0x11, 0xc, /* FC_RP [allocated_on_stack] [simple_pointer] */ 0x08, /* FC_LONG */ 0x5c, /* FC_PAD */ 0x0 } };
One thing to note is that the existence of other functions taking BSTR's (as with IAccessibleAction in the IAccessible2 spec) seems to only result in the missing 'allocated_on_stack' flag problem.