[Bug 10368] Corel Draw X3 Won't Install
wine-bugs at winehq.org
wine-bugs at winehq.org
Sat Aug 9 05:51:37 CDT 2008
http://bugs.winehq.org/show_bug.cgi?id=10368
Anastasius Focht <focht at gmx.net> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |focht at gmx.net
--- Comment #12 from Anastasius Focht <focht at gmx.net> 2008-08-09 05:51:36 ---
Hello,
random pick of the day ;-)
I downloaded the X3 trial version.
James' analysis (comment #6) is correct so far.
Sub-installer custom action "CA_AcquireKey" fails due to MAIN_INSTALL_DLG_TITLE
containing garbage.
And yes, custom action "CA_Callit" which builds the action string contains some
code which looks like subtile application bug.
In short: Differences in Wine and Windows heap block management let this app
succeed in Windows - despite an application bug.
Following is the stack before a sequence of internal installer function calls
which ultimately lead to the bug:
--- snip ---
$+0 7ED445F8 ptr 009D0B28
$+4 1001C830 "%s SERIALNUMBER="%s""
$+8 009D0B28 "ACTIONTODO="AcquireKey" MAIN_INSTALL_DLG_TITLE="Setup
Initialization""
$+C 7ED44604 "DR13WTX-9999998-YSP"
..
--- snip ---
$+0 = pointer to destination buffer address (dest = heap allocated)
$+4 = format string
$+8 = first vararg parameter for format string call (heap allocated)
$+C = second vararg parameter for format string call (stack allocated)
Notice how the destination buffer address is actually the same as first vararg
parameter (part of problem).
Lets dissect the memory block of interest.
I formatted all memory blocks in single dword format which makes them easier to
read/comment (address | DWORD value | ASCII reprs. | comment).
--- snip #1 ---
(wine heap block header)
009D0B10 00000058 X... ; ARENA_INUSE.size
009D0B14 02455355 USE. ; ARENA_INUSE.unused_bytes, ARENA_INUSE.magic
(app internal buffer part)
009D0B18 10027450 Pt.. ; vtable pointer for some string manager
009D0B1C 00000045 E... ; length of currently used data
009D0B20 00000045 E... ; length of allocated data
009D0B24 00000001 .... ; reference count for this string object
009D0B28 49544341 ACTI ; begin of string buffer
..
009D0B68 6E6F6974 tion
009D0B6C 50410022 ".AP
--- snip #1 ---
Following is the first free block which is of interest (there is an in-use
block between both not of interest).
--- snip #2 ---
..
009D0BA0 00000221 !... ; ARENA_FREE.size
009D0BA4 45455246 FREE ; ARENA_FREE.magic
009D0BA8 009D00F8 ø.. ; ARENA_FREE.list_entry.FLink
009D0BAC 009D00E8 è.. ; ARENA_FREE.list_entry.BLink
009D0BB0 6F646E69 indo
...
--- snip #2 ---
Within the buggy sequence, a reallocation happens, hence the memory block
layout is as follows:
First memory block (which was previously allocated):
--- snip #3 ---
009D0B10 00000051 Q... ; ARENA_FREE.size
009D0B14 45455246 FREE ; ARENA_FREE.magic
009D0B18 009D00B8 ... ; ARENA_FREE.list_entry.FLink
009D0B1C 009D00A8 ... ; ARENA_FREE.list_entry.BLink
009D0B20 00000045 E...
009D0B24 00000001 ....
009D0B28 49544341 ACTI
..
009D0B68 6E6F6974 tion
009D0B6C 009D0B10 ... ;
--- snip #3 ---
Directly after (re)allocation:
Previously free, now newly allocated block to hold the result data.
--- snip #4 ---
009D0BA0 000000A0 ....
009D0BA4 05455355 USE.
009D0BA8 10027450 Pt..
009D0BAC 00000045 E...
009D0BB0 0000008A Š...
009D0BB4 00000001 ....
009D0BB8 49544341 ACTI
009D0BBC 4F544E4F ONTO
009D0BC0 223D4F44 DO="
009D0BC4 75716341 Acqu
009D0BC8 4B657269 ireK
009D0BCC 20227965 ey"
009D0BD0 4E49414D MAIN
009D0BD4 534E495F _INS
009D0BD8 4C4C4154 TALL
009D0BDC 474C445F _DLG
009D0BE0 5449545F _TIT
009D0BE4 223D454C LE="
009D0BE8 75746553 Setu
009D0BEC 6E492070 p In
009D0BF0 61697469 itia
009D0BF4 617A696C liza
009D0BF8 6E6F6974 tion
009D0BFC 69570022 ".Wi
...
--- snip #4 ---
And the same block after bug sequence:
--- snip #5 ---
009D0BA0 000000A0 ....
009D0BA4 05455355 USE.
009D0BA8 10027450 Pt..
009D0BAC 00000045 E...
009D0BB0 0000008A Š...
009D0BB4 00000001 ....
009D0BB8 49544341 ACTI
..
009D0BF0 61697469 itia
009D0BF4 617A696C liza
009D0BF8 6E6F6974 tion
009D0BFC 209D0B10 ..
009D0C00 49524553 SERI
009D0C04 554E4C41 ALNU
009D0C08 5245424D MBER
009D0C0C 5244223D ="DR
009D0C10 54573331 13WT
009D0C14 39392D58 X-99
009D0C18 39393939 9999
009D0C1C 53592D38 8-YS
009D0C20 00002250 P"..
..
--- snip #5 ---
Ok, that's a lot of heap block dumps ... let me explain what happens.
I'll provide a pseudo code sequence which I think resembles the bug behaviour.
It might not be 100% accurate, just to illustrate the problem.
Consider the following snippet:
--- pseudo code ---
void format_string_memfn( const char* formatstring, ...)
{
va_list ap;
va_start( ap, formatstring);
int required_length = get_required_length_for_format_operation(
formatstring, ap);
if( internal_string_buffer.length < required_length)
reallocate_internal_buffer( required_length);
vsnprintf( internal_string_buffer, required_length, formatstring, ap);
va_end(ap);
}
// instanciate string class object
some_string_class str;
..
// do some formatstring ops on string object
// str's internal buffer now contains "ACTIONTODO="AcquireKey"
MAIN_INSTALL_DLG_TITLE="Setup Initialization"
// I am evil
str.format_string_memfn( "%s SERIALNUMBER="%s"", (const char*) str,
"DR13WTX-9999998-YSP");
--- pseudo code ---
The internal format function checks if the expected result buffer size of
format operation is larger than internal storage.
If so, it reallocates the internal buffer (while preserving the content).
snippet #3 = previously allocated heap block, now marked free
snippet #4 = new buffer
The string format operation then copies the data into newly allocated buffer.
Now the problem: noticed the first vararg parameter?
It's actually a "raw" pointer to the internal representation of the string
buffer - at the time before the function call.
Most string classes provide such "operator const char * () const" to get a C
string representation of underlying object.
This means that even after internal reallocation to new heap block, the old
storage is still referenced by this parameter/pointer (va_list).
When the string copying for the first vararg param occurs, the old (now freed)
block contents are copied.
If you look closely at snippet #3 last DWORD you see "009D0B10".
It's actually a back pointer, set by Wine's heap manager when the block has
been marked as free. A part of string data has been overwritten.
The string copy operation copies until it encounters null terminator, hence
this back pointer data is taken as string data (see "209D0B10" data in snippet
#5).
Because Wine's heap manager is actually touching the data area by writing the
back pointer value to last 4 bytes when it marks the block as "free", the data
integrity is not preserved.
This behaviour is completely valid because application shall not touch the old
block anymore.
I can only guess that Windows heap manager preserves the old storage until next
heap calls/consolidation which lets this application succeed despite this nasty
bug.
If heap managers would clear heap blocks by default I guess many applications
will not work anymore due to such brain damaged code ;-)
I won't provide a patch here.
Wine's heap manager is something Julliard probably wants to fix himself.
Just a hint: if you keep the back pointer for free blocks at this place
(directly before the next arena header), provide sizeof(ARENA_FREE*) more
storage, to not let the back pointer overwrite data parts.
I already tested it - works ;-)
If this bug is fixed, you'll run into bug 2547
I'll have a look into that too ...
Regards
--
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
Do not reply to this email, post in Bugzilla using the
above URL to reply.
------- You are receiving this mail because: -------
You are watching all bug changes.
More information about the wine-bugs
mailing list