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

WebView: fatal: morestack on g0 #261

Open
pennersr opened this issue Apr 9, 2017 · 16 comments
Open

WebView: fatal: morestack on g0 #261

pennersr opened this issue Apr 9, 2017 · 16 comments

Comments

@pennersr
Copy link

pennersr commented Apr 9, 2017

I was trying out the webview and ran into an issue using the following code:

package main

import (
	. "github.com/lxn/walk/declarative"
)

func main() {
	m := MainWindow{
		Title:   "Webtest",
		MinSize: Size{600, 400},
		Layout:  VBox{},
		Children: []Widget{
			WebView{
				URL: "https://www.google.com",
			},
		},
	}	
	m.Run()
}

Try searching for "what is my browser" using the embedded search page. Then, click on the "https://www.whatismybrowser.com" link that is likely to be the 1st search result. Alternatively, you can change the URL in the source directly to point to whatismybrowser. The page never appears, instead an error message is printed thousands of time on the console and the application crashes:

fatal: morestack on g0
fatal: morestack on g0
fatal: morestack on g0
fatal: morestack on g0
...
@lxn
Copy link
Owner

lxn commented Apr 11, 2017

WebView is very limited in functionality and, especially on 64 bit Go, unstable. In general I would advise against using walk on top of 64 bit Go. I'm running into problems with one of my projects that look like a stack overflow, resulting in the same error message you have reported here. It seems like Go limits the size of the main os thread it starts on to just 128K, which quickly get exhausted with deeply nested callbacks, even more so with 64 bit pointers all over the place.

@typeless
Copy link

It seems like Go limits the size of the main os thread it starts on to just 128K

@lxn Do you mean the size of stack or the number of threads? I suppose you mean the stack size.
As far I know, all goroutines, including the main one, do NOT use the system stack created by the OS.
And the stack size of each normal goroutine starts small and growing when needed. The problem you encounter is probably a Go runtime bug.

@lxn
Copy link
Owner

lxn commented Apr 12, 2017

I mean this.

@typeless
Copy link

@lxn Oh, I see. BTW I can build & run the reported program on my win10 64bit machine. I built it with Go 1.8.1.

@xenoscopic
Copy link

There may actually be a really hackish workaround for this (and the 64-bit WebView problems in general). Perhaps @lxn can comment as to whether or not he's gone down this path.

