gotranspile / cxgo Goto Github PK
View Code? Open in Web Editor NEWTool for transpiling C to Go.
Home Page: https://gotranspile.dev
License: MIT License
Tool for transpiling C to Go.
Home Page: https://gotranspile.dev
License: MIT License
Currently cxgo
cannot translate any comments. To make it work, we need some support from cc side.
Before opening of NI , i send the same information to community (gotranspile/community room)
Looks not active since dec 2022
Because all examples failed on my computer (different reasons), I tried to check simple single file:
#include <stdlib.h>
#include <errno.h>
void main() {
errno = ENOMEM;
}
cxgo file main.c
creates :
package main
import "github.com/gotranspile/cxgo/runtime/libc"
func main() {
libc.Errno = ENOMEM
}
go build main.go returns error:
./main.go:6:15: undefined: ENOMEM
I expected that RegisterLibrary("errno.h",... will replace ENOMEM or add const to go file
This problem was solved using replace:
package: main
int_size: 8
ptr_size: 8
use_go_int: true
files:
name: main.c
replace:
old: 'ENOMEM'
new: '50'
What is the right way?
Possibly related to #10
Go enforces a syntactic reachability analysis for return
s, while C never required that returns be reachable and C compilers which do reachability use more sophisticated algorighms.
Some situations where the return
statement is considered reachable (or at least not an issue) by C are not considered reachable by Go.
It appears that cxgo
has implemented a bit of checking to implicitly add missing returns (see postproc.go:fixImplicitReturnStmts
).
However, I've found a test case which is improperly handled.
#include <stdio.h>
#define TRUE 1
#define FALSE 0
int implicit_return(char* str)
{
while(TRUE)
{
while(TRUE)
{
if(*str == '\0') { return 0; }
else if(*str != 'a') { break; }
str++;
}
printf("%c is not a\n", *str);
str++;
}
}
int main()
{
return implicit_return("aaabaababaaaaa");
}
I believe the last line of this function should have an (actually unreachable) return 0
added to fool Go into believing there is a reachable return 0
.
DISTRIBUTION STATEMENT “A”. (Approved for public release. Distribution is unlimited.)
This material is based upon work supported by DARPA under Contract No. HR001122C0047. Any opinions, findings and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of DARPA. DISTRIBUTION STATEMENT “A”. (Approved for public release. Distribution is unlimited.)
maze.io/x/math32 - looks broken
Downloading failed with timeout
It isn't the problem of cxgo per se ,
just FYI
Thanks
panic: types.ArrayType{elem:(*types.namedType)(0xc0000e2f30), size:1, slice:false}."name" (test.c:14:10)
struct s {
const char *const name;
};
static const struct s ss[] = {
{NULL },
};
int
main(void) {
if(!ss->name)
return(-1);
return 0;
}
Currently cxgo
ignores information about bit sizes of fields. Should be supported at some point if we want to transpile ~anything that touches the disk/network.
While testing Go 1.23 rc1 in
there was an error:
# github.com/gotranspile/cxgo/cmd/cxgo
link: github.com/gotranspile/cxgo/runtime/libc: invalid reference to runtime.findnull
Go 1.23 no longer allows //go:linkname * runtime.*
link instructioins, see
It is used several times in
https://github.com/gotranspile/cxgo/blob/29871598a6a289a52f5c92cfc3da031b8aa1ce6b/runtime/libc/runtime.go
C allows to take addresses of goto
labels.
cxgo
doesn't yet support label variables, however it should be possible to emulate.
Hi. I've found cxgo today and I think it's really exciting!
I decided to try to find some small project in C which might be interesting to be transpiled to go and this experiment was really successful. The project I found was Physac. It's a small 2d physics engine written in pure C with just a few deps.
I created a repo with end results of my try: https://github.com/koteyur/physac-go
In the first commit output is almost what I get after running cxgo. To make it usable I've just replaced time functions from libc package, because some of them wasn't implemented. After that it started working just fine.
TLDR; I think, this example of completely working program after using cxgo might be interesting.
Thanks!
#66 was finished
as result Adding new header section of contributing guide should be updated
In C it's valid to have struct foo
defined alongside with void foo()
. When using cxgo this causes name collision.
We should detect this case and append _t
to a converted Go type name automatically.
From struct_FILE.h
:
#ifndef _IO_lock_t_defined
typedef void _IO_lock_t;
#endif
Result:
2023/04/08 07:47:14 ipptool.c
panic: TODO: typedef of void? /usr/include/bits/types/struct_FILE.h:43:14
I cannot define _IO_lock_t_defined via yml, because
"...# error "_IO_lock_t_defined should only be defined when building libc itself"
convert.go:
if vt == nil {
panic("TODO: typedef of void? " + id.Position().String())
}
Is there workaround for this case?
For the case C header is constant string:
For 1. - Headers will be placed in dedicated folder and automatically registered
For 2. - Add instructions to Contributing guideline and examples
Implementation of proposed enhancement will be based on https://pkg.go.dev/embed
Currently auto
specifier is ignored. Should be fixed at some point.
Although it would be really awesome to have C++ support, we don't plan to support C++ yet.
We do believe that full C support will eventually help us bootstrap C++ support (by converting GCC, for example), but that requires a ton of work.
So please do not file new issues or questions about C++ code... Unless you are ready to bootstrap C++ support yourself 😉
Adding reaction here is welcome though. It will us help prioritize the conversion of GCC.
cxgo
2022/02/17 07:31:29 clonning https://github.com/skyrpex/potrace.git to C:\cygwin
64\tmp\potrace
Cloning into 'C:\cygwin64\tmp\potrace'...
remote: Enumerating objects: 151, done.
remote: Counting objects: 100% (151/151), done.
remote: Compressing objects: 100% (123/123), done.
remote: Total 151 (delta 28), reused 69 (delta 26), pack-reused 0
Receiving objects: 100% (151/151), 648.91 KiB | 1.03 MiB/s, done.
Resolving deltas: 100% (28/28), done.
Note: switching to 'd32fc5acc2b53b14d0b682cee8c641320fb1ef44'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
2022/02/17 07:31:31 writing to D:\code\cxgo-main.examples\potrace-go
2022/02/17 07:31:31 auxiliary.h
Error: auxiliary.h: parsing failed: C:\cygwin64\tmp\potrace\src\auxiliary.h:15:1
: include file not found: stdlib.h (wd D:\code\cxgo-main\examples\potrace)
search paths:
C:\cygwin64\tmp\potrace\src\includes
C:\cygwin64\tmp\potrace\src\include
/_cxgo_overrides
cxgo_predef.h:2:1: include file not found: cxgo_builtin.h (wd D:\code\cxgo-main
examples\potrace)
search paths:
C:\cygwin64\tmp\potrace\src\includes
C:\cygwin64\tmp\potrace\src\include
/_cxgo_overrides
Usage:
cxgo [flags]
cxgo [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
file transpile a single C file to Go
help Help about any command
version print cxgo version
Flags:
-c, --config string config file path (default "cxgo.yml")
-h, --help help for cxgo
Use "cxgo [command] --help" for more information about a command.
auxiliary.h: parsing failed: C:\cygwin64\tmp\potrace\src\auxiliary.h:15:1: inclu
de file not found: stdlib.h (wd D:\code\cxgo-main\examples\potrace)
search paths:
C:\cygwin64\tmp\potrace\src\includes
C:\cygwin64\tmp\potrace\src\include
/_cxgo_overrides
cxgo_predef.h:2:1: include file not found: cxgo_builtin.h (wd D:\code\cxgo-main
examples\potrace)
search paths:
C:\cygwin64\tmp\potrace\src\includes
C:\cygwin64\tmp\potrace\src\include
/_cxgo_overrides
$ cat nuklear.c
#define NK_IMPLEMENTATION
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#include "nuklear.h"
nuklear.h
is from https://github.com/Immediate-Mode-UI/Nuklear/blob/master/nuklear.h
Output of cxgo file nuklear.c
Error: parsing failed: nuklear.h:428:1: front-end: undefined: size_t
nuklear.h:429:1: front-end: undefined: size_t
nuklear.h:430:1: front-end: undefined: size_t
nuklear.h:431:1: front-end: undefined: size_t
nuklear.h:432:1: front-end: undefined: size_t
Go has more strict rules regarding what goto
jumps are valid.
cxgo
currently doesn't reflow goto
automatically. So "bad" goto
will fail to compile in Go.
There is a workaround implemented in cxgo
as one of the "ugly" ways to make the code compile. This workaround will completely flatten the code in a specified function.
We can try to implement a proper reflow algorithm, since those kind of goto
statements are quite common.
#include <stdint.h>
int main() {
typedef uint8_t MYubyte;
MYubyte vendor[] = "Robert Winkler";
return 0;
}
This code compiles under gcc but it doesn't in cxgo. I get this error:
Error: parsing failed: test.c:4:21: initializer for an object that has aggregate or union type shall be a brace-enclosed list of initializers for the elements or named members: array of MYubyte
After discussion in https://gitlab.com/cznic/cc/-/issues/126 it's clear that cxgo must define types like size_t
, ptrdiff_t
, etc.
Given the following C code:
struct hello {
struct inside {
int x;
} stuff;
};
I get this Go code:
package main
type hello struct {
Stuff inside
}
It doesn't generate the inside struct.
One thing that is missing from the project goals section in the documentation is the target use case. The use case makes a huge difference in how you approach the task of transpiling C to Go. Consider the difference between github.com/rsc/c2go
(use case: convert Go compiler and runtime to Go, and leave the C version behind) and modernc.org/ccgo
(use case: call C libraries, like sqlite, from Go without using CGo).
I found this much explanation of the use case in a Reddit comment:
The main idea for this project was to have cxgo download the latest commit, transpile it, and then push it to the go repo. Then by hand a developer can write an idiomatic and stable api on top of that others can use. This way future updates to the c project can be incorporated by just running the tool again.
So the use case appears to be basically in the "call C libraries without CGo" camp.
Currently cxgo fails on Nuklear due to the fact that we erase types for nil values:
typedef int ptrdiff_t;
#define NK_ALIGNOF(t) ((char*)(&((struct {char c; t _h;}*)0)->_h) - (char*)0)
int a = NK_ALIGNOF(int);
Do we want to start using unsafe.Add
for arrays? It will make the code shorter and potentially easier to read. It would, however, require that we push the version of the compiler to 1.17 and all resulting code would use that version too.
Example:
var Ptr *int
Ptr = (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(Ptr)) + uintptr(Len)))
Now becomes:
var Ptr *int
Ptr = (*int)(unsafe.Add(unsafe.Pointer(Ptr)), Len)
the following c code:
int a = 0;
(void)a;
should produce:
var a int = 0
_ = a
instead, it produces:
var a int = 0
a
which doesn't compile in go because the variable is evaluated but not used
Using a define that contains a block scope inside of an if statement removes the brackets. Given:
#define send_bits(s) \
{ int t = s;\
}
void main() {
int s;
if (0) {
send_bits(s)
send_bits(s)
send_bits(s)
}
}
The generated code:
package main
func main() {
var s int
if false {
var t int = s
_ = t
var t int = s
_ = t
var t int = s
_ = t
}
}
I would expect there to be an inner bracket for each time the define is used. This might be an issue with the preprocessor but I didn't know if CXGO does some "optimization" that would remove these brackets unintentionally. If there isn't an if statement the brackets are generated.
This C code panics:
void foo(void) {}
static void (*functions[1])(void) = {
foo,
};
void main() {
functions[0]();
}
with error:
panic: expected type must be set
goroutine 1 [running]:
github.com/gotranspile/cxgo.(*translator).ToFunc(0x1400040ca00, {0x105199000, 0x14000532e10}, 0x0)
/Users/jarrettkuklis/GolandProjects/cxgo/funcs.go:462 +0x400
github.com/gotranspile/cxgo.(*translator).convertPostfixExpr(0x1400040ca00, 0x1400046edc0)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:1013 +0x9a8
github.com/gotranspile/cxgo.(*translator).convertUnaryExpr(0x1400040ca00, 0x14000474540)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:1070 +0x1d4
github.com/gotranspile/cxgo.(*translator).convertCastExpr(0x1400040ca00, 0x14000470bd0)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:1052 +0x16c
github.com/gotranspile/cxgo.(*translator).convertMulExpr(0x1400040ca00, 0x14000473880)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:661 +0x18c
github.com/gotranspile/cxgo.(*translator).convertAddExpr(0x1400040ca00, 0x140004738f0)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:685 +0x178
github.com/gotranspile/cxgo.(*translator).convertShiftExpr(0x1400040ca00, 0x14000473960)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:707 +0x178
github.com/gotranspile/cxgo.(*translator).convertRelExpr(0x1400040ca00, 0x140004739d0)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:729 +0x154
github.com/gotranspile/cxgo.(*translator).convertEqExpr(0x1400040ca00, 0x14000473a40)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:752 +0x118
github.com/gotranspile/cxgo.(*translator).convertAndExpr(0x1400040ca00, 0x14000473ab0)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:771 +0x158
github.com/gotranspile/cxgo.(*translator).convertLOrExcExpr(0x1400040ca00, 0x14000473b20)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:787 +0x158
github.com/gotranspile/cxgo.(*translator).convertLOrIncExpr(0x1400040ca00, 0x14000473b90)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:803 +0x158
github.com/gotranspile/cxgo.(*translator).convertLAndExpr(0x1400040ca00, 0x14000459320)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:819 +0x1a4
github.com/gotranspile/cxgo.(*translator).convertLOrExpr(0x1400040ca00, 0x14000459380)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:832 +0x1a4
github.com/gotranspile/cxgo.(*translator).convertCondExpr(0x1400040ca00, 0x14000470c60)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:845 +0x1c4
github.com/gotranspile/cxgo.(*translator).convertAssignExpr(0x1400040ca00, 0x14000470cf0)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:1134 +0x218
github.com/gotranspile/cxgo.(*translator).convertExprStmt(0x1400040ca00, 0x14000466740)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:1203 +0x168
github.com/gotranspile/cxgo.(*translator).convertStmt(0x1400040ca00, 0x140004653b0)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:1355 +0x54
github.com/gotranspile/cxgo.(*translator).convertCompStmt(0x1400040ca00, 0x14000468270)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:616 +0x90
github.com/gotranspile/cxgo.(*translator).convertCompBlockStmt(0x1400040ca00, 0x14000468270)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:626 +0x30
github.com/gotranspile/cxgo.(*translator).convertFuncDef(0x1400040ca00, 0x140004681a0)
/Users/jarrettkuklis/GolandProjects/cxgo/convert.go:127 +0x1e8
github.com/gotranspile/cxgo.(*translator).translateC(0x1400040ca00, {0x16b167b4f, 0x2b}, 0x14000460900)
/Users/jarrettkuklis/GolandProjects/cxgo/translate.go:311 +0x174
github.com/gotranspile/cxgo.(*translator).translate(0x1400040ca00, {0x16b167b4f, 0x2b}, 0x14000460900)
/Users/jarrettkuklis/GolandProjects/cxgo/translate.go:260 +0x40
github.com/gotranspile/cxgo.TranslateAST({0x16b167b4f, 0x2b}, 0x14000460900, 0x14000246300, {{0x0, 0x0}, {0x105043b8c, 0x4}, {0x14000220120, 0x2c}, ...})
/Users/jarrettkuklis/GolandProjects/cxgo/translate.go:156 +0x70
github.com/gotranspile/cxgo.Translate({0x0, 0x0}, {0x16b167b4f, 0x2b}, {0x14000220120, 0x24}, 0x14000246300, {{0x0, 0x0}, {0x105043b8c, ...}, ...})
/Users/jarrettkuklis/GolandProjects/cxgo/translate.go:74 +0x194
main.init.0.func1(0x14000236780, {0x14000210930, 0x1, 0x1})
/Users/jarrettkuklis/GolandProjects/cxgo/cmd/cxgo/file.go:40 +0x178
github.com/spf13/cobra.(*Command).execute(0x14000236780, {0x14000210900, 0x1, 0x1})
/Users/jarrettkuklis/go/pkg/mod/github.com/spf13/[email protected]/command.go:826 +0x668
github.com/spf13/cobra.(*Command).ExecuteC(0x1053fde40)
/Users/jarrettkuklis/go/pkg/mod/github.com/spf13/[email protected]/command.go:914 +0x344
github.com/spf13/cobra.(*Command).Execute(...)
/Users/jarrettkuklis/go/pkg/mod/github.com/spf13/[email protected]/command.go:864
main.main()
/Users/jarrettkuklis/GolandProjects/cxgo/cmd/cxgo/main.go:63 +0x30
Process finished with the exit code 2
cxgo
doesn't support thread local storage yet.
We can emulate it by passing a *TLS
object to all the functions that use it, and to all their callers, similar to how context.Context
is passed in Go.
I tried to transpile some C source from this project.
Getting this panic:
/Users/prologic/tmp/genext2fs # cxgo file genext2fs.c
panic: interface conversion: types.Type is types.IntType, not *types.StructType
goroutine 1 [running]:
github.com/gotranspile/cxgo.(*translator).convertStructType.func1()
/go/pkg/mod/github.com/gotranspile/[email protected]/c_type.go:357 +0x6bd
github.com/gotranspile/cxgo.(*translator).newOrFindNamedType(0xc001932840, {0xc0000b4558, 0x8}, 0xc000fbfd98)
/go/pkg/mod/github.com/gotranspile/[email protected]/c_type.go:149 +0x8e
github.com/gotranspile/cxgo.(*translator).convertStructType(0xc001932840, {{0x0, 0x0}, 0x0, {0x0, 0x0}, 0x0, {0x0, 0x0}, 0x0, ...}, ...)
/go/pkg/mod/github.com/gotranspile/[email protected]/c_type.go:389 +0x275
github.com/gotranspile/cxgo.(*translator).newTypeCC(0xc001932840, {{0x0, 0x0}, 0x0, {0x0, 0x0}, 0x0, {0x0, 0x0}, 0x0, ...}, ...)
/go/pkg/mod/github.com/gotranspile/[email protected]/c_type.go:241 +0x618
github.com/gotranspile/cxgo.(*translator).convertType(0xc001932840, {{0x0, 0x0}, 0x0, {0x0, 0x0}, 0x0, {0x0, 0x0}, 0x0, ...}, ...)
/go/pkg/mod/github.com/gotranspile/[email protected]/c_type.go:59 +0x3c5
github.com/gotranspile/cxgo.(*translator).convertDecl(0xc001932840, 0xc000198640)
/go/pkg/mod/github.com/gotranspile/[email protected]/convert.go:391 +0x24f8
github.com/gotranspile/cxgo.(*translator).translateC(0xc001932840, {0x7ffcd8a76f0c?, 0xc0000bcc60?}, 0xc0017cf080)
/go/pkg/mod/github.com/gotranspile/[email protected]/translate.go:320 +0x133
github.com/gotranspile/cxgo.(*translator).translate(0xc001932840, {0x7ffcd8a76f0c, 0xb}, 0x4?)
/go/pkg/mod/github.com/gotranspile/[email protected]/translate.go:267 +0x4b
github.com/gotranspile/cxgo.TranslateAST({0x7ffcd8a76f0c, _}, _, _, {{0x0, 0x0}, {0x876f27, 0x4}, {0xc0000b4810, 0xc}, ...})
/go/pkg/mod/github.com/gotranspile/[email protected]/translate.go:163 +0x98
github.com/gotranspile/cxgo.Translate({0x0, _}, {_, _}, {_, _}, _, {{0x0, 0x0}, {0x876f27, ...}, ...})
/go/pkg/mod/github.com/gotranspile/[email protected]/translate.go:77 +0x233
main.init.0.func1(0xc0000b6780?, {0xc000098870?, 0x1?, 0x1?})
/go/pkg/mod/github.com/gotranspile/[email protected]/cmd/cxgo/file.go:40 +0x19a
github.com/spf13/cobra.(*Command).execute(0xc0000b6780, {0xc000098840, 0x1, 0x1})
/go/pkg/mod/github.com/spf13/[email protected]/command.go:826 +0x67c
github.com/spf13/cobra.(*Command).ExecuteC(0xb765c0)
/go/pkg/mod/github.com/spf13/[email protected]/command.go:914 +0x2ee
github.com/spf13/cobra.(*Command).Execute(...)
/go/pkg/mod/github.com/spf13/[email protected]/command.go:864
main.main()
/go/pkg/mod/github.com/gotranspile/[email protected]/cmd/cxgo/main.go:63 +0x25
/Users/prologic/tmp/genext2fs #
To reproduce:
$ git clone https://github.com/bestouff/genext2fs.git
$ docker run -i -t --rm -v $PWD:$PWD -w $PWD golang:alpine /bin/sh
# apk add musl-dev
# ln -s /usr/include .
# go install github.com/gotranspile/cxgo/cmd/cxgo@latest
# cxgo file genext2fs.c
I noticed that my project was randomly crashing from time to time with a panic similar to the following:
unexpected fault address 0xc00017ffe0
fatal error: fault
[signal 0xc0000005 code=0x0 addr=0xc00017ffe0 pc=0xc797b7]
goroutine 1 [running]:
runtime.throw({0xca46bd?, 0x0?})
C:/Program Files/Go/src/runtime/panic.go:992 +0x76 fp=0xc000071eb0 sp=0xc000071e80 pc=0xc50d76
runtime.sigpanic()
C:/Program Files/Go/src/runtime/signal_windows.go:261 +0x125 fp=0xc000071ef8 sp=0xc000071eb0 pc=0xc620a5
runtime.memmove()
C:/Program Files/Go/src/runtime/memmove_amd64.s:512 +0x657 fp=0xc000071f00 sp=0xc000071ef8 pc=0xc797b7
github.com/gotranspile/cxgo/runtime/libc.MemCpy(...)
C:/Users/Crazyinfin8/go/pkg/mod/github.com/gotranspile/[email protected]/runtime/libc/string.go:120
github.com/gotranspile/cxgo/runtime/libc.Realloc(0xc00000e1e8, 0x1312d00)
C:/Users/Crazyinfin8/go/pkg/mod/github.com/gotranspile/[email protected]/runtime/libc/memory.go:45 +0xd4 fp=0xc000071f40 sp=0xc000071f00 pc=0xc8efb4
main.main()
C:/Users/Crazyinfin8/Desktop/mpg-go/realloc/main.go:10 +0x79 fp=0xc000071f80 sp=0xc000071f40 pc=0xc8f239
runtime.main()
C:/Program Files/Go/src/runtime/proc.go:250 +0x1fe fp=0xc000071fe0 sp=0xc000071f80 pc=0xc5337e
runtime.goexit()
C:/Program Files/Go/src/runtime/asm_amd64.s:1571 +0x1 fp=0xc000071fe8 sp=0xc000071fe0 pc=0xc78341
exit status 2
Doing some investigation, I managed to pinpoint the issue was with the function Realloc
from the package github.com/gotranspile/cxgo/runtime/libc
. In doing so, I created a small case that appears to reliably reproduce this panic on my Windows machine though for some odd reason, this does not create any panics on Windows Subsystem for Linux.
package main
import "github.com/gotranspile/cxgo/runtime/libc"
func main() {
ptr := libc.Malloc(1)
println("Original Pointer is: ", ptr)
newPtr := libc.Realloc(ptr,20_000_000) // This panics sometimes
if newPtr == nil {
println("newPtr is nil")
} else {
println("New Pointer is: ", newPtr)
}
}
I suspect the cause of this issue is that during the call to Realloc
, it creates a new, bigger buffer. Then Realloc
calls MemCpy
but it converts both the original buffer and the new buffer as slices that are the size of the bigger buffer. This ends up making the call to Go's internal copy
function try to read more bytes than the original buffer is supposed to have access to, leading to a potential panic.
When I did go get -u github.com/gotranspile/cxgo/cmd/cxgo
on my windows computer. This is what was happened:
go: downloading modernc.org/cc/v3 v3.33.9
# github.com/gotranspile/cxgo/runtime/csys
D:\go\pkg\mod\github.com\gotranspile\[email protected]\runtime\csys\ioctl.go:22:30: not enough arguments in call to syscall.Syscall
D:\go\pkg\mod\github.com\gotranspile\[email protected]\runtime\csys\ioctl.go:22:31: undefined: syscall.SYS_IOCTL
# github.com/gotranspile/cxgo/runtime/cnet
D:\go\pkg\mod\github.com\gotranspile\[email protected]\runtime\cnet\socket.go:52:21: cannot use fd (type int) as type syscall.Handle in argument to syscall.Bind
D:\go\pkg\mod\github.com\gotranspile\[email protected]\runtime\cnet\socket.go:68:2: cannot use fd (type syscall.Handle) as type int in return argument
D:\go\pkg\mod\github.com\gotranspile\[email protected]\runtime\cnet\socket.go:103:30: cannot use fd (type int) as type syscall.Handle in argument to syscall.SetsockoptInt
This is because the syscall package is used which is different for each OS.
Just including sys/socket.h
causes a panic:
#include <sys/socket.h>
int main() {
inet_addr("...");
return 0;
}
I confirmed that arpa/inet.h
is being registered in registery.go
. I'm not sure the difference between Env.GetLibrary and Env.GetLib.
panic: cannot find library: arpa/inet.h
goroutine 38 [running]:
github.com/gotranspile/cxgo/libs.(*Env).GetLib(...)
/Users/jarrettkuklis/GolandProjects/cxgo/libs/config.go:58
github.com/gotranspile/cxgo/libs.init.29.func1(0xc000140320, 0xc000114c60)
/Users/jarrettkuklis/GolandProjects/cxgo/libs/sys_socket.go:20 +0x3211
github.com/gotranspile/cxgo/libs.(*Env).GetLibrary(0xc000140320, 0xc00002a051, 0xc, 0xc00039c601, 0xc00039e2a8)
/Users/jarrettkuklis/GolandProjects/cxgo/libs/registry.go:140 +0xe2
github.com/gotranspile/cxgo/libs.(*Env).NewLibrary(0xc000140320, 0xc00002a040, 0x1d, 0xc0001e3938, 0x10ad98d)
/Users/jarrettkuklis/GolandProjects/cxgo/libs/registry.go:193 +0xcf
github.com/gotranspile/cxgo.includeFS.content(0xc000140320, 0xc00002a040, 0x1d, 0xc00039c601, 0xc0001e3978, 0xc0001e3978, 0x10a6707, 0x1585b60)
/Users/jarrettkuklis/GolandProjects/cxgo/vfs.go:28 +0x4c
github.com/gotranspile/cxgo.includeFS.Stat(0xc000140320, 0xc00002a040, 0x1d, 0xc000110001, 0x1, 0x0, 0x1585d20, 0xc00039c660)
/Users/jarrettkuklis/GolandProjects/cxgo/vfs.go:36 +0x52
modernc.org/cc/v3.overlayFS.Stat(0x15891b0, 0x1805848, 0x1589138, 0xc000140320, 0xc00002a040, 0x1d, 0x1, 0x0, 0x1d, 0xc00002a040, ...)
/Users/jarrettkuklis/go/pkg/mod/modernc.org/cc/[email protected]/filesystem.go:87 +0x13b
modernc.org/cc/v3.(*context).statFile(0xc000104600, 0xc00002a040, 0x1d, 0xc00002a001, 0x1d, 0x0, 0x1585b60, 0xc000110030)
/Users/jarrettkuklis/go/pkg/mod/modernc.org/cc/[email protected]/cc.go:769 +0x5e
modernc.org/cc/v3.(*ppIncludeDirective).translationPhase4(0xc00015c740, 0xc00015a840)
/Users/jarrettkuklis/go/pkg/mod/modernc.org/cc/[email protected]/cpp.go:2462 +0xa6c
modernc.org/cc/v3.(*ppFile).translationPhase4(0xc000140440, 0xc00015a840)
/Users/jarrettkuklis/go/pkg/mod/modernc.org/cc/[email protected]/cpp.go:3029 +0xa3
modernc.org/cc/v3.(*cpp).translationPhase4.func2(0xc00015a840, 0xc000140480, 0x2, 0x2)
/Users/jarrettkuklis/go/pkg/mod/modernc.org/cc/[email protected]/cpp.go:2598 +0x1b2
created by modernc.org/cc/v3.(*cpp).translationPhase4
/Users/jarrettkuklis/go/pkg/mod/modernc.org/cc/[email protected]/cpp.go:2586 +0x126
Currently static
specifier is ignored, leading to incorrect code (variable is defined in the local scope, with the lifetime of a block).
This is a serious issue and it must be addressed.
Currently cxgo
ignores __attribute__((__packed__))
. We should support it eventually, if we want to transpile anything that touches disk/network.
Currently union
layout is ignored. Instead fields are flattened into the parent structure.
Proper layout should be implemented at some point if we want to transpile ~anything that touches the disk/network.
Given this C code:
int main() {
int *ptr = 0;
ptr -= 3;
return 0;
}
Results in this Go Code:
package main
import (
"os"
"unsafe"
)
func main() {
var ptr *int = nil
ptr = (*int)(unsafe.Add(unsafe.Pointer(ptr), -(unsafe.Sizeof(int(0)) * 3)))
os.Exit(0)
}
The negative number overflows uintptr from unsafe.Sizeof. Just casting it to any signed number fixes the error. Should it be a cast to int because that is usually the same size as the register like uintptr?
One of the c projects I am trying to convert uses RAND_MAX found in stdlib.h. I added it to the header in libs/stdlib.go and a go constant in runtime/libc/rand.go. I wondered if there is a way to make the header define equal to the go constant? This way future changes don't require two places to be updated.
It's typical to have constants defined with #define
.
cxgo
should recognize those patterns and declare the corresponding constant in Go.
Unfortunately last time I checked, cc had no info for macro expansion. Need to double-check this and possibly contribute support, if it's not there yet.
C supports case
in weird places. They are basically goto
labels, so they may be inside an if
statement.
We need to collect some real-world example for this. If it's common enough, we can solve it by some heavy AST rewrites of those switch
statements.
add support for Windows
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.