Search code examples
c++goswigcgo

How to debug "exit status 3221225477" with swig/cgo?


I'm using the integration of SWIG with golang to generate the cgo files. I'm linking a C++ lib and Go.

I've installed my package with: swig -go -cgo -c++ -intgosize 64 ./basic_host.i and go install and it happened well. But when I launched my main example here :

package main

import (
    "fmt"
    "myLib/basic_host"
)

func main() {
    fmt.Println("Hello")
    basic_host.PrintHelpAndExit("test", 0)
    fmt.Println("World!")
}

When I try to launch it I get the exit status 3221225477 and my print hello is not even taken in account, it seems my program isn't even launched... I'm don't know how to handle this as debug tools are not even launched.

The exit status seems to be related to a NIL pointer ref : see here, surely due to cgo integration. I'm building on Windows 10 with MinGW, under my config:

swig -version
SWIG Version 4.0.2
Compiled with i686-w64-mingw32-g++ [i686-w64-mingw32]
Configured options: +pcre

My SWIG interface file is like this (basic_host.i):

%module basic_host
%{
    #include <atomic>
    #include <map>
    #include <iostream>
    #include <memory>
    
    #include <myLib/myLib.hpp>
    #include "../../examples/basic_host/command_line.h"
    #include "../../examples/basic_host/command_line.cpp"
%}

%inline %{
    extern void printHelpAndExit(const char* binary, unsigned int exitCode);
%}

Here is the go file generated (basic_host.go):

    /* ----------------------------------------------------------------------------
 * This file was automatically generated by SWIG (http://www.swig.org).
 * Version 4.0.2
 *
 * This file is not intended to be easily readable and contains a number of
 * coding conventions designed to improve portability and efficiency. Do not make
 * changes to this file unless you know what you are doing--modify the SWIG
 * interface file instead.
 * ----------------------------------------------------------------------------- */

// source: .\basic_host.i

package basic_host

/*
#define intgo swig_intgo
typedef void *swig_voidp;

#include <stdint.h>


typedef long long intgo;
typedef unsigned long long uintgo;



typedef struct { char *p; intgo n; } _gostring_;
typedef struct { void* array; intgo len; intgo cap; } _goslice_;


typedef _gostring_ swig_type_1;
extern void _wrap_Swig_free_basic_host_5ddda8bb50543998(uintptr_t arg1);
extern uintptr_t _wrap_Swig_malloc_basic_host_5ddda8bb50543998(swig_intgo arg1);
extern void _wrap_printHelpAndExit_basic_host_5ddda8bb50543998(swig_type_1 arg1, swig_intgo arg2);
#undef intgo
*/
import "C"

import "unsafe"
import _ "runtime/cgo"
import "sync"


type _ unsafe.Pointer



var Swig_escape_always_false bool
var Swig_escape_val interface{}


type _swig_fnptr *byte
type _swig_memberptr *byte


type _ sync.Mutex

func Swig_free(arg1 uintptr) {
    _swig_i_0 := arg1
    C._wrap_Swig_free_basic_host_5ddda8bb50543998(C.uintptr_t(_swig_i_0))
}

func Swig_malloc(arg1 int) (_swig_ret uintptr) {
    var swig_r uintptr
    _swig_i_0 := arg1
    swig_r = (uintptr)(C._wrap_Swig_malloc_basic_host_5ddda8bb50543998(C.swig_intgo(_swig_i_0)))
    return swig_r
}

func PrintHelpAndExit(arg1 string, arg2 uint) {
    _swig_i_0 := arg1
    _swig_i_1 := arg2
    C._wrap_printHelpAndExit_basic_host_5ddda8bb50543998(*(*C.swig_type_1)(unsafe.Pointer(&_swig_i_0)), C.swig_intgo(_swig_i_1))
    if Swig_escape_always_false {
        Swig_escape_val = arg1
    }
}

And here is the c++ wrapped file (basic_host_wrap.cxx):

    /* ----------------------------------------------------------------------------
 * This file was automatically generated by SWIG (http://www.swig.org).
 * Version 4.0.2
 *
 * This file is not intended to be easily readable and contains a number of
 * coding conventions designed to improve portability and efficiency. Do not make
 * changes to this file unless you know what you are doing--modify the SWIG
 * interface file instead.
 * ----------------------------------------------------------------------------- */

// source: .\basic_host.i

#define SWIGMODULE basic_host

