therecipe / qt

Qt binding for Go (Golang) with support for Windows / macOS / Linux / FreeBSD / Android / iOS / Sailfish OS / Raspberry Pi / AsteroidOS / Ubuntu Touch / JavaScript / WebAssembly
GNU Lesser General Public License v3.0
10.42k stars 744 forks source link

exitsyscall: syscall frame is no longer valid panic on widgets.QApplication_Exec() #767

Open thiekus opened 5 years ago

thiekus commented 5 years ago

I got this problem when running 32-bit generated of windows build, but this bugs doesn't occurs on 64-bit generated build. After widgets.QApplication_Exec(), program are run fine until I close MainWindow and I got this:

fatal error: exitsyscall: syscall frame is no longer valid

goroutine 1 [running, locked to thread]:
runtime.throw(0xbdf7d8, 0x2d)
    C:/Go/src/runtime/panic.go:608 +0x64 fp=0x14063f40 sp=0x14063f2c pc=0x426464
runtime.exitsyscall()
    C:/Go/src/runtime/proc.go:3010 +0x1f1 fp=0x14063f58 sp=0x14063f40 pc=0x42dd31
runtime.cgocallbackg(0x0)
    C:/Go/src/runtime/cgocall.go:188 +0x99 fp=0x14063f88 sp=0x14063f58 pc=0x403879
runtime.cgocallback_gofunc(0x424b79, 0x4497a0, 0x124cc50, 0x0)
    C:/Go/src/runtime/asm_386.s:809 +0x7e fp=0x14063f98 sp=0x14063f88 pc=0x4488de
runtime.asmcgocall(0x4497a0, 0x124cc50, 0x0)
    C:/Go/src/runtime/asm_386.s:673 +0x36 fp=0x14063f9c sp=0x14063f98 pc=0x4487c6
runtime.stdcall(0x951618, 0x0)
    C:/Go/src/runtime/os_windows.go:747 +0x79 fp=0x14063fb4 sp=0x14063f9c pc=0x424b79
runtime.stdcall1(0x951618, 0x0, 0x140440f8)
    C:/Go/src/runtime/os_windows.go:767 +0x33 fp=0x14063fc0 sp=0x14063fb4 pc=0x424c23
runtime.exit(0x0)
    C:/Go/src/runtime/os_windows.go:445 +0x2f fp=0x14063fd0 sp=0x14063fc0 pc=0x42416f
runtime.main()
    C:/Go/src/runtime/proc.go:223 +0x251 fp=0x14063ff0 sp=0x14063fd0 pc=0x427b71
runtime.goexit()
    C:/Go/src/runtime/asm_386.s:1324 +0x1 fp=0x14063ff4 sp=0x14063ff0 pc=0x448d91

Process finished with exit code 0

This bug also reproduced by building examples (e.g qt_xkcd). I'm using pre-build Qt 5.6.3 binaries for mingw shipped by QtInstaller with latest Go 1.11.4 and mingw 4.9.2 posix dwarf shipped with QtInstaller. Also I have tested on previous Go 1.10.7 for same problems. Quick research https://github.com/mitchellh/go-mruby/issues/49 and https://github.com/aarzilli/golua/issues/66 and the problems are may be on mingw sjlj (setjmp/longjmp) that causing Go's stack corruption. But pre-built Qt binaries and mingw variant are dwarf.

Does this is known problems or occurs in the past? Because I just new for using this binding.

Thank you!

therecipe commented 5 years ago

Hey

I looked into this and tried to reproduce it by compiling the xkcd example with the help of the windows_32_shared_xp image. Which comes with Go 1.10.5 and the official pre-built version of Qt 5.6.3 alongside mingw's GCC 4.9.2. But the application doesn't seem to crash after closing the window.

However, I haven't tried to compile the example against the full binding (i.e. with qtdeploy -fast or go build/run)

Did you use go build/run or qtdeploy -fast? If yes, maybe test an application deployed with qtdeploy build desktop instead.

I also did a little research and found this https://github.com/golang/go/issues/15639 which references these changes https://github.com/golang/go/commit/1f7a0d4b5ec7ef94b96755e9b95168abf86e9d71 which can strangely only be found in go 1.10.x, even though they should also be found in 1.11.x and 1.12.x and might or might not address this issue. (Maybe try to patch your go version and rebuild the go tools, to see if it helps ...)

thiekus commented 5 years ago

Have tried as you suggested, and qtdeploy build desktop seems run flawlessly (slower build times, but I got smaller exe size). It was compile and runs fine on Go 1.10.7 for some examples (including qt_xkcd I have mentioned).

However, since my project does have qt code in separate package, I got this error when deploying:

