Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[invalid] custom popup hosting / lifespan with Wpf.HwndHost causes crash on popup with ChromeStyle #4980

Open
1 task done
mitchcapper opened this issue Nov 15, 2024 · 2 comments

Comments

@mitchcapper
Copy link
Contributor

Is there an existing issue for this?

  • I have searched both open/closed issues, no issue already exists.

CefSharp Version

130

Operating System

Windows 10

Architecture

x64

.Net Version

.net 6

Implementation

WPF

Reproduction Steps

We don't quite have HwndHost integrated into the main CefSharp sample yet but if we did then uncommenting https://github.com/cefsharp/CefSharp/blob/master/CefSharp.Wpf.Example/Views/BrowserTabView.xaml.cs#L129-L183 would result in the crash (note if trying to repro with external HwndHost need to add the experimental handlers to the inclusion).

Once you do so just open a new popup (ie target= _blank) and it will crash.

Expected behavior

Not Crash

Actual behavior

Crashes

Regression?

Doubt it

Known Workarounds

Unable to find any

Does this problem also occur in the CEF Sample Application

No

Other information

This might be a bug in CEF based on the cef code comments but I can't reproduce it so we might be calling down some wrong path. It doesn't happen with WPF (non HwndHost) (or seemingly WinForms) but if the CEF comment is right the flow would only be an issue with chrome style not alloy style windows. See below for more details.

The error occurs because the 'pending popup' var set to empty and then it trying to copy properties from that.

src is: 0x00000000000000a8
(this seems to be a CEF constant for empty for pending popup)

