Suis-je en train de faire quelque chose de mal ou est-ce un bug Go compilateur C?

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

  •  21-12-2019
  •  | 
  •  

Question

Donc, je suis portage xxhash de l'aide cgo Aller natif 9p C, mais je suis plutôt un problème bizarre.

La fonction de hachage fonctionne parfaitement bien si on l'appelle comme cgo fonction, mais si j'essaie d'utiliser la version "native" il renvoie le mal de hachage.

J'en sais assez C pour le faire fonctionner, mais avant de signaler le problème, je veux m'assurer que je ne fais rien de mal.

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;
}

Exécuter:

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

TL;DR:

A C de la fonction renvoie la valeur faux lorsqu'ils sont utilisés par Go 6c, même exacte C de la fonction renvoie la valeur correcte lorsqu'il est appelé par le biais de CGO.

//edit

J'ai eu une réponse sur le question, il ne va pas se fixe et le 9p de la chaîne va loin finalement.

À partir de mi...@golang.org:

le compilateur C finira par s'en aller.Plan pour qui, donc, ne pas compter sur elle.

Note du Plan 9 compilateur C n'est pas entièrement conforme à la norme ANSI, et nous ne sommes pas va pour corriger les bugs (parce que nous contrôler à la fois le compilateur et ses d'entrée, il nous suffit de contournement de ses bugs).

Était-ce utile?

La solution

Après quelques recherches, la modification de la signature de la fonction de

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

pour

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

Et en l'appelant comme :

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

Renvoie le bon de hachage.

Je ne suis toujours pas sûr de ce qui se passe, c' devrait de travail, comment il était à l'origine, mais j'imagine que l'exécution est en train de faire de la magie derrière les coulisses.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top