Clarify Memory Ownership Model of libCwtch and Callers
continuous-integration/drone/pr Build is passing Details

Provides a way of telling libCwtch to free memory returned from functions
that provide CStrings as results.
This commit is contained in:
Sarah Jamie Lewis 2021-08-24 22:01:53 -07:00
parent 23c15130c7
commit f86e670241
2 changed files with 40 additions and 14 deletions

27
MEMORY.md Normal file
View File

@ -0,0 +1,27 @@
# Memory Model
This document provides an overview of the memory model of libCwtch. Callers should consult this document to ensure
that they are properly handling pointers passed to-and-from libCwtch.
## Pointer Parameters
All pointers **passed** into functions in this library, except `c_FreePointer`, are assumed to be owned by the caller.
libCwtch **will not** modifying the underlying memory, nor attempt to free or otherwise modify these pointers.
This is realized by copying the underlying memory using `C.GoStringN`. libCwtch guarantees that it will not depend
on the underlying memory of these pointers being available after returning from this function.
Callers are responsible for freeing these pointers after the call has been completed.
## Returned Pointers
All pointers **returned** by functions in libCwtch should be assumed to owned by libCwtch
Callers **must not** modifying the underlying memory of these pointers, nor attempt to free or otherwise modify these pointers
through any method other than the one provided below.
Calling functions **must** copy the contents of the memory into their own memory space and then call `c_FreePointer` providing
the returned pointer as a parameter.
libCwtch guarantees that it will not modify or free the underlying memory of these pointers prior to a call to `c_FreePointer`.

27
lib.go
View File

@ -2,7 +2,10 @@
package main
// //Needed to invoke C.free
// #include <stdlib.h>
import "C"
import (
"crypto/rand"
"cwtch.im/cwtch/app"
@ -21,6 +24,7 @@ import (
"runtime"
"strconv"
"strings"
"unsafe"
"encoding/base64"
"git.openprivacy.ca/openprivacy/connectivity/tor"
@ -381,6 +385,7 @@ func SendProfileEvent(onion string, eventJson string) {
}
//export c_GetAppBusEvent
// the pointer returned from this function **must** be freed using c_Free
func c_GetAppBusEvent() *C.char {
return C.CString(GetAppBusEvent())
}
@ -427,20 +432,6 @@ func LoadProfiles(pass string) {
application.LoadProfiles(pass)
}
//export c_ContactEvents
func c_ContactEvents() *C.char {
return C.CString(ContactEvents())
}
func ContactEvents() string {
select {
case myevent := <-contactEventsQueue.OutChan():
return fmt.Sprintf("%v", myevent)
default:
return ""
}
}
//export c_AcceptContact
func c_AcceptContact(profilePtr *C.char, profileLen C.int, handlePtr *C.char, handleLen C.int) {
AcceptContact(C.GoStringN(profilePtr, profileLen), C.GoStringN(handlePtr, handleLen))
@ -520,6 +511,7 @@ func UpdateMessageFlags(profileOnion, handle string, mIdx int, flags int64) {
}
//export c_GetMessage
// the pointer returned from this function **must** be Freed by c_Free
func c_GetMessage(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, message_index C.int) *C.char {
profile := C.GoStringN(profile_ptr, profile_len)
handle := C.GoStringN(handle_ptr, handle_len)
@ -585,6 +577,7 @@ func GetMessage(profileOnion, handle string, message_index int) string {
}
//export c_GetMessagesByContentHash
// the pointer returned from this function **must** be freed by calling c_Free
func c_GetMessagesByContentHash(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, contenthash_ptr *C.char, contenthash_len C.int) *C.char {
profile := C.GoStringN(profile_ptr, profile_len)
handle := C.GoStringN(handle_ptr, handle_len)
@ -592,6 +585,12 @@ func c_GetMessagesByContentHash(profile_ptr *C.char, profile_len C.int, handle_p
return C.CString(GetMessagesByContentHash(profile, handle, contentHash))
}
//export c_FreePointer
// Dangerous function. Should only be used as documented in `MEMORY.md`
func c_FreePointer(ptr *C.char) {
C.free(unsafe.Pointer(ptr))
}
func GetMessagesByContentHash(profileOnion, handle string, contentHash string) string {
var indexedMessages []model.LocallyIndexedMessage
if application != nil {