mctrl
mctrl copied to clipboard
Broken image in example ex_html.exe on Windows 8 and 8.1
When running ex_html.exe built with mingw-w64 on Windows 8 and 8.1, a PNG image is not shown in the HTML page.
Investigation showed the following facts:
- When built with MSVC 2010 Express, the problem does not occur.
- On Windows 7 and XP it does not occur.
- The problem disappears if the ex_html.exe does not have manifest (RT_MANIFEST), or if the manifest is smaller then 512 bytes.
- By adding more HTML resources or by reodering them (involves renaming them as they are sorted by
windres
), different resource may be made broken instead. - The resource seems to be correct in that sense that if the ex_html.exe uses
FindResource()
+LoadResource()
+LockResource()
and saves the resource into the file (at end of the program), it is valid PNG image binary equal to the source one. PerhapsMSHTML.DLL
accesses it in a different way rather then using those Win32 functions???
More observations:
- The issue does not occur when the resource is in a module not linked into the .EXE. It is enough to rename the original .exe to 'foo.exe' and change the URLs in the original resources accordingly (to begin with
res://foo.exe/
)
Even more observations. It seems that many conditions have to be met in order to reproduce the bug:
- OS is Win 8 or 8.1.
- ex_html.exe must be built with gcc toolchain (gcc + binutils). ex_html.exe built with MSVC does not exhibit the issue (even when used together with mCtrl.dll built with gcc)
- Both 32-bit and 64-bit builds have the bug.
- ex_html.exe must have the application manifest resource (removing it fixes the issue).
- The web browser must be embedded in the process. Accessing the resource from other process (e.g. from a renamed copy of ex_html.exe with changed URLs referring to resources in the broken ex_html.exe) does not lead to the bug.
- It is 1st run of ex_html.exe (since reboot, after (re)built, copied, or at least
touch
ed). Subsequent runs do not trigger the issue.
Gosh. This issue is big mystery to me.
As the issue seems to be related to layout of resources in .rsrc section, I performed several analyzes and experiments.
- Updated ex_html.exe to access the "broken" resources with
FindResource() + LoadResource()
on app. exit (i.e. after the bug happens) and saved them to a file. They are genuine and same as the "unbroken" originals. - Commented the image resource in resource script. Other resource (the
doc.html
) got broken. - Placed various padding resources (custom resources created from zero-filled blocks of given length, never loaded by the program). Seems that resource of type 23 (i.e.
RT_MANIFEST - 1
) which is long enough "fixes" the issue. - Retried (3) and (2) together. Required length of the padding differs.
- Retried (2), (3) and (4) with 32 as well as 64-bit builds, and with various compile time options. For given resource script, the minimal length to "fix" the issue is always constant.
- Tried to edit resources in "broken" ex_html.exe with resource hacker: Added a dummy resource, saved and then removed it back. This way, I assume, I forced the Windows API (
BeginUpdateResource()
+ related functions). Result was not same as that one ofRC.EXE
but much closer thenwindres.exe
. Again this "fixed" the issue.
Is it possible there is incompatibility between windres
, and some part of Windows 8 (which may be the embedded browser, dynamic loader which surely interprets the manifest or whatever)???
Manually analyzed hex-dump of the .rsrc
section, both from ex_html.exe built with gcc and MSVC:
- Both seem to follow .rsrc correctly (as described here: http://www.thehackademy.net/madchat/vxdevl/papers/winsys/pefile/pefile.htm).
- However the two differ a lot. Layout of the tree making the resources directories and order of resource raw data is very different.
- In general MSVC (or
RC.EXE
) seems to be much more generous about padding in .rsrc section.
Tried once again to verify correctness of mCtrl.dll + ex_html.exe code:
- Asked friend to make an independent review
MC_WC_HTML
control implementation as well as code of ex_html.exe. No output. - Run with AppVerifier. No usable output.
- Run with DrMemory. On Windows XP and 7, it does not find any issue. On Windows 8.1 it crashes with ex_html.exe.
- Scanned with Coverity. No issue.
- Tried to remove as much non-essential code from
MC_WC_HTML
as possible. Bug still happens.
Enabled HTML traces (-DHTML_DEBUG=1
), run ex_html.exe multiple times. When compared the 1st run (when the bug happens) and subsequent runs (when it does not):
- All logged calls to COM interfaces implemented in
html.c
are same and it the very same order. - Strangely there is only one difference in the logs (when ignoring thread ID and timestamps of logged messages): The 1st run logs 10 times about
DllMain(DLL_THREAD_ATTACH)
while subsequent runs do 11 times. The 6th (sic!) started thread is the one that is missing in the 1st run. - Verified that all calls to the COM objects implemented in html.c are performed in the context of the main thread (as of ex_html.exe).
What the hell is going on??
Tried one more intersting experiment:
- Compiled ex_html.rc into ex_html.rc.obj by
windres
from the mingw-w64 toolchain. - Compiled ex_html.c into ex_html.c.obj by MSVC 12 compiler.
- Linked the two together with MSVC 12 linker.
The bug is still there. By this I consider more or less proved the issue is about incompatibility of windres
from GNU binutils and something in Windows 8 or 8.1. Given the bug happens only on the 1st run, it may involve some caching in some Windows subsystem.
Perhaps dynamic loader somehow and very subtly breaks state of loaded ex_html.exe
image when accessing the application manifest in it (in a way colliding only with resource layout as output by windres
but not RC.EXE
. Arguably, Windows might cache the manifest for next app. starts so the subsequent starts do not trigger the bug. But this paragraph is pure speculation.
Reported in binutils bugzilla: https://sourceware.org/bugzilla/show_bug.cgi?id=17184