uires\MainWindow_ui.go:12:14: undefined: widgets.QGridLayout
uires\MainWindow_ui.go:13:12: undefined: widgets.QVBoxLayout
uires\MainWindow_ui.go:14:12: undefined: widgets.QHBoxLayout
uires\MainWindow_ui.go:15:10: undefined: widgets.QPushButton
uires\MainWindow_ui.go:16:10: undefined: widgets.QPushButton
uires\MainWindow_ui.go:17:20: undefined: widgets.QSpacerItem
uires\MainWindow_ui.go:18:11: undefined: widgets.QPushButton
uires\MainWindow_ui.go:19:10: undefined: widgets.QPushButton
uires\MainWindow_ui.go:20:15: undefined: widgets.QTableWidget
uires\MainWindow_ui.go:21:21: undefined: widgets.QHBoxLayout
uires\MainWindow_ui.go:21:21: too many errors

UI's are generated using goqtuic and in local package named uires instead main. Of course github.com/therecipe/qt/widgets is imported. It will build using go build but it doesn't if I use qtdeploy build desktop. Could qtdeploy build qt source that have separate go package?

therecipe commented 5 years ago

Does your main package import uires somehow, if yes then it usually should work. But I will take a look at goqtuic and try to reproduce it.

Also, could you confirm that using go run/build or qtdeploy -fast still crashes with fatal error: exitsyscall: syscall frame is no longer valid on Go 1.10.7?

thiekus commented 5 years ago

Yes, I have imported uires from main package. Here is my appmain.go:

package main

import (
    "github.com/therecipe/qt/core"
    "github.com/therecipe/qt/widgets"
    "os"
)

func main() {
    widgets.NewQApplication(len(os.Args), os.Args)
    // Set default library location
    core.QCoreApplication_AddLibraryPath(core.QCoreApplication_ApplicationDirPath())
    // Setup and show main window
    setupMainWindow()
    mainWindow.Show()
        // Run application
    widgets.QApplication_Exec()
}

window_main.go

package main

import (
    "./uires"
    "github.com/therecipe/qt/widgets"
)

var mainWindow *widgets.QMainWindow
var mainWindowUI uires.UIMainWindowMainWindow

func setupMainWindow() {
    // Initialize our windows
    mainWindow = widgets.NewQMainWindow(nil, 0)
    mainWindowUI.SetupUI(mainWindow)
    // Setting window properties
    mainWindow.SetWindowTitle("Main Window")
    mainWindow.Move2(100, 100)
}

Generated MainWindow_ui.go from goqtuic

// WARNING! All changes made in this file will be lost!
package uires

import (
    "github.com/therecipe/qt/core"
    "github.com/therecipe/qt/gui"
    "github.com/therecipe/qt/widgets"
)

type UIMainWindowMainWindow struct {
    MainWidget *widgets.QWidget
    GridLayout *widgets.QGridLayout
    LayVMain *widgets.QVBoxLayout
    LayHzBtn *widgets.QHBoxLayout
    BtnAdd *widgets.QPushButton
    BtnDel *widgets.QPushButton
    HorizontalSpacer *widgets.QSpacerItem
    BtnDown *widgets.QPushButton
    BtnOpt *widgets.QPushButton
    TableWidget *widgets.QTableWidget
    HorizontalLayout3 *widgets.QHBoxLayout
    LblDirLoc *widgets.QLabel
    LineEdit *widgets.QLineEdit
    BtnSetDir *widgets.QPushButton
    Menubar *widgets.QMenuBar
    MenuFile *widgets.QMenu
    MenuHelp *widgets.QMenu
    Statusbar *widgets.QStatusBar
}

