[Bug 49195] New: Multiple 4k demoscene OpenGL demos crash on startup (failure to lookup atom 0xC019 'static' from global atom tables)

WineHQ Bugzilla wine-bugs at winehq.org
Mon May 18 13:51:35 CDT 2020


https://bugs.winehq.org/show_bug.cgi?id=49195

            Bug ID: 49195
           Summary: Multiple 4k demoscene OpenGL demos crash on startup
                    (failure to lookup atom 0xC019 'static' from global
                    atom tables)
           Product: Wine
           Version: 5.8
          Hardware: x86-64
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: user32
          Assignee: wine-bugs at winehq.org
          Reporter: focht at gmx.net
      Distribution: ---

Hello folks,

extracted from bug 48898

My comment: https://bugs.winehq.org/show_bug.cgi?id=48898#c12

--- quote ---
To me it looks like bug 18490 ("Multiple games fail to set pixel format on D3D
device context created on desktop window (Empire: Total War, Napoleon: Total
War, Utopia City)") but for GL device context on the desktop window.

According to online information it's not allowed to do any rendering using this
context but enough to call functions like glGetString() etc. 

Maybe some of the Wine graphics folks could weigh in with an opinion if this
limitation is already known / tracked in a bug?
--- quote ---

Henri's answer: https://bugs.winehq.org/show_bug.cgi?id=48898#c13

--- quote ---
I'm not aware of an existing bug report for this issue, no. It does strike me
as similar to bug 36506 though, and it would not particularly surprise me if
wglGetProcAddress() is supposed to return results consistent with
GL_EXTENSIONS/GL_VERSION here, even without a current GL context.

I seem to recall having established in the context of bug 18490 that creating a
GL context (or more specifically, setting a pixel format) on the desktop window
is indeed supposed to fail. In any case, this seems like of of those bugs that
would benefit from tests to establish what's supposed to happen.
--- quote ---

Turns out this was a side-effect of an earlier problem.
It was not supposed to be GetDC(NULL) (Desktop window).

--- snip ---
$ WINEDEBUG=+seh,+relay,+server,+class,+win,+msg wine ./End\ of\ time\ 720p.exe
>>log.txt 2>&1
...
0024:Call user32.ChangeDisplaySettingsA(00421288,00000004) ret=004200da 
...
0024: get_desktop_window( force=0 )
0024: get_desktop_window() = 0 { top_window=00010020, msg_window=00010026 } 
...
0024:Ret  user32.ChangeDisplaySettingsA() retval=00000000 ret=004200da
0024:Call
KERNEL32.CreateThread(00000000,00000000,004201ca,004304e8,00000000,00000000)
ret=004200ee 
...
0024:Ret  KERNEL32.CreateThread() retval=00000080 ret=004200ee
00bc: *fd* 17 <- 38
00bc: init_thread( unix_pid=3683, unix_tid=3729, debug_level=1, teb=7ffd4000,
entry=004201ca, reply_fd=15, wait_fd=17, cpu=x86 )
0024:Call
user32.CreateWindowExA(00000000,0000c019,00000000,91000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000)
ret=004200f4
0024:trace:win:WIN_CreateWindowEx (null) #c019 ex=00000000 style=91000000 0,0
0x0 parent=(nil) menu=(nil) inst=(nil) params=(nil)
00bc: init_thread() = 0 { pid=0020, tid=00bc, server_start=1d62d3b280579be
(-2.9701360), info_size=0, version=603, all_cpus=00000003, suspend=0 }
0024:trace:win:dump_window_styles style: WS_POPUP WS_VISIBLE WS_MAXIMIZE
0024:trace:win:dump_window_styles exstyle: 
...
00bc:Starting thread proc 0x4201ca (arg=0x4304e8) 
...
0024: create_window( parent=00010020, owner=00000000, atom=c019,
instance=00000000, dpi=96, awareness=2, class=L"" )
0024: create_window() = INVALID_HANDLE { handle=00000000, parent=00000000,
owner=00000000, extra=0, class_ptr=00000000, dpi=0, awareness=0 }
0024:warn:win:create_window_handle error 6 creating window
0024:trace:class:GetClassInfoExW (nil) #c019 0x1518f9e0
0024:trace:class:CLASS_FindClass #c019 0x7e910000 -> not found
0024:Ret  user32.CreateWindowExA() retval=00000000 ret=004200f4 
--- snip ---

The failing window creation resulted in NULL handle which got passed to
user32.GetDC():

--- snip ---
0024:Call user32.GetDC(00000000) ret=004200fb
0024:trace:win:GetDCEx hwnd 0x10020, hrgnClip (nil), flags 00000003 
...
0024: get_visible_region( window=00010020, flags=00000013 )
0024: get_visible_region() = 0 { top_win=00010020, top_rect={-1920,0;-1919,1},
win_rect={0,0;3200,1080}, paint_flags=00000001, total_size=16,
region={{-1920,0;1280,1080}} }
0024:Call
winex11.drv.GetDC(00030039,00010020,00010020,1518fde0,1518fdf0,00000013)
ret=7e97bd3e
0024:Ret  winex11.drv.GetDC() retval=00000001 ret=7e97bd3e
0024:trace:win:GetDCEx (0x10020,(nil),0x13): returning 0x30039 (updated)
0024:Ret  user32.GetDC() retval=00030039 ret=004200fb
--- snip ---

Well, the rest of the OpenGL story is known and the current behaviour makes
sense.
Back to the actual problem...

The creation of the window which ought the be used for OpenGL context/rendering
fails because atom 0xc019 can't be found/resolved.
I should have looked more carefully at the trace log and the demo disassembly.

--- snip ---
...
004200B6 | xor esi,esi                                          |               
004200B8 | push esi                                             |
004200B9 | push esi                                             |
004200BA | push esi                                             |
004200BB | push esi                                             |
004200BC | push esi                                             |
004200BD | push esi                                             |
004200BE | push esi                                             |
004200BF | push esi                                             |
004200C0 | push esi                                             |
004200C1 | push 91000000                                        |
004200C6 | push esi                                             |
004200C7 | push C019                                            | global atom!
004200CC | push esi                                             |
004200CD | push 4                                               |
004200CF | push end of time 720p.421288                         |
004200D4 | call dword ptr ds:[<&user32.ChangeDisplaySettingsA>] |
004200DA | push esi                                             |
004200DB | push esi                                             |
004200DC | push end of time 720p.4304E8                         |
004200E1 | push end of time 720p.4201CA                         |
004200E6 | push esi                                             |
004200E7 | push esi                                             |
004200E8 | call dword ptr ds:[<&KERNEL32.CreateThread>]         |
004200EE | call dword ptr ds:[<&user32.CreateWindowExA>]        | fails
004200F4 | push eax                                             |
004200F5 | call dword ptr ds:[<&user32.GetDC>]                  |
004200FB | mov edi,eax                                          |
004200FD | mov dword ptr ds:[3AB08EC],eax                       |
00420102 | push esi                                             |
00420103 | push edi                                             |
00420104 | push esi                                             |
00420105 | push end of time 720p.42125C                         |
0042010A | push edi                                             |
0042010B | call dword ptr ds:[<&gdi32.ChoosePixelFormat>]       |
00420111 | push eax                                             |
00420112 | push edi                                             |
00420113 | call dword ptr ds:[<&gdi32.SetPixelFormat>]          |
00420119 | call dword ptr ds:[<&opengl32.wglCreateContext>]     |
0042011F | push eax                                             |
00420120 | push edi                                             |
00420121 | call dword ptr ds:[<&opengl32.wglMakeCurrent>]       |
00420127 | call dword ptr ds:[<&user32.ShowCursor>]             |
0042012D | call end of time 720p.4202CC                         |
--- snip ---

The demoscene guys are crazy and fight for each saved byte ;-)

