[Bug 16187] Google Sketchup Layout crashes on startup

wine-bugs at winehq.org wine-bugs at winehq.org
Fri Dec 19 18:36:53 CST 2008


http://bugs.winehq.org/show_bug.cgi?id=16187


Anastasius Focht <focht at gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |focht at gmx.net




--- Comment #2 from Anastasius Focht <focht at gmx.net>  2008-12-19 18:36:53 ---
Hello,

gdiplus bug: unsupported image stream codec requested.

--- snip ---
...
0032:Call ole32.CreateStreamOnHGlobal(00000000,00000001,0032d580) ret=00528955 
...
0032:Ret  ole32.CreateStreamOnHGlobal() retval=00000000 ret=00528955
0032:Call gdiplus.GdipGetImageEncodersSize(0032d564,0032d568) ret=0052888f
0032:trace:gdiplus:GdipGetImageEncodersSize 0x32d564 0x32d568
0032:Ret  gdiplus.GdipGetImageEncodersSize() retval=00000000 ret=0052888f
...
0032:Call gdiplus.GdipGetImageEncoders(00000001,0000004c,01014698) ret=005288af
0032:trace:gdiplus:GdipGetImageEncoders 1 76 0x1014698
0032:Ret  gdiplus.GdipGetImageEncoders() retval=00000000 ret=005288af
...
0032:Call gdiplus.GdipSaveImageToStream(068da908,06af41a0,0032d584,00000000)
ret=00528981
0032:trace:gdiplus:GdipSaveImageToStream 0x68da908 0x6af41a0 0x32d584 (nil)
0032:Ret  gdiplus.GdipSaveImageToStream() retval=0000000d ret=00528981
...
0032:Ret  KERNEL32.SetLastError() retval=00000578 ret=79e74af7
0032:CALL gdiplus.GdipLoadImageFromStream(0568d0d0,0032d580) ret=0147a1d4
0032:RET  gdiplus.GdipLoadImageFromStream() retval=00000002 ret=0147a1d4
--- snip ---

A default (invalid, see later comment) CLSID is passed which leads to:

GdipSaveImageToStream -> UnknownImageFormat

Due to unhandled image format, the stream parameter will be NULL which leads
to:

GdipLoadImageFromStream -> InvalidParameter

and managed exception which goes by unhandled.
The app's own crash hander finally catches it, hence the error dialog.

---

The real problem is actually not visible with trace, one has to debug through.

What really happens is that the app tries to resolve gdiplus image codec for
specific MIME formats by looping through the list of encoders returned by
GdipGetImageEncoders().
It compares the MIME type of each returned encoder entry to the given MIME.
On match the class identifier of that encoder is used.
The default (invalid) CLSID gets overwritten with the one found by successful
lookup.

The MIME type for requested codec "bad guy" is actually "image/tiff".
Wine's gdiplus misses encoders/decoders for various famous image formats.
Maybe additional image formats support can be added by the use of libtiff (and
libjpeg for jpeg stuff, ...).

FYI it also suffers from bug 13462

=================

--- snip ---
Installing gdiplus seems to make things worse; even after
uninstalling it, layout crashes much sooner.
--- snip ---

A bit lengthy story which might deserve its own bugzilla bug but I will explain
here ...

This app early binds to gdiplus.dll (using dllimports) while parts the .NET
runtime also bind to gdiplus (manifest+activation context mechanism).

When you do the usual native gdiplus override (using winetricks gdiplus) you
install/copy gdiplus.dll into system32 folder.
With the installation of the .NET Framework another copy will be installed in
private load path: C:\windows\Microsoft.NET\Framework\v2.0.50727\gdiplus.dll
(due to installer winver w2k hack -> missing junction API).

When the app load time reference to gdiplus is resolved (explicit dll import),
gdiplus is loaded from system32.
Later when parts of the .NET runtime are initialized, another copy will be
loaded by .NET from private load path
"C:\windows\Microsoft.NET\Framework\v2.0.50727\".
This happens because .NET initially tries to load the SxS version using
manifest/activation context and this fails because SxS version not present.

As fallback method, gdiplus library is directly loaded with private load path,
resulting in another copy loaded with different base address.
This fallback to private load path exists to prevent dll pollution from
unknown/unwanted library version in system32.
Result: two copies exist in memory with different base addresses.

Gdiplus API relies on Gdiplusstartup()/shutdown() being called, otherwise most
of its API won't work and you see all sorts of side-effects/crashes.
Try to call native gdiplus API before Gdiplusstartup() and you will see...

Now consider the following:

---
Scenario 1 (one gdiplus dll from SxS present in memory because of
manifest/activation context/SxS):

When the app tries to use gdiplus API for the first time, .NET already
initialized gdiplus (for itself) hence the app can successfully use the API
too.
Because of late .NET unload mechanism, the bug (scenario 3) goes unnoticed.

---
Scenario 2 (two gdiplus dlls present in memory, wine builtin + .NET native from
private load path):

Because Wine doesn't employ gdiplus object tracking/reference counting (see
comments in gdiplusstartup/shutdown) it doesn't impose restrictions when API
can be called (like allocation, ..).
The dll loaded by app will be used by app code while .NET will use the dll from
private load path and call API on it.
-> not really good but acceptable for now

---
Scenario 3 (two gdiplus dlls present in memory, wine native override from
system32 + .NET native from private load path):

Both libraries are present in memory at different base addresses.
The app will call API on the gdiplus loaded by itself and goes *boom* because
it didn't explicitly call gdiplusstartup.
.NET runtime will initialize its own loaded version and call API on it.

In short: Technically it's an g00gle application bug which is hidden in Windows
due to scenario 1 but exposed in Wine due to scenario 3.

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