#ifdef __cplusplus
/* SwigValueWrapper is described in swig.swg */
template<typename T> class SwigValueWrapper {
  struct SwigMovePointer {
    T *ptr;
    SwigMovePointer(T *p) : ptr(p) { }
    ~SwigMovePointer() { delete ptr; }
    SwigMovePointer& operator=(SwigMovePointer& rhs) { T* oldptr = ptr; ptr = 0; delete oldptr; ptr = rhs.ptr; rhs.ptr = 0; return *this; }
  } pointer;
  SwigValueWrapper& operator=(const SwigValueWrapper<T>& rhs);
  SwigValueWrapper(const SwigValueWrapper<T>& rhs);
public:
  SwigValueWrapper() : pointer(0) { }
  SwigValueWrapper& operator=(const T& t) { SwigMovePointer tmp(new T(t)); pointer = tmp; return *this; }
  operator T&() const { return *pointer.ptr; }
  T *operator&() { return pointer.ptr; }
};

template <typename T> T SwigValueInit() {
  return T();
}
#endif

/* -----------------------------------------------------------------------------
 *  This section contains generic SWIG labels for method/variable
 *  declarations/attributes, and other compiler dependent labels.
 * ----------------------------------------------------------------------------- */

/* template workaround for compilers that cannot correctly implement the C++ standard */
#ifndef SWIGTEMPLATEDISAMBIGUATOR
# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
#  define SWIGTEMPLATEDISAMBIGUATOR template
# elif defined(__HP_aCC)
/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
#  define SWIGTEMPLATEDISAMBIGUATOR template
# else
#  define SWIGTEMPLATEDISAMBIGUATOR
# endif
#endif

/* inline attribute */
#ifndef SWIGINLINE
# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
#   define SWIGINLINE inline
# else
#   define SWIGINLINE
# endif
#endif

/* attribute recognised by some compilers to avoid 'unused' warnings */
#ifndef SWIGUNUSED
# if defined(__GNUC__)
#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
#     define SWIGUNUSED __attribute__ ((__unused__))
#   else
#     define SWIGUNUSED
#   endif
# elif defined(__ICC)
#   define SWIGUNUSED __attribute__ ((__unused__))
# else
#   define SWIGUNUSED
# endif
#endif

#ifndef SWIG_MSC_UNSUPPRESS_4505
# if defined(_MSC_VER)
#   pragma warning(disable : 4505) /* unreferenced local function has been removed */
# endif
#endif

#ifndef SWIGUNUSEDPARM
# ifdef __cplusplus
#   define SWIGUNUSEDPARM(p)
# else
#   define SWIGUNUSEDPARM(p) p SWIGUNUSED
# endif
#endif

/* internal SWIG method */
#ifndef SWIGINTERN
# define SWIGINTERN static SWIGUNUSED
#endif

/* internal inline SWIG method */
#ifndef SWIGINTERNINLINE
# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
#endif

/* exporting methods */
#if defined(__GNUC__)
#  if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
#    ifndef GCC_HASCLASSVISIBILITY
#      define GCC_HASCLASSVISIBILITY
#    endif
#  endif
#endif

#ifndef SWIGEXPORT
# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
#   if defined(STATIC_LINKED)
#     define SWIGEXPORT
#   else
#     define SWIGEXPORT __declspec(dllexport)
#   endif
# else
#   if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
#     define SWIGEXPORT __attribute__ ((visibility("default")))
#   else
#     define SWIGEXPORT
#   endif
# endif
#endif

/* calling conventions for Windows */
#ifndef SWIGSTDCALL
# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
#   define SWIGSTDCALL __stdcall
# else
#   define SWIGSTDCALL
# endif
#endif

/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
# define _CRT_SECURE_NO_DEPRECATE
#endif

/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
# define _SCL_SECURE_NO_DEPRECATE
#endif

/* Deal with Apple's deprecated 'AssertMacros.h' from Carbon-framework */
#if defined(__APPLE__) && !defined(__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES)
# define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
#endif

/* Intel's compiler complains if a variable which was never initialised is
 * cast to void, which is a common idiom which we use to indicate that we
 * are aware a variable isn't used.  So we just silence that warning.
 * See: https://github.com/swig/swig/issues/192 for more discussion.
 */
#ifdef __INTEL_COMPILER
# pragma warning disable 592
#endif


#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>



typedef long long intgo;
typedef unsigned long long uintgo;


# if !defined(__clang__) && (defined(__i386__) || defined(__x86_64__))
#   define SWIGSTRUCTPACKED __attribute__((__packed__, __gcc_struct__))
# else
#   define SWIGSTRUCTPACKED __attribute__((__packed__))
# endif



