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
}
// The returned structure must not be freed. Applies to all methods.
// https://gstreamer.freedesktop.org/documentation/gstreamer/gstmessage.html#gst_message_parse_error_details
return wrapStructure(st)
return structureFromGlibNone(st)
}
// parseToError returns a new GError from this message instance. There are multiple

View File

@@ -17,6 +17,7 @@ import (
"fmt"
"os"
"reflect"
"runtime"
"sync"
"unsafe"
@@ -35,7 +36,7 @@ func NewStructure(name string) *Structure {
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
structure := C.gst_structure_new_empty(cName)
return wrapStructure(structure)
return structureFromGlibFull(structure)
}
// NewStructureFromString builds a new GstStructure from the given string.
@@ -46,7 +47,7 @@ func NewStructureFromString(stStr string) *Structure {
if structure == nil {
return nil
}
return wrapStructure(structure)
return structureFromGlibFull(structure)
}
// 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{}
func (s *Structure) copy() *C.GstStructure {
return C.gst_structure_copy(s.Instance())
}
// ToGValue implements a glib.ValueTransformer
func (s *Structure) ToGValue() (*glib.Value, error) {
val, err := glib.ValueInit(TypeStructure)
if err != nil {
return nil, err
}
C.gst_value_set_structure(
(*C.GValue)(unsafe.Pointer(val.GValue)),
s.Instance(),
s.copy(),
)
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 {
return &Structure{
ptr: unsafe.Pointer(st),
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}
}
// 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,
// the value representing the intersection isreturned. Otherwise this function returns false. This function
// 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
}
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) {
c := C.g_value_get_object(toGValue(p))
obj := (*C.GstContext)(unsafe.Pointer(c))