func (this *UIMainWindowMainWindow) SetupUI(MainWindow *widgets.QMainWindow) {
    MainWindow.SetObjectName("MainWindow")
    MainWindow.SetGeometry(core.NewQRect4(0, 0, 600, 400))
    var icon *gui.QIcon
    icon = gui.NewQIcon()
    icon.AddPixmap(gui.NewQPixmap5(":/artworks/lime.png", "", core.Qt__AutoColor), gui.QIcon__Normal, gui.QIcon__Off)
    MainWindow.SetWindowIcon(icon)
    this.MainWidget = widgets.NewQWidget(MainWindow, core.Qt__Widget)
    this.MainWidget.SetObjectName("MainWidget")
    this.GridLayout = widgets.NewQGridLayout(this.MainWidget)
    this.GridLayout.SetObjectName("gridLayout")
    this.GridLayout.SetContentsMargins(0, 0, 0, 0)
    this.GridLayout.SetSpacing(0)
    this.LayVMain = widgets.NewQVBoxLayout2(this.MainWidget)
    this.LayVMain.SetObjectName("layVMain")
    this.LayVMain.SetContentsMargins(10, 10, 10, 10)
    this.LayVMain.SetSpacing(6)
    this.LayHzBtn = widgets.NewQHBoxLayout2(this.MainWidget)
    this.LayHzBtn.SetObjectName("layHzBtn")
    this.LayHzBtn.SetContentsMargins(0, 0, 0, 0)
    this.LayHzBtn.SetSpacing(6)
    this.BtnAdd = widgets.NewQPushButton(this.MainWidget)
    this.BtnAdd.SetObjectName("BtnAdd")
    icon = gui.NewQIcon()
    icon.AddPixmap(gui.NewQPixmap5(":/icons/add.png", "", core.Qt__AutoColor), gui.QIcon__Normal, gui.QIcon__Off)
    this.BtnAdd.SetIcon(icon)
    this.BtnAdd.SetFlat(true)
    this.LayHzBtn.AddWidget(this.BtnAdd, 0, 0)
    this.BtnDel = widgets.NewQPushButton(this.MainWidget)
    this.BtnDel.SetObjectName("BtnDel")
    icon = gui.NewQIcon()
    icon.AddPixmap(gui.NewQPixmap5(":/icons/delete.png", "", core.Qt__AutoColor), gui.QIcon__Normal, gui.QIcon__Off)
    this.BtnDel.SetIcon(icon)
    this.BtnDel.SetFlat(true)
    this.LayHzBtn.AddWidget(this.BtnDel, 0, 0)
    this.HorizontalSpacer = widgets.NewQSpacerItem(40, 20, widgets.QSizePolicy__Expanding, widgets.QSizePolicy__Minimum)
    this.LayHzBtn.AddItem(this.HorizontalSpacer)
    this.BtnDown = widgets.NewQPushButton(this.MainWidget)
    this.BtnDown.SetObjectName("BtnDown")
    icon = gui.NewQIcon()
    icon.AddPixmap(gui.NewQPixmap5(":/icons/accept.png", "", core.Qt__AutoColor), gui.QIcon__Normal, gui.QIcon__Off)
    this.BtnDown.SetIcon(icon)
    this.BtnDown.SetFlat(true)
    this.LayHzBtn.AddWidget(this.BtnDown, 0, 0)
    this.BtnOpt = widgets.NewQPushButton(this.MainWidget)
    this.BtnOpt.SetObjectName("BtnOpt")
    icon = gui.NewQIcon()
    icon.AddPixmap(gui.NewQPixmap5(":/icons/wrench.png", "", core.Qt__AutoColor), gui.QIcon__Normal, gui.QIcon__Off)
    this.BtnOpt.SetIcon(icon)
    this.BtnOpt.SetFlat(true)
    this.LayHzBtn.AddWidget(this.BtnOpt, 0, 0)
    this.LayVMain.AddLayout(this.LayHzBtn, 0)
    this.TableWidget = widgets.NewQTableWidget(this.MainWidget)
    this.TableWidget.SetObjectName("TableWidget")
    this.LayVMain.AddWidget(this.TableWidget, 0, 0)
    this.HorizontalLayout3 = widgets.NewQHBoxLayout2(this.MainWidget)
    this.HorizontalLayout3.SetObjectName("horizontalLayout_3")
    this.HorizontalLayout3.SetContentsMargins(0, 0, 0, 0)
    this.HorizontalLayout3.SetSpacing(6)
    this.LblDirLoc = widgets.NewQLabel(this.MainWidget, core.Qt__Widget)
    this.LblDirLoc.SetObjectName("LblDirLoc")
    this.HorizontalLayout3.AddWidget(this.LblDirLoc, 0, 0)
    this.LineEdit = widgets.NewQLineEdit(this.MainWidget)
    this.LineEdit.SetObjectName("LineEdit")
    this.HorizontalLayout3.AddWidget(this.LineEdit, 0, 0)
    this.BtnSetDir = widgets.NewQPushButton(this.MainWidget)
    this.BtnSetDir.SetObjectName("BtnSetDir")
    icon = gui.NewQIcon()
    icon.AddPixmap(gui.NewQPixmap5(":/icons/drive_disk.png", "", core.Qt__AutoColor), gui.QIcon__Normal, gui.QIcon__Off)
    this.BtnSetDir.SetIcon(icon)
    this.BtnSetDir.SetFlat(true)
    this.HorizontalLayout3.AddWidget(this.BtnSetDir, 0, 0)
    this.LayVMain.AddLayout(this.HorizontalLayout3, 0)
    this.GridLayout.AddLayout2(this.LayVMain, 0, 0, 1, 1, 0)
    MainWindow.SetCentralWidget(this.MainWidget)
    this.Menubar = widgets.NewQMenuBar(MainWindow)
    this.Menubar.SetObjectName("Menubar")
    this.Menubar.SetGeometry(core.NewQRect4(0, 0, 600, 21))
    this.MenuFile = widgets.NewQMenu(this.Menubar)
    this.MenuFile.SetObjectName("MenuFile")
    this.MenuHelp = widgets.NewQMenu(this.Menubar)
    this.MenuHelp.SetObjectName("MenuHelp")
    MainWindow.SetMenuBar(this.Menubar)
    this.Statusbar = widgets.NewQStatusBar(MainWindow)
    this.Statusbar.SetObjectName("Statusbar")
    MainWindow.SetStatusBar(this.Statusbar)
    this.Menubar.QWidget.AddAction(this.MenuFile.MenuAction())
    this.Menubar.QWidget.AddAction(this.MenuHelp.MenuAction())

    this.RetranslateUi(MainWindow)

}