The issue with the limited stack size was actually reported to the Go project before (golang/go#8233), but it was retracted because apparently the author found a workaround.

However, there's a somewhat related issue (golang/go#9457), where programs using the syscall interface to load and run DLLs weren't being given enough stack space because they weren't importing runtime/cgo (this is the indicator that the Go linker uses to determine if it should grant a larger stack space) (see this comment). Adding a blank import of runtime/cgo (import _ "runtime/cgo") will cause the linker to give the executable a more standard 2 MB of stack space on 64-bit Windows (1 MB on 32-bit Windows).

I tried adding such an import to the sample program above to trick the linker into giving the executable more stack space and it seemed to work (crashed before, not after, although there are still some scripting errors).

There's just one hitch, which is that CGO on Windows doesn't understand the -H windowsgui build mode, so you have to build it as a console program and deal with the annoying console window. This problem was brought up on the golang-nuts mailing list last month, although it doesn't look like any action has been taken on it yet (https://groups.google.com/forum/#!topic/golang-nuts/4rnCvFKTYgs/discussion).

But, it's not a huge issue, because if you install Visual Studio (the community version is free), you can use the editbin.exe program to manually change the executable subsystem after linking (http://stackoverflow.com/a/2435907/2829001). There are other ways to do this, though this is the most canonical. In any case, it seems to work on Go executables - I think it just changes some bit in the PE header.

As far as the scripting errors are concerned, I'm not sure, but I think that's probably related to the OLE/COM callbacks or FEATURE_* keys that control the WebBrowser control.

@lxn
Copy link
Owner

lxn commented Apr 18, 2017

Thanks @havoc-io for your great comment. Didn't know about that cgo import trick.

@xenoscopic
Copy link

You're very welcome - I'm glad to hear that it's a new avenue of approach. I'm not sure if it's the panacea you've been searching for with regards to WebView controls on 64-bit Windows (I know you've been trying to figure out the problems there for years), but maybe this can help with some of the issues.

I'm also not sure if there's anything here worth reporting back to the Go team in terms of fixable issues. I think maybe CGO support for the windowsgui build mode is worth opening an issue, but the Windows Go team is stretched thin in general and may not get to it for a while. Given that building walk-based applications already requires a few extra steps with the manifest, perhaps one more step to manually change the subsystem (if using this runtime/cgo trick) isn't so bad.

@lxn
Copy link
Owner

lxn commented Apr 18, 2017

At least for me this solution would suffice.

Right now I have some other ffi related trouble though. I have an experimental walk branch with support to decorate widgets with graphics effects like border glow and drop shadow, implemented using Direct2D. The problem is, Direct2D has a few important methods that have a float parameter, but the syscall package does not support that. For this particular task it was possible to work around this, but it would rule out replacing the current GDI based Canvas implementation with one using Direct2D (or GDI+, which also uses float parameters).

The problem has been reported to the Go team in the past though I can't find any link now, but IIRC the resolution was to use CGO instead of the syscall package...

@xenoscopic
Copy link

That's a bit of a shame - adding a "real" CGO dependency that required the MinGW toolchain would be a bit heavy. Although I guess you could hide that API behind a cgo build constraint? Go's built-in DLL-loading "syscall" interface on Windows is one of it's best features IMHO - it's just a shame that it supports a limited subset of the ABI.

@lxn
Copy link
Owner

lxn commented Apr 18, 2017

Yes, it's sad. I would really like to avoid CGO.

@xenoscopic
Copy link

It looks like part of this problem is going to be fixed in Go 1.9 thanks to @kjk notifying the Go developers with golang/go#20975. Go will default to 2 MB stacks for 64-bit Windows in 1.9 and then also default to 1 MB stacks for 32-bit Windows in 1.10. The latter change is being pushed back so they can evaluate the effects of the increased memory pressure during the Go 1.10 development cycle. But since the webview problems only really manifest on 64-bit systems anyway, this problem may be largely solved.

@kjk
Copy link

kjk commented Jul 24, 2017

Even with that fix, web view on 64bit is very unstable.

When visiting https://vox.com, webview sample crashes for me always with a stack overflow in runtime even if I give it ridiculous amounts of stack (I tried up to 16 MB).

This might be a bug in the runtime or a bug in webview implementation or a combination (the latter triggering the former).

@xenoscopic
Copy link

xenoscopic commented Jul 24, 2017

Yeah, there are definitely still some issues. It's impressive that @lxn managed to make the thing work at all given the COM/OLE trickery involved (especially without resorting to CGO). I think there are a number of other potential areas that warrant investigation. I'm hoping to look at this in the next 1-2 weeks, probably in a separate package to get as clean an implementation as possible.

First, there are a lot of registry keys and configuration flags that can be set on a per-process basis to regulate the webview's behavior (e.g. stuff like enabling GPU rendering). These can be set in an ephemeral fashion so that they only span the lifetime of the process. Here's just a small example of some of these (this is in the context of the .NET WebBrowser control, but that's the same underlying COM object).

Second, there may also be some other COM interfaces that the webview is relying on being able to call back into for certain things (like setting script execution policy). There's a bunch of different interfaces that the host application can implement to customize the webview behavior. Unfortunately the documentation for a lot of this stuff is becoming increasingly buried on MSDN.

I'll update here if I make any progress.

@xenoscopic
Copy link

After thinking a bit more about your comment (and re-reading golang/go#20975), I'm really starting to doubt the role of stack size even more. 16 MB is sort of an insane amount of stack - even Visual Studio doesn't create stack sizes that large when compiling C/C++ code, and there's loads of C/C++ code out there using IWebBrowser2. I think the assessment of infinite recursion is probably close to the truth. The webview control certainly isn't allocating its internal resources on the stack, so the size and complexity of the webpage should really make little difference. I think what's far more likely is that either there's some unhandled COM method being called or a message being dispatched in a way that causes infinite recursion.

@xenoscopic
Copy link

Although Go 1.9 hasn't fixed the "morestack" issue (which I'm fairly certain is due to thread-local storage not being supported in purely syscall-based C FFI), it seems they did fix the issue with windowsgui build mode conflicting with CGO. So you can now use the import _ "runtime/cgo" trick without having to use editbin.exe to change the executable subsystem. This at least removes the need for Visual Studio to work around the issue.

@kjk
Copy link

kjk commented Mar 31, 2019

This issue is most likely fixed in go 1.11 (see golang/go#20975)

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

5 participants