go-allegro icon indicating copy to clipboard operation
go-allegro copied to clipboard

example game.go - panic: cgo argument has Go pointer to Go pointer

Open kdeenanauth opened this issue 8 years ago • 5 comments

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

kdeenanauth avatar May 24 '16 08:05 kdeenanauth

Issue can be avoided by setting environment variable GODEBUG=cgocheck=0 per https://tip.golang.org/cmd/cgo/#hdr-Passing_pointers

kdeenanauth avatar May 24 '16 09:05 kdeenanauth

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.

kdeenanauth avatar May 24 '16 23:05 kdeenanauth

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?

SeanTolstoyevski avatar May 19 '21 16:05 SeanTolstoyevski

@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?

dradtke avatar May 21 '21 03:05 dradtke

  • 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.

SeanTolstoyevski avatar May 21 '21 06:05 SeanTolstoyevski