Sto facendo qualcosa di sbagliato o è questo un bug nel compilatore di Go's C?

StackOverflow https://stackoverflow.com//questions/25048775

  •  21-12-2019
  •  | 
  •  

Domanda

Quindi sto porting xxhash dall'utilizzo di CGO per Go nativo 9P C, però io "M correre in un problema piuttosto strano.

La funzione Hash funziona perfettamente fine se chiamata una funzione CGO, tuttavia se provo a utilizzare la versione "nativa" restituisce l'hash errato.

Conosco abbastanza c per farlo funzionare, ma prima di segnalare il problema, voglio assicurarmi che non sto facendo nulla di sbagliato.

GIST

xxhash.go:

//#include "xxhash_9p.c"
//import "C" //uncomment this and comment the next line for the cgo version
func XXH32_test(in unsafe.Pointer, l uint32, seed uint32) uint32


func GoXXH32(in []byte, seed uint32) (h uint32) {
    //omitted, full version in the gist above
}

func main() {
    b := []byte("ABCDEFGLAALSDLSD:LSDL:DL:DL:SDL:SL:DSL:DL:DSL:DL:{W{EOQWExzghp[[")
    fmt.Println(XXH32_test(unsafe.Pointer(&b[0]), uint32(len(b)), 0)) //uncomment this and comment the next line for the cgo version
    //fmt.Println(C.XXH32_test(unsafe.Pointer(&b[0]), C.uint(len(b)), 0))
    fmt.Println(GoXXH32(b, 0)) //this is tested against the C implementation and it's the right hash.
}
.

xxhash_9p.c:

#define PRIME32_1   2654435761U
#define PRIME32_2   2246822519U
#define PRIME32_3   3266489917U
#define PRIME32_4    668265263U
#define PRIME32_5    374761393U

#define U32 unsigned int
typedef struct _U32_S { U32 v; } U32_S;
#define A32(x) (((U32_S *)(x))->v)

U32 ·XXH32_test(const void* input, U32 len, U32 seed) {
//static U32 XXH32_test(const void* input, U32 len, U32 seed) {
    const char* p = (const char*)input;
    const char* bEnd = p + len;
    U32 h32;

    #define XXH_get32bits(p) A32(p)
    #define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))

    if (len>=16) {
        const char* const limit = bEnd - 16;
        U32 v1 = seed + PRIME32_1 + PRIME32_2;
        U32 v2 = seed + PRIME32_2;
        U32 v3 = seed + 0;
        U32 v4 = seed - PRIME32_1;
        do
        {
            v1 += XXH_get32bits(p) * PRIME32_2; v1 = XXH_rotl32(v1, 13); v1 *= PRIME32_1; p+=4;
            v2 += XXH_get32bits(p) * PRIME32_2; v2 = XXH_rotl32(v2, 13); v2 *= PRIME32_1; p+=4;
            v3 += XXH_get32bits(p) * PRIME32_2; v3 = XXH_rotl32(v3, 13); v3 *= PRIME32_1; p+=4;
            v4 += XXH_get32bits(p) * PRIME32_2; v4 = XXH_rotl32(v4, 13); v4 *= PRIME32_1; p+=4;
        } while (p<=limit);

        h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
    }
    else
    {
        h32  = seed + PRIME32_5;
    }

    h32 += (unsigned long) len;
    while (p<=bEnd-4) {
        h32 += XXH_get32bits(p) * PRIME32_3;
        h32  = XXH_rotl32(h32, 17) * PRIME32_4 ;
        p+=4;
    }

    while (p<bEnd) {
        h32 += (*p) * PRIME32_5;
        h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
        p++;
    }

    h32 ^= h32 >> 15;
    h32 *= PRIME32_2;
    h32 ^= h32 >> 13;
    h32 *= PRIME32_3;
    h32 ^= h32 >> 16;
    return h32;
}
.

Run:

$ go build && ./nocgo #9p native
134316512
981225178
$ go build && ./nocgo #cgo
981225178
981225178
.

TL; DR:

A funzione C Restituisce il valore sbagliato se utilizzato tramite il 6c di go, la stessa esatta funzione C restituisce il valore corretto quando viene chiamato tramite CGO.

// Modifica

Ho ricevuto una risposta su Problema , non è Verrà fissato e il toolchain 9P sta andando via eventualmente.

Da Mi ... @ Golang.org :

.

Il compilatore C alla fine andrà via. Pianifica per questo, quindi non fare affidamento su di esso.

Nota Il compilatore Plan 9 C non è completamente conforme ANSI e non lo siamo andando a correggere gli insetti in esso (perché controlliamo sia il compilatore che il suo Input, facciamo solo soluzionari i suoi bug).

È stato utile?

Soluzione

Dopo alcuni scavo, cambiando la firma della funzione da

U32 ·XXH32_test(const void* input, U32 len, U32 seed)
.

a

void ·XXH32_test(const unsigned char* input, U32 len, U32 seed, U32 *ret)
.

e chiamandolo come:

var u uint32
XXH32_test(unsafe.Pointer(&b[0]), uint32(len(b)), 0, &u)
.

restituisce l'hash corretto.

Non sono ancora sicuro di cosa sta succedendo, it dovrebbe funziona come è stato originariamente, ma immagino che il runtime stia facendo qualche magia dietro le quinte.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top