minio / c2goasm

C to Go Assembly
Apache License 2.0
1.31k stars 110 forks source link

panic: runtime error: slice bounds out of range #3

Closed mrd0ll4r closed 7 years ago

mrd0ll4r commented 7 years ago

This sounded like a cool project, so I tried it out!

go env:

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/media/data/go"
GORACE=""
GOROOT="/opt/go/latest"
GOTOOLDIR="/opt/go/latest/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build111986249=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"

C: (xor128plus.c)

#include <stdint.h>

uint64_t XORShift128Plus(uint64_t *s) {
        uint64_t s1 = s[0];
        const uint64_t s0 = s[1];
        const uint64_t result = s0 + s1;
        s[0] = s0;
        s1 ^= s1 << 23; // a
        s[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5); // b, c
        return result; 
}

Compiling this with

clang -O3 -masm=intel -mno-red-zone -mstackrealign -mllvm -inline-threshold=1000 -fno-asynchronous-unwind-tables -fno-exceptions -fno-rtti -S xor128plus.c

yields (xor128plus.s):

        .text
        .file   "xor128plus.c"
        .globl  XORShift128Plus
        .align  16, 0x90
        .type   XORShift128Plus,@function
XORShift128Plus:                        # @XORShift128Plus
# BB#0:
        push    rbp
        mov     rbp, rsp
        and     rsp, -8
        mov     rcx, qword ptr [rdi]
        mov     rdx, qword ptr [rdi + 8]
        lea     rax, qword ptr [rdx + rcx]
        mov     qword ptr [rdi], rdx
        mov     rsi, rcx
        shl     rsi, 23
        xor     rsi, rcx
        mov     rcx, rsi
        xor     rcx, rdx
        shr     rsi, 18
        shr     rdx, 5
        xor     rdx, rcx
        xor     rdx, rsi
        mov     qword ptr [rdi + 8], rdx
        mov     rsp, rbp
        pop     rbp
        ret
.Ltmp0:
        .size   XORShift128Plus, .Ltmp0-XORShift128Plus

        .ident  "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)"
        .section        ".note.GNU-stack","",@progbits

Accompanied by xor128plusg_amd64.go:

import "unsafe"

//go:noescape
func _XORShift128Plus(s unsafe.Pointer) uint64

func XORShift128Plus(s [2]uint64) uint64 {
    return _XORShift128Plus(unsafe.Pointer(&s))
}

And finally running c2goasm -a -f xor128plus.s xor128plus_amd64.s yields:

Processing xor128plus.s
panic: runtime error: slice bounds out of range

goroutine 1 [running]:
main.extractNamePart(0xc42000b790, 0x7, 0xe, 0xc420043510, 0x4a0731)
    /media/data/go/src/github.com/minio/c2goasm/subroutine.go:262 +0xf6
main.extractName(0xc42000b788, 0xf, 0xc42000b788, 0xf)
    /media/data/go/src/github.com/minio/c2goasm/subroutine.go:273 +0x145
main.splitOnGlobals(0xc4200a6c00, 0x21, 0x40, 0x7f88b0c56428, 0x1b, 0x7f88b0c575f8)
    /media/data/go/src/github.com/minio/c2goasm/subroutine.go:50 +0x167
main.segmentSource(0xc4200a6c00, 0x21, 0x40, 0xc40000000c, 0x0, 0x4)
    /media/data/go/src/github.com/minio/c2goasm/subroutine.go:64 +0x5d
main.process(0xc4200a6c00, 0x21, 0x40, 0xc42000b6c0, 0x13, 0x0, 0x0, 0xc42008bae0, 0xc420043e60, 0x4bc2bb)
    /media/data/go/src/github.com/minio/c2goasm/c2goasm.go:78 +0x80
main.main()
    /media/data/go/src/github.com/minio/c2goasm/c2goasm.go:264 +0x403
fwessels commented 7 years ago

You need to pass in unsafe.Pointer(&s[0]) -- you are now getting the pointer to the slice struct, and not the data itself

mrd0ll4r commented 7 years ago

But s is a [2]uint64, not a []uint64? (Also I just tried it and it doesn't work.) Thanks for the quick reply still!

EDIT: I also just tried to have the C function accept a pointer to the value to be returned, instead of actually returning the value, still nothing...

fwessels commented 7 years ago

Was too quick, I see what is wrong (has to do with C vs C++ name mangling), will create a fix for this.

fwessels commented 7 years ago

The C++ name mangling parsing errored out which takes the form of eg. _ZN4Simd4Avx213Yuv444pToBgraEPKhmS2_mS2_mmmPhmh where the digits contain the length of the next part. In this case it was a plain style C name (XORShift128Plus) that happened to contain the 128 digits which threw the parsing off... 😄

For your reference here is the accompanying Go code (note that in line 7 the return parameter is also named: (result uint64)):

package main

import "unsafe"
import "fmt"

//go:noescape
func _XORShift128Plus(s unsafe.Pointer) (result uint64)

func XORShift128Plus(s [2]uint64) uint64 {
    return _XORShift128Plus(unsafe.Pointer(&s))
}

func main() {
        test := [2]uint64{}
        test[0] = 1
        test[1] = 2
        fmt.Println(XORShift128Plus(test))
}

Also make sure you move out the xor128plus.s file before you go build because otherwise go will try to include this as well.