prevent use after frees with structures that are transfer:none

This commit is contained in:
RSWilli
2024-11-25 23:58:18 +01:00
parent 4c73c3cfbe
commit 178d38ef69
4 changed files with 37 additions and 22 deletions

View File

@@ -95,9 +95,7 @@ func (m *Message) GetStructure() *Structure {
return nil return nil
} }
// The returned structure must not be freed. Applies to all methods. return structureFromGlibNone(st)
// https://gstreamer.freedesktop.org/documentation/gstreamer/gstmessage.html#gst_message_parse_error_details
return wrapStructure(st)
} }
// parseToError returns a new GError from this message instance. There are multiple // parseToError returns a new GError from this message instance. There are multiple

View File

@@ -17,6 +17,7 @@ import (
"fmt" "fmt"
"os" "os"
"reflect" "reflect"
"runtime"
"sync" "sync"
"unsafe" "unsafe"
@@ -35,7 +36,7 @@ func NewStructure(name string) *Structure {
cName := C.CString(name) cName := C.CString(name)
defer C.free(unsafe.Pointer(cName)) defer C.free(unsafe.Pointer(cName))
structure := C.gst_structure_new_empty(cName) structure := C.gst_structure_new_empty(cName)
return wrapStructure(structure) return structureFromGlibFull(structure)
} }
// NewStructureFromString builds a new GstStructure from the given string. // NewStructureFromString builds a new GstStructure from the given string.
@@ -46,7 +47,7 @@ func NewStructureFromString(stStr string) *Structure {
if structure == nil { if structure == nil {
return nil return nil
} }
return wrapStructure(structure) return structureFromGlibFull(structure)
} }
// MarshalStructure will convert the given go struct into a GstStructure. Currently nested // MarshalStructure will convert the given go struct into a GstStructure. Currently nested
@@ -190,22 +191,54 @@ var TypeStructure = glib.Type(C.gst_structure_get_type())
var _ glib.ValueTransformer = &Structure{} var _ glib.ValueTransformer = &Structure{}
func (s *Structure) copy() *C.GstStructure {
return C.gst_structure_copy(s.Instance())
}
// ToGValue implements a glib.ValueTransformer // ToGValue implements a glib.ValueTransformer
func (s *Structure) ToGValue() (*glib.Value, error) { func (s *Structure) ToGValue() (*glib.Value, error) {
val, err := glib.ValueInit(TypeStructure) val, err := glib.ValueInit(TypeStructure)
if err != nil { if err != nil {
return nil, err return nil, err
} }
C.gst_value_set_structure( C.gst_value_set_structure(
(*C.GValue)(unsafe.Pointer(val.GValue)), (*C.GValue)(unsafe.Pointer(val.GValue)),
s.Instance(), s.copy(),
) )
return val, nil return val, nil
} }
// marshalStructure is used to extract the GstStructure from a GValue.
func marshalStructure(p unsafe.Pointer) (interface{}, error) {
c := C.gst_value_get_structure(toGValue(p))
obj := (*C.GstStructure)(unsafe.Pointer(c))
return structureFromGlibNone(obj), nil
}
func wrapStructure(st *C.GstStructure) *Structure { func wrapStructure(st *C.GstStructure) *Structure {
return &Structure{ return &Structure{
ptr: unsafe.Pointer(st), ptr: unsafe.Pointer(st),
gType: glib.Type(st._type), gType: glib.Type(st._type),
} }
} }
// structureFromGlibNone wraps a *C.GstStructure in a Structure after copying it.
// this is needed when the structure is returned from a function that does not transfer ownership.
func structureFromGlibNone(st *C.GstStructure) *Structure {
copy := C.gst_structure_copy(st)
return structureFromGlibFull(copy)
}
// structureFromGlibFull wraps a *C.GstStructure in a Structure. This is used when the structure
// is returned by a function that transfers ownership to the caller.
func structureFromGlibFull(st *C.GstStructure) *Structure {
s := wrapStructure(st)
runtime.SetFinalizer(s, func(s *Structure) {
s.Free()
})
return s
}

View File

@@ -161,16 +161,6 @@ func ValueGetCapsFeatures(value *glib.Value) *CapsFeatures {
return &CapsFeatures{native: feats} return &CapsFeatures{native: feats}
} }
// ValueGetStructure extracts the GstStructure from a glib.Value, or nil
// if one does not exist.
func ValueGetStructure(gval *glib.Value) *Structure {
st := C.gst_value_get_structure((*C.GValue)(unsafe.Pointer(gval.GValue)))
if st == nil {
return nil
}
return wrapStructure(st)
}
// ValueIntersect calculates the intersection of two values. If the values have a non-empty intersection, // ValueIntersect calculates the intersection of two values. If the values have a non-empty intersection,
// the value representing the intersection isreturned. Otherwise this function returns false. This function // the value representing the intersection isreturned. Otherwise this function returns false. This function
// can also return false for any allocation errors. // can also return false for any allocation errors.

View File

@@ -461,12 +461,6 @@ func marshalCapsFeatures(p unsafe.Pointer) (interface{}, error) {
return wrapCapsFeatures(obj), nil return wrapCapsFeatures(obj), nil
} }
func marshalStructure(p unsafe.Pointer) (interface{}, error) {
c := C.gst_value_get_structure(toGValue(p))
obj := (*C.GstStructure)(unsafe.Pointer(c))
return wrapStructure(obj), nil
}
func marshalContext(p unsafe.Pointer) (interface{}, error) { func marshalContext(p unsafe.Pointer) (interface{}, error) {
c := C.g_value_get_object(toGValue(p)) c := C.g_value_get_object(toGValue(p))
obj := (*C.GstContext)(unsafe.Pointer(c)) obj := (*C.GstContext)(unsafe.Pointer(c))