typedef struct { char *p; intgo n; } _gostring_;
typedef struct { void* array; intgo len; intgo cap; } _goslice_;




#define swiggo_size_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
#define swiggo_size_assert(t, n) swiggo_size_assert_eq(sizeof(t), n, swiggo_sizeof_##t##_is_not_##n)

swiggo_size_assert(char, 1)
swiggo_size_assert(short, 2)
swiggo_size_assert(int, 4)
typedef long long swiggo_long_long;
swiggo_size_assert(swiggo_long_long, 8)
swiggo_size_assert(float, 4)
swiggo_size_assert(double, 8)

#ifdef __cplusplus
extern "C" {
#endif
extern void crosscall2(void (*fn)(void *, int), void *, int);
extern char* _cgo_topofstack(void) __attribute__ ((weak));
extern void _cgo_allocate(void *, int);
extern void _cgo_panic(void *, int);
#ifdef __cplusplus
}
#endif

static char *_swig_topofstack() {
  if (_cgo_topofstack) {
    return _cgo_topofstack();
  } else {
    return 0;
  }
}

static void _swig_gopanic(const char *p) {
  struct {
    const char *p;
  } SWIGSTRUCTPACKED a;
  a.p = p;
  crosscall2(_cgo_panic, &a, (int) sizeof a);
}




#define SWIG_contract_assert(expr, msg) \
  if (!(expr)) { _swig_gopanic(msg); } else


static void Swig_free(void* p) {
  free(p);
}

static void* Swig_malloc(int c) {
  return malloc(c);
}


    #include <atomic>
    #include <map>
    #include <iostream>
    #include <memory>
    
    #include <myLib/myLib.hpp>
    #include "../../examples/basic_host/command_line.h"
    #include "../../examples/basic_host/command_line.cpp"


    extern void printHelpAndExit(const char* binary, unsigned int exitCode);

#ifdef __cplusplus
extern "C" {
#endif

void _wrap_Swig_free_basic_host_5ddda8bb50543998(void *_swig_go_0) {
  void *arg1 = (void *) 0 ;
  
  arg1 = *(void **)&_swig_go_0; 
  
  Swig_free(arg1);
  
}


void *_wrap_Swig_malloc_basic_host_5ddda8bb50543998(intgo _swig_go_0) {
  int arg1 ;
  void *result = 0 ;
  void *_swig_go_result;
  
  arg1 = (int)_swig_go_0; 
  
  result = (void *)Swig_malloc(arg1);
  *(void **)&_swig_go_result = (void *)result; 
  return _swig_go_result;
}


void _wrap_printHelpAndExit_basic_host_5ddda8bb50543998(_gostring_ _swig_go_0, intgo _swig_go_1) {
  char *arg1 = (char *) 0 ;
  unsigned int arg2 ;
  
  
  arg1 = (char *)malloc(_swig_go_0.n + 1);
  memcpy(arg1, _swig_go_0.p, _swig_go_0.n);
  arg1[_swig_go_0.n] = '\0';
  
  arg2 = (unsigned int)_swig_go_1; 
  
  printHelpAndExit((char const *)arg1,arg2);
  
  free(arg1); 
}


#ifdef __cplusplus
}
#endif

The function in CPP PrintHelpAndExit:

void printHelpAndExit(const char* binary, unsigned int exitCode)
{
    std::cout << "Usage: " << binary
            << " -t test " << std::endl;
    std::cout << std::endl;
    std::cout << " -h                          Prints this help and exit" << std::endl;
    std::cout << " -t test                    test desc "
            "desc."
            << std::endl;
    exit(exitCode);
}

If you have any idea of a building problem or to debug what could cause this. I would be glad to hear it.

UPDATE #1:

I found that if I remove the lib <iostream>, I'm able to access my variables of my "../../examples/basic_host/command_line.h" without any problem. I still have no idea why this lib in particular is causing issues but I'm looking into it. Btw, I cannot just remove it as I need it in my c++ lib.

I found an other person building c++ with python and having the same issue as I with iostream but not expalining how to do it :

UPDATE #2:

Seems that it comes from my compiler, I'm currently using TDM GCC and got errors under windows. I tried with WSL2 Ubuntu to compile and it works. However I still need to build under Windows as I am using winsock in my lib.


Solution

  • The issue I had was the compiler I was using on Windows. I used to compile with TDM-GCC but there are know issues between this and iostreamlib as this post suggests...

    I just changed my compiler(gcc,g++,..) for building with SWIG to MinGW64 : download link. After that everything works and I'm able to use my lib without any problems. Thanks to people that tried helping me.