func (this *UIMainWindowMainWindow) RetranslateUi(MainWindow *widgets.QMainWindow) {
    _translate := core.QCoreApplication_Translate
    MainWindow.SetWindowTitle(_translate("MainWindow", "MainWindow", "", -1))
    this.BtnAdd.SetText(_translate("MainWindow", "Add Song", "", -1))
    this.BtnDel.SetText(_translate("MainWindow", "Delete", "", -1))
    this.BtnDown.SetText(_translate("MainWindow", "Download!", "", -1))
    this.BtnOpt.SetText(_translate("MainWindow", "Options", "", -1))
    this.TableWidget.SetColumnCount(0)
    this.TableWidget.SetRowCount(0)
    this.LblDirLoc.SetText(_translate("MainWindow", "Download Location", "", -1))
    this.BtnSetDir.SetText(_translate("MainWindow", "Set Directory", "", -1))
    this.MenuFile.SetTitle(_translate("MainWindow", "File", "", -1))
    this.MenuHelp.SetTitle(_translate("MainWindow", "Help", "", -1))
}

For Go 1.10.7 using go build, still got same panic (although bit different stack trace)

fatal error: exitsyscall: syscall frame is no longer valid

runtime stack:
runtime.throw(0x84d3b3, 0x2d)
        C:/Go/src/runtime/panic.go:616 +0x6b
runtime.exitsyscall.func1()
        C:/Go/src/runtime/proc.go:2941 +0x2b
runtime.systemstack(0x147fe14)
        C:/Go/src/runtime/asm_386.s:464 +0x5e
runtime.mstart()
        C:/Go/src/runtime/proc.go:1175

goroutine 1 [running, locked to thread]:
runtime.systemstack_switch()
        C:/Go/src/runtime/asm_386.s:418 fp=0x13ba3f3c sp=0x13ba3f38 pc=0x446d50
runtime.exitsyscall(0x0)
        C:/Go/src/runtime/proc.go:2940 +0x1de fp=0x13ba3f54 sp=0x13ba3f3c pc=0x42df1e
runtime.cgocallbackg(0x0)
        C:/Go/src/runtime/cgocall.go:191 +0xa0 fp=0x13ba3f84 sp=0x13ba3f54 pc=0x402c20
runtime.cgocallback_gofunc(0x424ad5, 0x449290, 0x11c3cd8, 0x13ba3fa8)
        C:/Go/src/runtime/asm_386.s:854 +0x7e fp=0x13ba3f94 sp=0x13ba3f84 pc=0x4481fe
runtime.asmcgocall(0x449290, 0x11c3cd8, 0x13ba3fa8)
        C:/Go/src/runtime/asm_386.s:730 +0x2c fp=0x13ba3f98 sp=0x13ba3f94 pc=0x4480fc
runtime.stdcall(0xecff20, 0x0)
        C:/Go/src/runtime/os_windows.go:716 +0x65 fp=0x13ba3fac sp=0x13ba3f98 pc=0x424ad5
runtime.stdcall1(0xecff20, 0x0, 0x13b54108)
        C:/Go/src/runtime/os_windows.go:734 +0x33 fp=0x13ba3fb8 sp=0x13ba3fac pc=0x424b73
runtime.exit(0x0)
        C:/Go/src/runtime/os_windows.go:443 +0x2f fp=0x13ba3fc8 sp=0x13ba3fb8 pc=0x42426f
runtime.main()
        C:/Go/src/runtime/proc.go:220 +0x251 fp=0x13ba3ff0 sp=0x13ba3fc8 pc=0x427b21
runtime.goexit()
        C:/Go/src/runtime/asm_386.s:1665 +0x1 fp=0x13ba3ff4 sp=0x13ba3ff0 pc=0x448901
therecipe commented 5 years ago

For Go 1.10.7 using go build, still got same panic (although bit different stack trace)

Thanks

"./uires"

I tested your example, you will just need to use an "absolute" path here, these relative paths won't work. So using something like github.com/therecipe/uicexample/uires did work for me.