Courtesy of: http://www.pouet.net/topic.php?which=9894

--- quote ---
I was able to get 4 bytes off of a test 1k intro (Peach GLSL Shader of Japan)
by replacing the "edit" string with 0xC018, making it 1006 bytes instead of
1010. Nice.

...and then I got it down to 1004 bytes, because now "test eax, eax" compressed
better than "test ax, ax", which used to compress better sometime before this
newest change. ;) This 1k intro business is crazy, you'd really need some kind
of brute-force code masher that tries all possible combinations of code that
perform the same thing.
--- quote ---

--- quote ---
That´s mine since 2009 using DirectX9...someone told me using "static" instead
of "edit" would be better back then in some other thread...was iq if i remember
correctly.
The ATOM for "static" is 0xC019 btw, but be warned: it added 7 bytes here in my
first test, opposed to chopping off 4 bytes in case of "edit".
--- quote ---

--- quote ---
Oh, shit...i did the test the wrong way around...meaning the ATOM actually
chopped off 7 bytes in case of "static" vs. "0xC019" :/ :D
Yay, thanks for the nice trick, man! :)
--- quote ---

Also relevant, shows dump of global and typical local atom tables:

https://github.com/lungetech/ICAS/blob/master/logs/volatility/win32/output/atoms.txt