so: target->windowless_frame_rate = src->windowless_frame_rate; throws a read error
>	libcef.dll!CefBrowserSettingsTraits::set(const _cef_browser_settings_t * src, _cef_browser_settings_t * target, bool copy) Line 500	C++
 	[Inline Frame] libcef.dll!CefStructBase<CefBrowserSettingsTraits>::Set(const _cef_browser_settings_t & source, bool copy) Line 108	C++
 	[Inline Frame] libcef.dll!CefStructBase<CefBrowserSettingsTraits>::operator=(const _cef_browser_settings_t & s) Line 116	C++
 	[Inline Frame] libcef.dll!CefStructBase<CefBrowserSettingsTraits>::operator=(const CefStructBase<CefBrowserSettingsTraits> & s) Line 112	C++
 	libcef.dll!CefBrowserInfoManager::WebContentsCreated(const GURL & target_url, const content::GlobalRenderFrameHostId & opener_global_id, CefStructBase<CefBrowserSettingsTraits> & settings, scoped_refptr<CefClient> & client, std::__Cr::unique_ptr<CefBrowserPlatformDelegate,std::__Cr::default_delete<CefBrowserPlatformDelegate>> & platform_delegate, scoped_refptr<CefDictionaryValue> & extra_info, content::WebContents * new_contents) Line 266	C++
 	libcef.dll!ChromeBrowserDelegate::WebContentsCreated(content::WebContents * source_contents, int opener_render_process_id, int opener_render_frame_id, const std::__Cr::basic_string<char,std::__Cr::char_traits<char>,std::__Cr::allocator<char>> & frame_name, const GURL & target_url, content::WebContents * new_contents) Line 508	C++
 	libcef.dll!content::WebContentsImpl::CreateNewWindow(content::RenderFrameHostImpl * opener, const content::mojom::CreateNewWindowParams & params, bool is_new_browsing_instance, bool has_user_gesture, content::SessionStorageNamespace * session_storage_namespace) Line 4862	C++
 	libcef.dll!content::RenderFrameHostImpl::CreateNewWindow(mojo::StructPtr<content::mojom::CreateNewWindowParams> params, base::OnceCallback<void (content::mojom::CreateNewWindowStatus, mojo::StructPtr<content::mojom::CreateNewWindowReply>)> callback) Line 9144	C++
 	libcef.dll!content::mojom::FrameHostStubDispatch::AcceptWithResponder(content::mojom::FrameHost * impl, mojo::Message * message, std::__Cr::unique_ptr<mojo::MessageReceiverWithStatus,std::__Cr::default_delete<mojo::MessageReceiverWithStatus>> responder) Line 5736	C++
 	libcef.dll!content::mojom::FrameHostStub<mojo::RawPtrImplRefTraits<content::mojom::FrameHost>>::AcceptWithResponder(mojo::Message * message, std::__Cr::unique_ptr<mojo::MessageReceiverWithStatus,std::__Cr::default_delete<mojo::MessageReceiverWithStatus>> responder) Line 860	C++
 	[Inline Frame] libcef.dll!mojo::InterfaceEndpointClient::HandleValidatedMessage(mojo::Message * message) Line 1005	C++
 	libcef.dll!mojo::InterfaceEndpointClient::HandleIncomingMessageThunk::Accept(mojo::Message * message) Line 371	C++
 	libcef.dll!mojo::MessageDispatcher::Accept(mojo::Message * message) Line 48	C++
 	libcef.dll!mojo::InterfaceEndpointClient::HandleIncomingMessage(mojo::Message * message) Line 724	C++
 	libcef.dll!IPC::ChannelAssociatedGroupController::AcceptSyncMessage(unsigned int interface_id, unsigned int message_id, IPC::`anonymous namespace'::ScopedUrgentMessageNotification scoped_urgent_message_notification) Line 1259	C++
 	[Inline Frame] libcef.dll!base::internal::DecayedFunctorTraits<void (IPC::ChannelAssociatedGroupController::*)(unsigned int, unsigned int, IPC::(anonymous namespace)::ScopedUrgentMessageNotification),IPC::ChannelAssociatedGroupController *&&,unsigned int &&,unsigned int &&,IPC::(anonymous namespace)::ScopedUrgentMessageNotification &&>::Invoke(void(IPC::ChannelAssociatedGroupController::*)(unsigned int, unsigned int, IPC::`anonymous namespace'::ScopedUrgentMessageNotification) method, scoped_refptr<IPC::ChannelAssociatedGroupController> && receiver_ptr, unsigned int && args, unsigned int && args, IPC::`anonymous namespace'::ScopedUrgentMessageNotification && args) Line 738	C++
 	[Inline Frame] libcef.dll!base::internal::InvokeHelper<0,base::internal::FunctorTraits<void (IPC::ChannelAssociatedGroupController::*&&)(unsigned int, unsigned int, IPC::(anonymous namespace)::ScopedUrgentMessageNotification),IPC::ChannelAssociatedGroupController *&&,unsigned int &&,unsigned int &&,IPC::(anonymous namespace)::ScopedUrgentMessageNotification &&>,void,0,1,2,3>::MakeItSo(void(IPC::ChannelAssociatedGroupController::*)(unsigned int, unsigned int, IPC::`anonymous namespace'::ScopedUrgentMessageNotification) && functor, std::__Cr::tuple<scoped_refptr<IPC::ChannelAssociatedGroupController>,unsigned int,unsigned int,IPC::(anonymous namespace)::ScopedUrgentMessageNotification> && bound) Line 930	C++
 	[Inline Frame] libcef.dll!base::internal::Invoker<base::internal::FunctorTraits<void (IPC::ChannelAssociatedGroupController::*&&)(unsigned int, unsigned int, IPC::(anonymous namespace)::ScopedUrgentMessageNotification),IPC::ChannelAssociatedGroupController *&&,unsigned int &&,unsigned int &&,IPC::(anonymous namespace)::ScopedUrgentMessageNotification &&>,base::internal::BindState<1,1,0,void (IPC::ChannelAssociatedGroupController::*)(unsigned int, unsigned int, IPC::(anonymous namespace)::ScopedUrgentMessageNotification),scoped_refptr<IPC::ChannelAssociatedGroupController>,unsigned int,unsigned int,IPC::(anonymous namespace)::ScopedUrgentMessageNotification>,void ()>::RunImpl(void(IPC::ChannelAssociatedGroupController::*)(unsigned int, unsigned int, IPC::`anonymous namespace'::ScopedUrgentMessageNotification) && functor, std::__Cr::tuple<scoped_refptr<IPC::ChannelAssociatedGroupController>,unsigned int,unsigned int,IPC::(anonymous namespace)::ScopedUrgentMessageNotification> && bound, std::__Cr::integer_sequence<unsigned long long,0,1,2,3>) Line 1067	C++
 	libcef.dll!base::internal::Invoker<base::internal::FunctorTraits<void (IPC::ChannelAssociatedGroupController::*&&)(unsigned int, unsigned int, IPC::(anonymous namespace)::ScopedUrgentMessageNotification),IPC::ChannelAssociatedGroupController *&&,unsigned int &&,unsigned int &&,IPC::(anonymous namespace)::ScopedUrgentMessageNotification &&>,base::internal::BindState<1,1,0,void (IPC::ChannelAssociatedGroupController::*)(unsigned int, unsigned int, IPC::(anonymous namespace)::ScopedUrgentMessageNotification),scoped_refptr<IPC::ChannelAssociatedGroupController>,unsigned int,unsigned int,IPC::(anonymous namespace)::ScopedUrgentMessageNotification>,void ()>::RunOnce(base::internal::BindStateBase * base) Line 980	C++
 	[Inline Frame] libcef.dll!base::OnceCallback<void ()>::Run() Line 156	C++
 	libcef.dll!base::TaskAnnotator::RunTaskImpl(base::PendingTask & pending_task) Line 203	C++
 	[Inline Frame] libcef.dll!base::TaskAnnotator::RunTask(perfetto::StaticString event_name, base::PendingTask & pending_task, base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl::<lambda_4> && args) Line 90	C++
 	[Inline Frame] libcef.dll!base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow * continuation_lazy_now) Line 470	C++
 	libcef.dll!base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() Line 332	C++
 	libcef.dll!base::MessagePumpForUI::DoRunLoop() Line 260	C++
 	libcef.dll!base::MessagePumpWin::Run(base::MessagePump::Delegate * delegate) Line 85	C++
 	libcef.dll!base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool application_tasks_allowed, base::TimeDelta timeout) Line 643	C++
 	libcef.dll!base::RunLoop::Run(const base::Location & location) Line 136	C++
 	libcef.dll!CefMainRunner::RunMessageLoop() Line 198	C++
 	libcef.dll!CefUIThread::ThreadMain() Line 106	C++
 	libcef.dll!base::`anonymous namespace'::ThreadFunc(void * params) Line 124	C++
 	kernel32.dll!00007ffbfa4d7374()	Unknown
 	ntdll.dll!00007ffbfaedcc91()	Unknown

The may be more telling is the code https://github.com/chromiumembedded/cef/blob/e513077eaca4097e2283cb70bcd72c804a6ee922/libcef/browser/browser_info_manager.cc#L318-L321

where it tries to get the pending popup information. If the comment saying GET_CUSTOM_WEB_CONTENTS_VIEW should only be used with alloy style maybe that is why this happens? I doubt this specifically given it also does an alloy style check below on pending_popup so maybe it just means GET_CUSTOM_WEB_CONTENTS_VIEW is ignored if not alloy style. Either way poppendingpopup returns empty. If it does mean GET_CUSTOM_WEB_CONTENTS_VIEW shouldn't be called on chrome style then I figured I should be able to reproduce it with:

./cefclient.exe --no-sandbox --lang=en-US --remote-debugging-port=8088 --uncaught-exception-stack-size=10 --use-chrome-style-window --disable-features=EnableHangWatcher --disable-chrome-login-prompt --hide-crash-restore-bubble --enable-unsafe-extension-debugging --enable-experimental-extension-apis --no-proxy-server --cache-path=f:/cache/  --url=https://google.com --use-views

and doing the new popup test. This succeeds though both with and without the --use-default-popup arg. The PopPendingPopup function does seem to handle chromestyle too.

I tried to repro in WinForms without success as well. I added CefSharpSettings.RuntimeStyle = CefRuntimeStyle.Chrome; to program.cs and tried both the normal lifespan handler and setting it equal to browser.LifeSpanHandler = new WinFormsLifeSpanHandlerEx(); but I am not sure if that is really a full hosted popup. Without HandlerEx new tabs open fine no matter what target is set to or if shift is held on links (everything just opens as new tab). When set to HandlerEx things that should open in new window do nothing (but no crash), but holding control does cause new tabs to open properly on links.

Back to where it does crash I found if you hold control or shift it does not crash when clicking the link with target _blank. Similar to in the non HwndHost WPF version holding control/shift just causes links to open in the same tab. These just don't flow through the lifespan handler for popups.

@amaitland
Copy link
Member

so: target->windowless_frame_rate = src->windowless_frame_rate; throws a read error

This suggests that window less rendering is still enabled. Does it make a difference if you disable it?

It'll be enabled by default if you use the CefSettings from the Wpf namespace.

https://github.com/cefsharp/CefSharp/blob/master/CefSharp.Wpf/CefSettings.cs#L18

@mitchcapper
Copy link
Contributor Author

I think this is the problem: https://github.com/cefsharp/CefSharp/blob/master/CefSharp.Wpf/Experimental/LifespanHandler.cs#L216

with using the main WPF sampe for hwndhost I switched to using that, and my actual helper app implemented similar logic calling SetWindowless as it was built for WPF. Removing that prevents the crash.

Once #4981 is integrated and the samples merge will just need to slightly modify the handler to work as expected. One other change is likely the delayed close handling.

The normal sample app doesn't crash once commenting it out but does have something of an odd behavior. It opens a new window (win #2) but the page opens in another chrome styled window (win #3). Closing Win #2 which is just gray closes Win #3. If you close Win #3 win #2 stays open, which you can then manually close.

No matter what you do (close #2 first which closes 3 or close 3 and manually close 2 as well) it isn't properly deregistering as DoClose doesn't get called as the window is destroyed. Looking at the comment though it says

 It will not be called for browsers after
        /// the associated OS window has been destroyed (for those browsers it is no
        /// longer possible to cancel the close).
....
/// If an application provides its own top-level window it should handle OS
/// close notifications by calling CefBrowserHost::CloseBrowser(false) instead

so it sounds like should not just close the window but call that. Otherwise the window handle gets reused which leads to
image

Don't know if I should just close this or leave it open as a reminder to do those two things once merged together.

@mitchcapper mitchcapper changed the title custom popup hosting / lifespan with Wpf.HwndHost causes crash on popup with ChromeStyle [invalid] custom popup hosting / lifespan with Wpf.HwndHost causes crash on popup with ChromeStyle Nov 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants