obsproject / obs-browser

CEF-based OBS Studio browser plugin
GNU General Public License v2.0
781 stars 222 forks source link

QCefWidget misses CEF main frame after being hidden once #375

Open StefanEnsmann opened 2 years ago

StefanEnsmann commented 2 years ago

Operating System Info

Windows 11

Other OS

No response

OBS Studio Version

28.0.0-beta2

OBS Studio Version (Other)

No response

OBS Studio Log URL

https://obsproject.com/logs/FVEWXEztE0yVkLau

OBS Studio Crash Log URL

None available

Expected Behavior

QCefWidget (nested in a QDialog) can set the URL and be shown properly after being closed.

Current Behavior

QCefWidget can set the initial URL and navigate to a different URL. After being hidden once, setting the URL for a new display causes a full OBS crash.

Steps to Reproduce

  1. Build Own3dPro plugin for OBS 28 https://github.com/StefanEnsmann/own3dpro-obs-plugin/tree/obs28
  2. Open the Theme Selector
  3. Close Theme Selector
  4. Re-open Theme Selector

Anything else we should know?

WizardCM commented 2 years ago

Please provide either the crash log or a stack trace from VS. It'll help determine whether the crash is in our own code, or deep within CEF.

StefanEnsmann commented 2 years ago
Exception thrown at 0x00007FFFC2E3E8D3 (obs-browser.dll) in obs64.exe: 0xC0000005: Access violation reading location 0x0000000000000000.

obs-browser.dll!CefBrowserCToCpp::GetMainFrame() Line 249
    at C:\dev\cef_binary_5060_windows_x64\libcef_dll\ctocpp\browser_ctocpp.cc(249)
obs-browser.dll!QCefWidgetInternal::setURL(const std::string & url_) Line 430
    at D:\obs2\plugins\obs-browser\panel\browser-panel.cpp(430)
own3d.dll!own3d::ui::browser::show() Line 70
    at C:\Users\Stefan\src\own3dpro-obs-plugin\source\ui\ui-browser.cpp(70)
Qt6Core.dll!00007fff7b9594c4()
Qt6Core.dll!00007fff7b95b9a4()
Qt6Gui.dll!00007fff7eb61c91()
Qt6Widgets.dll!00007fff7fd511b9()
Qt6Widgets.dll!00007fff7fd51034()
Qt6Widgets.dll!00007fff7fd570fa()
Qt6Widgets.dll!00007fff7fc0d980()
Qt6Widgets.dll!00007fff7fbd14ae()
Qt6Widgets.dll!00007fff7fbcf5e9()
Qt6Core.dll!00007fff7b920505()
Qt6Widgets.dll!00007fff7fbd50f2()
Qt6Widgets.dll!00007fff7fc2ac0b()
Qt6Widgets.dll!00007fff7fc28d6d()
Qt6Widgets.dll!00007fff7fbd14ae()
Qt6Widgets.dll!00007fff7fbd0674()
Qt6Core.dll!00007fff7b920505()
Qt6Gui.dll!00007fff7e8d4448()
Qt6Gui.dll!00007fff7e9203e8()
Qt6Core.dll!00007fff7ba73f04()
Qt6Gui.dll!00007fff7eb30fa9()
Qt6Core.dll!00007fff7b925874()
Qt6Core.dll!00007fff7b91e57d()
obs64.exe!run_program(std::basic_fstream<char,std::char_traits<char>> & logFile={...}, int argc=2, char * * argv=0x000001aa4de745d0) Line 2340
    at D:\obs2\UI\obs-app.cpp(2340)
obs64.exe!main(int argc, char * * argv=0x000001aa4de745d0) Line 3050
    at D:\obs2\UI\obs-app.cpp(3050)
obs64.exe!WinMain(HINSTANCE__ * __formal=0x0000000000000000, HINSTANCE__ * __formal=0x0000000000000000, char * __formal=0x0000000000000000, int __formal=0) Line 97
    at D:\a\obs-deps\obs-deps\windows_build_temp\qt6\qtbase\src\entrypoint\qtentrypoint_win.cpp(97)
[Inline Frame] obs64.exe!invoke_main() Line 102
    at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl(102)
obs64.exe!__scrt_common_main_seh() Line 288
    at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl(288)
kernel32.dll!00007ff811ed54e0()
ntdll.dll!00007ff81378485b()

Thanks for the prompt response. This is the VS stack trace to the point where the nullpointer is coming up. The exception then occurs one step out when trying to call ->LoadURL(...)

WizardCM commented 2 years ago

Interesting - that crash is within the CEF wrapper's code, rather than in ours directly.

I will look into this when I can, before 28's final release. That code hasn't changed on our side since it was introduced. Interestingly, we don't protect against an invalid GetMainFrame() result in most places, only in the SendBrowserProcessMessage macro.

In the meantime, what happens if you try showing the widget first (so swap lines 70 and 71 in source/ui/ui-browser.cpp) before trying to set the URL?

WizardCM commented 2 years ago

As a note:

public virtual CefRefPtr<CefFrame> GetMainFrame()= 0; Returns the main (top-level) frame for the browser. In the browser process this will return a valid object until after CefLifeSpanHandler::OnBeforeClose is called. In the renderer process this will return NULL if the main frame is hosted in a different renderer process (e.g. for cross-origin sub-frames). The main frame object will change during cross-origin navigation or re-navigation after renderer process termination (due to crashes, etc).

StefanEnsmann commented 2 years ago

Thanks a lot for your support. I swapped the lines and the result is the same. The window opens during the debugging step, but on the setURL afterwards it still crashes with _retval = 0x000....

You beat me to the comment from the source code, was just about to post it here as well