Wine source:

https://source.winehq.org/git/wine.git/blob/9e26bc811656ad8eb901bffa5528b9ce25d44bc3:/dlls/user32/class.c#l407

--- snip ---
 407 /***********************************************************************
 408  *           CLASS_FindClass
 409  *
 410  * Return a pointer to the class.
 411  */
 412 static CLASS *CLASS_FindClass( LPCWSTR name, HINSTANCE hinstance )
 413 {
 414     static const WCHAR comctl32W[] =
{'c','o','m','c','t','l','3','2','.','d','l','l',0};
 415     struct list *ptr;
 416     ATOM atom = get_int_atom_value( name );
 417 
 418     GetDesktopWindow();  /* create the desktop window to trigger builtin
class registration */
 419 
 420     if (!name) return NULL;
 421 
 422     name = CLASS_GetVersionedName( name, NULL, NULL, TRUE );
 423 
 424     for (;;)
 425     {
 426         USER_Lock();
 427 
 428         LIST_FOR_EACH( ptr, &class_list )
 429         {
 430             CLASS *class = LIST_ENTRY( ptr, CLASS, entry );
 431             if (atom)
 432             {
 433                 if (class->atomName != atom) continue;
 434             }
 435             else
 436             {
 437                 if (strcmpiW( class->name, name )) continue;
 438             }
 439             if (!class->local || class->hInstance == hinstance)
 440             {
 441                 TRACE("%s %p -> %p\n", debugstr_w(name), hinstance,
class);
 442                 return class;
 443             }
 444         }
 445         USER_Unlock();
 446 
 447         if (atom) break;
 448         if (!is_comctl32_class( name )) break;
 449         if (GetModuleHandleW( comctl32W )) break;
 450         if (!LoadLibraryW( comctl32W )) break;
 451         TRACE( "%s retrying after loading comctl32\n", debugstr_w(name) );
 452     }
 453 
 454     TRACE("%s %p -> not found\n", debugstr_w(name), hinstance);
 455     return NULL;
 456 }
--- snip ---

https://source.winehq.org/git/wine.git/blob/9e26bc811656ad8eb901bffa5528b9ce25d44bc3:/dlls/user32/class.c#l323

$ sha1sum atz-end_of_time.zip 
3a4ce3fd92e2fdd1a4533ee67d4809d3f2184f6b  atz-end_of_time.zip

$ du -sh atz-end_of_time.zip 
3.3M    atz-end_of_time.zip

$ wine --version
wine-5.8-173-g9e26bc8116

Regards

-- 
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