CGO: Incorrect result after returning CString type to C + +

I use tidb (a kV structure database engine), and make its interface into a shared library through CGO, and then call it through C + +. Then I write a piece of data, and when I look up the data, something strange happens.

I can print out this data in a shared library, whether it’s byte or string. But when I pass it back to C + +, it looks like the data is truncated.

The code blocks in C + + are as follows

 std::string key = "f590ca8a-0283-4389-a769-5d66b8be72be.546733.1_wlf1";
    char *tarKey = const_cast<char*>(key.c_str());
    int newStrSize = key.size();
    cout<<"start get"<<endl;
    GetKey_return getRes = ((FUNC_GETKEY)funcMap["GetKey"])(1, beginRes, buildGoString(tarKey, newStrSize), 0);
    std::cout<<"res is " << getRes.r1 << std::endl;// Nothing can be printed here!!!!!!!!!
struct GetKey_return {
        GoInt32 r0;
        char* r1;
};

The code in the shared library compiled by GO is as follows

val, err := txn.Get(context.TODO(), []byte(key))
            if err != nil {
                if use == 0{
                        defer CloseTxn(client, index)
                }
                none := C.CString("")
                defer C.free(unsafe.Pointer(none))
                if err == kv.ErrNotExist{
                        return ErrorKeyNotExist, none
                }
                return  ErrorGetKeyFail, none
        }
        // todo: 0 close,1 continue use
        if use == 0{
                defer CloseTxn(client, index)
        }
        fmt.Println(val)   //  Val is a byte type, which can be printed normally.I give the result as 
                            //   follows.
        sval := string(val)
        fmt.Println(sval)   // It can also be printed here.I give the result as follows.
        res := C.CString(sval)
        fmt.Println(res)
        defer C.free(unsafe.Pointer(res))
        return OperatorSuccess, res

The value of this byte is :

[11 3 233 2 0 0 1 1 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 8 3 97 0 0 0 1 173 71 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 0 0 0 51 52 54 53 51 100 102 99 54 53 99 52 57 99 99 97 48 102 102 56 54 97 100 101 99 49 97 101 98 54 54 48 2 0 0 0 108 113 173 71 0 0 0 0 0 0 6 0 0 0 109 97 115 116 101 114 8 0 0 0 83 84 65 78 68 65 82 68 0 0 0 0 0 0 0 0 45 0 0 0 102 53 57 48 99 97 56 97 45 48 50 56 51 45 52 51 56 57 45 97 55 54 57 45 53 100 54 54 98 56 98 101 55 50 98 101 46 54 54 50 48 57 53 46 50 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 12 0 0 0 117 115 101 114 46 114 103 119 46 97 99 108 113 0 0 0 3 2 107 0 0 0 3 2 12 0 0 0 2 0 0 0 108 113 2 0 0 0 108 113 3 3 79 0 0 0 1 1 0 0 0 2 0 0 0 108 113 15 0 0 0 1 0 0 0 2 0 0 0 108 113 4 3 44 0 0 0 2 2 4 0 0 0 0 0 0 0 2 0 0 0 108 113 0 0 0 0 0 0 0 0 2 2 4 0 0 0 15 0 0 0 2 0 0 0 108 113 0 0 0 0 0 0 0 0 0 0 0 0 21 0 0 0 117 115 101 114 46 114 103 119 46 99 111 110 116 101 110 116 95 116 121 112 101 1 0 0 0 0 13 0 0 0 117 115 101 114 46 114 103 119 46 101 116 97 103 33 0 0 0 51 52 54 53 51 100 102 99 54 53 99 52 57 99 99 97 48 102 102 56 54 97 100 101 99 49 97 101 98 54 54 48 0 17 0 0 0 117 115 101 114 46 114 103 119 46 109 97 110 105 102 101 115 116 35 1 0 0 6 3 29 1 0 0 173 71 0 0 0 0 0 0 36 0 0 0 119 108 102 49 46 121 120 77 85 109 105 74 86 53 121 79 105 84 105 122 110 86 48 111 77 97 98 45 107 105 76 68 118 71 122 105 1 0 0 0 0 0 0 0 0 0 0 0 2 1 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 45 0 0 0 102 53 57 48 99 97 56 97 45 48 50 56 51 45 52 51 56 57 45 97 55 54 57 45 53 100 54 54 98 56 98 101 55 50 98 101 46 53 52 54 55 51 51 46 49 1 1 132 0 0 0 36 0 0 0 53 100 52 56 55 102 52 56 45 57 100 98 99 45 49 49 101 98 45 57 98 48 56 45 49 52 49 56 55 55 53 50 57 100 97 100 36 0 0 0 49 99 53 50 50 102 99 48 45 57 100 98 99 45 49 49 101 98 45 98 49 53 98 45 49 52 49 56 55 55 53 50 57 100 97 100 0 0 0 0 36 0 0 0 53 100 52 56 55 102 52 56 45 57 100 98 99 45 49 49 101 98 45 57 98 48 56 45 49 52 49 56 55 55 53 50 57 100 97 100 0 0 0 0 0 0 0 0 0 1 1 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

After converting the above byte to string, the output is:

a­G 34653dfc65c49cca0ff86adec1aeb660lq­GmasteSTANDARD-f590ca8a-0283-4389-a769-5d66b8be72be.662095.2 user.rgw.aclqk user.rgw.etag!34653dfc65c49cca0ff86adec1aeb660user.rgw.manifest#­G$wlf1.yxMUmiJV5yOiTiznV0oMab-kiLDvGzi @-f590ca8a-0283-4389-a769-5d66b8be72be.546733.1$5d487f48-9dbc-11eb-9b08-141877529dad$1c522fc0-9dbc-11eb-b15b-141877529dad$5d487f48-9dbc-11eb-9b08-141877529dad

Nothing can be printed after returning the string back to c++.

What error are you getting? I’m not sure if this is the problem or not, but it looks like your Go code frees the string that it returns which will likely result in a use after free error.

Yes, this is one of the problems, but even if I delete the defer function, this problem still exists. As you can see, this byte slice is 751 characters long, but when I return it to C + +, it’s only 4 characters long.
Therefore, I think the internal CString function may cause the btye slice to be truncated.

C strings (at least, those returned by C.CString) are terminated at the first 0 byte. They are not length-delimited like Go strings are.
If your strings are going to contain embedded nulls, you will need to use another sequence-of-bytes type, like that returned by C.CBytes.
(C.CString will still work, I think, but you would need to pass the length as well to C++ and make a std::string or something equivalent out of it.)

1 Like