go-allegro
go-allegro copied to clipboard
example game.go - panic: cgo argument has Go pointer to Go pointer
I built go-allegro under Allegro 5.2 with go 1.6. Display.go works great but game.go fails with the following error:
panic: runtime error: cgo argument has Go pointer to Go pointer
goroutine 1 [running]: panic(0x52a980, 0xc08200c3e0) C:/Go/src/runtime/panic.go:464 +0x3f4 github.com/dradtke/go-allegro/allegro.(_KeyboardState).Get(0xc08200e390) C:/Users/kdeenanauth/Documents/git/go/src/github.com/dradtke/go-allegro/allegro/keyboard.go:187 +0x53 main.(_Game).Update(0xc08200e380) C:/Users/kdeenanauth/Documents/git/go/src/gitlab.com/kdeenanauth/allegroTest/main.go:134 +0x3c main.main.func1() C:/Users/kdeenanauth/Documents/git/go/src/gitlab.com/kdeenanauth/allegroTest/main.go:255 +0xc93 github.com/dradtke/go-allegro/allegro.go_main() C:/Users/kdeenanauth/Documents/git/go/src/github.com/dradtke/go-allegro/allegro/main.go:14 +0x7c github.com/dradtke/go-allegro/allegro._cgoexpwrap_8372e5eaafd2_go_main() ??:0 +0x1b github.com/dradtke/go-allegro/allegro._Cfunc_run_main() ??:0 +0x3d github.com/dradtke/go-allegro/allegro.Run(0x59b490) C:/Users/kdeenanauth/Documents/git/go/src/github.com/dradtke/go-allegro/allegro/main.go:32 +0x34 main.main() C:/Users/kdeenanauth/Documents/git/go/src/gitlab.com/kdeenanauth/allegroTest/main.go:260 +0x2a exit status 2
Issue can be avoided by setting environment variable GODEBUG=cgocheck=0
per https://tip.golang.org/cmd/cgo/#hdr-Passing_pointers
I'm able to reproduce this error with a tiny example:
package main
import (
"github.com/dradtke/go-allegro/allegro"
)
type Game struct {
keyboard allegro.KeyboardState
tiles map[int]*int
}
func main() {
allegro.Run(func() {
game := new(Game)
game.tiles = make(map[int]*int) // commenting out this line, causes the error to go away
if err := allegro.InstallKeyboard(); err != nil {
panic(err)
}
game.keyboard.Get()
})
}
This issue is stranger than I first thought. I'm not sure why the 'tiles' field causes the cgocheck to kick in.
As of golang 1.6, there are limitations to passing Go types to C.
allegro.Run
passes the working golang code to some C functions.
allegro.Run
needs to be removed and rewrite. It is not possible to work this way with current golang versions.
@dradtke Do you have any work or thing on this subject?
@kdeenanauth Apologies for the very late response, but I was able to get your example working with a simple change:
package main
import (
"github.com/dradtke/go-allegro/allegro"
)
type Game struct {
keyboard *allegro.KeyboardState
tiles map[int]*int
}
func main() {
allegro.Run(func() {
game := &Game{
keyboard: new(allegro.KeyboardState),
}
game.tiles = make(map[int]*int) // commenting out this line, causes the error to go away
if err := allegro.InstallKeyboard(); err != nil {
panic(err)
}
game.keyboard.Get()
})
}
It looks like storing the KeyboardState
struct as a pointer helps avoid the issue.
@SeanTolstoyevski The game.go
example works for me using Go 1.14.2 on Linux. Can you provide more details on your environment?
- windows 10, 64 bit
- go 1.16.4 64 bit
- gcc 10.2.0 64 bit
package allegro
/*
#include "allegro5/allegro.h"
#include "allegro5/system.h"
void initLib() {
al_init();
}
*/
import "C"
import (
"errors"
)
type SystemID int
const (
SYSTEM_ID_UNKNOWN SystemID = C.ALLEGRO_SYSTEM_ID_UNKNOWN
SYSTEM_ID_XGLX = C.ALLEGRO_SYSTEM_ID_XGLX
SYSTEM_ID_WINDOWS = C.ALLEGRO_SYSTEM_ID_WINDOWS
SYSTEM_ID_MACOSX = C.ALLEGRO_SYSTEM_ID_MACOSX
SYSTEM_ID_ANDROID = C.ALLEGRO_SYSTEM_ID_ANDROID
SYSTEM_ID_IPHONE = C.ALLEGRO_SYSTEM_ID_IPHONE
SYSTEM_ID_GP2XWIZ = C.ALLEGRO_SYSTEM_ID_GP2XWIZ
SYSTEM_ID_RASPBERRYPI = C.ALLEGRO_SYSTEM_ID_RASPBERRYPI
SYSTEM_ID_SDL = C.ALLEGRO_SYSTEM_ID_SDL
)
// Returns the (compiled) version of the Allegro library, packed into a single
// integer as groups of 8 bits in the form (major << 24) | (minor << 16) |
// (revision << 8) | release.
//
// See https://liballeg.org/a5docs/5.2.6/system.html#al_get_allegro_version
func Version() (major, minor, revision, release uint8) {
v := uint32(C.al_get_allegro_version())
major = uint8(v >> 24)
minor = uint8((v >> 16) & 255)
revision = uint8((v >> 8) & 255)
release = uint8(v & 255)
return
}
// Returns the system configuration structure. The returned configuration
// should not be destroyed with al_destroy_config. This is mainly used for
// configuring Allegro and its addons. You may populate this configuration
// before Allegro is installed to control things like the logging levels and
// other features.
//
// See https://liballeg.org/a5docs/5.2.6/system.html#al_get_system_config
func SystemConfig() (*Config, error) {
cfg := C.al_get_system_config()
if cfg == nil {
return nil, errors.New("no system config found")
}
return (*Config)(cfg), nil
}
// This override the executable name used by al_get_standard_path for
// ALLEGRO_EXENAME_PATH and ALLEGRO_RESOURCES_PATH.
//
// See https://liballeg.org/a5docs/5.2.6/system.html#al_set_exe_name
func SetExeName(path string) {
path_ := C.CString(path)
defer freeString(path_)
C.al_set_exe_name(path_)
}
// Sets the global organization name.
//
// See https://liballeg.org/a5docs/5.2.6/system.html#al_set_org_name
func SetOrgName(name string) {
name_ := C.CString(name)
defer freeString(name_)
C.al_set_org_name(name_)
}
// Sets the global application name.
//
// See https://liballeg.org/a5docs/5.2.6/system.html#al_set_app_name
func SetAppName(name string) {
name_ := C.CString(name)
defer freeString(name_)
C.al_set_app_name(name_)
}
// Returns the global organization name string.
//
// See https://liballeg.org/a5docs/5.2.6/system.html#al_get_org_name
func OrgName() string {
return C.GoString(C.al_get_org_name())
}
// Returns the global application name string.
//
// See https://liballeg.org/a5docs/5.2.6/system.html#al_get_app_name
func AppName() string {
return C.GoString(C.al_get_app_name())
}
// Returns the number of CPU cores that the system Allegro is running on has
// and which could be detected, or a negative number if detection failed. Even
// if a positive number is returned, it might be that it is not correct. For
// example, Allegro running on a virtual machine will return the amount of
// CPU's of the VM, and not that of the underlying system.
//
// See https://liballeg.org/a5docs/5.2.6/system.html#al_get_cpu_count
func CPUCount() int {
return int(C.al_get_cpu_count())
}
// Returns the size in MB of the random access memory that the system Allegro
// is running on has and which could be detected, or a negative number if
// detection failed. Even if a positive number is returned, it might be that it
// is not correct. For example, Allegro running on a virtual machine will
// return the amount of RAM of the VM, and not that of the underlying system.
//
// See https://liballeg.org/a5docs/5.2.6/system.html#al_get_ram_size
func RAMSize() int {
return int(C.al_get_ram_size())
}
// Returns the platform that Allegro is running on.
//
// See https://liballeg.org/a5docs/5.2.6/system.html#al_get_system_id
func GetSystemID() SystemID {
return SystemID(C.al_get_system_id())
}
func Install() {
C.initLib()
}
// Closes down the Allegro system.
//
// See https://liballeg.org/a5docs/5.2.6/system.html#al_uninstall_system
func uninstall() {
C.al_uninstall_system()
}
this is system.go file with modified.
This code parts solves problems under Windows.
"allegro.Run" should only be used for darvin. Would you accept it if I prepare a pr on this subject?
You have to call Install
before all functions and allegro.Run is no longer needed.