package libsignal /* #include #include */ import "C" import "unsafe" // Address identifies a Signal Protocol session peer: a logical recipient // name (for OMEMO, a bare JID) plus a numeric device ID. type Address struct { Name string DeviceID uint32 } // cAddress is a C-heap-allocated signal_protocol_address (struct and name // string both), for the specific cases - session_builder_create and // session_cipher_create - where the C library stores the *pointer* we pass // it and keeps dereferencing it for the object's entire lifetime (a // shallow assignment, e.g. `result_cipher->remote_address = remote_address;` // in session_cipher.c, confirmed by reading the source - not a defensive // copy). A transient, freed-after-the-call address (as a short-lived cgo // helper would naturally produce) becomes a use-after-free the moment the // constructor returns; this type's lifetime must instead match its owning // SessionBuilder/SessionCipher, freed only in their Close methods. type cAddress struct { ptr *C.signal_protocol_address } func newCAddress(addr Address) *cAddress { namePtr := C.CString(addr.Name) c := (*C.signal_protocol_address)(C.malloc(C.size_t(unsafe.Sizeof(C.signal_protocol_address{})))) c.name = namePtr c.name_len = C.size_t(len(addr.Name)) c.device_id = C.int32_t(addr.DeviceID) return &cAddress{ptr: c} } func (a *cAddress) free() { if a.ptr != nil { C.free(unsafe.Pointer(a.ptr.name)) C.free(unsafe.Pointer(a.ptr)) a.ptr = nil } } // addressFromC copies a C signal_protocol_address into a Go Address. func addressFromC(addr *C.signal_protocol_address) Address { return Address{ Name: C.GoStringN(addr.name, C.int(addr.name_len)), DeviceID: uint32(addr.device_id), } }