Mapping C pointer to BYTE to golang []byte

159 views
Skip to first unread message

snmed

unread,
Dec 14, 2017, 2:05:32 AM12/14/17
to golang-nuts
Hi all

I'm trying to map a C structure to an equivalent go struct, but I bumped into a problem with a pointer to byte that is actually an array of bytes.

Here is the C struct:

typedef struct _CERT_CONTEXT {
  DWORD      dwCertEncodingType
;
  BYTE      
*pbCertEncoded;
  DWORD      cbCertEncoded
;
  PCERT_INFO pCertInfo
;
  HCERTSTORE hCertStore
;
} CERT_CONTEXT, *PCERT_CONTEXT;

and this is my go struct:

type CERT_CONTEXT struct {
    dwCertEncodingType uint32
    pbCertEncoded      uintptr
    cbCertEncoded      uint32
    pCertInfo          uintptr
    hCertStore         uintptr
}

for my case I need only the first 3 fields and I do not have any problem to get 1 and 3, but I can't remember how to translate the second field to a slice of bytes.
This is how I map the struct from an uintptr and print it to the console:

    certctx = (*CERT_CONTEXT) (unsafe.Pointer(pccert_context))
    fmt
.Printf("%v\n", certctx)
   
   
>&{1 807520 674 833008 789360}

Any advise is warmly welcome.

Cheers,
Sandro

Miki Tebeka

unread,
Dec 14, 2017, 3:18:26 AM12/14/17
to golang-nuts
Do you mean
func C.GoBytes(unsafe.Pointer, C.int) []byte
 ?

snmed

unread,
Dec 14, 2017, 3:29:38 AM12/14/17
to golang-nuts
Hi Miki

I'm using syscall package and no C import, but maybe it is possible to use this function as well?

snmed

unread,
Dec 14, 2017, 5:27:57 AM12/14/17
to golang-nuts
Okay I found a way, this seems to work:

ca := (*[1000000]byte) (unsafe.Pointer(certctx.pbCertEncoded))[:certctx.cbCertEncoded]

or

mm := make([]byte, certctx.cbCertEncoded)
   
for i := uint32(0) ; i < certctx.cbCertEncoded; i++ {
        mm
[i] = *((*byte)(unsafe.Pointer(certctx.pbCertEncoded + uintptr(i) * unsafe.Sizeof(new(byte)))))
   
}



Anyway, the vet tool is complaining:

main.go:106: possible misuse of unsafe.Pointer
main
.go:109: possible misuse of unsafe.Pointer

This is the code fragment:

104    certctx := new(CERT_CONTEXT)
105
106    certctx = (*CERT_CONTEXT) (unsafe.Pointer(pccert_context))
107
108    
109    ca := (*[1000000]byte) (unsafe.Pointer(certctx.pbCertEncoded))[:certctx.cbCertEncoded]

Is there another way to use syscall return values uintptr without vet warnings? And which solution should I prefer? I think the later one should be more safe, isn't it?

Cheers

Bryan Mills

unread,
Dec 14, 2017, 6:48:51 PM12/14/17
to golang-nuts
In this case, the vet tool is correct if you're making the syscall with Go-allocated memory.
The Go runtime is allowed to move values around: the address of a Go variable is only pinned for the duration of the syscall itself.

If you've got C-allocated memory (or statically-allocated memory), https://golang.org/issue/13656#issuecomment-303216308 has a solution that avoids copying and is more robust to large sizes.

snmed

unread,
Dec 15, 2017, 1:54:47 AM12/15/17
to golang-nuts
Hi Bryan

But the returned uintptr from syscall is as far as i know a pointer to a struct which has been created by the C API, so go runtime won't touch it or do I miss something?

Bryan C. Mills

unread,
Dec 15, 2017, 12:12:31 PM12/15/17
to snmed, golang-nuts
You haven't actually said which system call you're invoking, but from the name CERT_CONTEXT and the layout of the struct I'm guessing it's probably CertCreateCertificateContext or CertEnumCertificatesInStore?

I don't really know anything about Windows system calls, but it does seem like those allocate memory somewhere outside of the Go heap.


--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/0JYB0-ZcFpk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

snmed

unread,
Dec 15, 2017, 3:23:00 PM12/15/17
to golang-nuts
Sorry if I wasn't clear about that, I calling CertFindCertificateInStore which according to MSDN returns a pointer to a struct of type PCCERT_CONTEXT and must be freed with CertFreeCertificateContext.

The returned pointer is freed when passed as the pPrevCertContext parameter on a subsequent call to the function. Otherwise, the pointer must be explicitly freed by calling CertFreeCertificateContext. A pPrevCertContext that is not NULL is always freed by CertFindCertificateInStore using a call to CertFreeCertificateContext, even if there is an error in the function.

So yes it is allocated by the crypt API of Windows, but i'm still not sure if can ignore the vet warning or not. As far as I understand, go only manages the pointer to the struct but not the struct itself.

Bryan C. Mills

unread,
Dec 15, 2017, 4:33:16 PM12/15/17
to snmed, golang-nuts
You can ignore the vet warning if you are certain that the uintptr values you are converting to unsafe.Pointer are valid pointers (i.e., not non-pointer sentinel values) that point outside the Go heap.

It sounds like that is probably the case, but you might want to check with someone more familiar with Windows system calls to be sure.

--
Reply all
Reply to author
Forward
0 new messages