user32/gdi32: Fix for a crash in create_alpha_bitmap()

Peter Schlaile peter at schlaile.de
Mon Jan 31 08:45:24 CST 2011


Hi Alexandre,

On Mon, 31 Jan 2011, Alexandre Julliard wrote:

>> And: from a design perspective it sounds very strange that a fast
>> track optimisation *silently* changes protection bits!
>
> There's nothing silent about it, the protection bits have to match the
> DIB state.

Hmm. In which way changes StretchDIBits() the DIB state? Or: why should 
be a DIB, that is created using CreateDIBSection() as READWRITE, 
silently change it's state into READONLY? (At least, msdn-docs don't 
tell me anything about that... Can you provide me with a link? )

But, let's say for a moment, that this is true and the right(tm) 
behaviour:

Then create_alpha_bitmap() (within user32/cursoricon.c) seems to be broken.

It does the following:

* create a DIBSection

   alpha = CreateDIBSection( hdc, info, DIB_RGB_COLORS, &bits, NULL, 0)

* here we can savely expect bits to be writable (at least the
   msdn-documentation says so)

* in certain cases (if we are provided with a src_info-pointer), we do
   now:

   StretchDIBits( hdc, 0, 0, bm.bmWidth, bm.bmHeight,
                  0, 0, src_info->bmiHeader.biWidth,
                  src_info->bmiHeader.biHeight,
                  color_bits, src_info, DIB_RGB_COLORS, SRCCOPY );

* after that, bits is *probably* non-writable (depending on fast path or
   not) (I still find that *really* strange. Again: it depends on certain
   parameters of this function, specifically: if in and out parameters do
   match at enough places, the DIB bitmap *changes* it's state to
   READONLY, in other cases it doesn't. If that isn't a big surprise, what
   is? :) ).

* and here...

     /* pre-multiply by alpha */
     for (i = 0, ptr = bits; i < bm.bmWidth * bm.bmHeight; i++, ptr += 4)
     {
         unsigned int alpha = ptr[3];
         ptr[0] = ptr[0] * alpha / 255;
         ptr[1] = ptr[1] * alpha / 255;
         ptr[2] = ptr[2] * alpha / 255;
     }

* ... we write to the now readonly bits-array, which leads to a page
   fault.

This is everything within wine code, the application only called 
CreateIconFromResourceEx(), which then called create_alpha_bitmap() (so: 
no, I don't think, the app is broken :) It only triggered a seldomly used 
code path within wine. ).

Where is the page fault handler within wine and what should the page 
fault handler actually do in that situation?

If we can't expect the "bits"-pointer to be writable after a call to 
StretchDIBs(), create_alpha_bitmap() should be rewritten.

>> That wouldn't be a problem, if windows behaved exactly the same way.
>> (which it most likely does not, otherwise PNClient wouldn't crash,
>> right?).
>
> I wouldn't be surprised if there was a way to crash it on Windows too,
> that app is broken, it never gives the code a chance to handle the
> exception. This is not how exception handlers are supposed to work.

Well, it doesn't crash on Windows and is actually rock solid there.

And: do you want to say, that there is a page fault handler within 
wine, that can handle *that* case above?

We either have to rewrite create_alpha_bitmap() in a way, that doesn't 
call StretchDIBits() in the fast path case and solves problems 
differently or: we should fix it at the source (which I still think my 
patch does, since it follows the rules of least surprise...).

In either way, I hope we can agree on the following:

a) the app is *not* broken (at least not regarding it's usage of
    CreateIconFromResourceEx() )
b) wine code *is* broken here
c) we can work around the problem within create_alpha_bitmap() or
d) make StretchDIBits() a function a lot less surprising to call...

> Of course this specific issue would be fixed by a DIB engine, but there are
> other places where exceptions can happen internally, even on Windows.

At least, they seem to install the handler in such a clever way, that 
no problems seem to occur within Windows (several different versions).
That said: I'd have prefered, if they didn't do that, since it made my 
debugging session a lot longer...

>> Are you sure? 0 means: everything is transparent, and that sounds
>> like: we need an alpha channel, right?
>
> 0 means there's no alpha channel, which is what we are checking here.

Ouch! If that is really Windows behaviour, then it is really broken but 
bug-to-bug compatible :)

Cheers,
Peter

----
Peter Schlaile



More information about the wine-devel mailing list