I am trying to build a rust wrapper around a c library. For the structs in this library there are generally two functions for memory management, one for allocation and another for deallocation.
Now I plan to use the allocation code in the constructor of the wrapper type and the destructor in the drop trait for these types. However there's a problem, on some functions in the c library where we actually consume these structs, I see that these deallocation functions are being called within these functions. I fear that if I were to call one of these functions then allow the wrapper struct to go out of scope the deallocation code would run twice which is undefined behavior.
Is there a way to ensure drop isn't called for a block of code? Or somehow prevent this code from being called twice when these functions are called?
Here's the struct I am referring to picture.h
#ifndef __VMAF_PICTURE_H__
#define __VMAF_PICTURE_H__
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
enum VmafPixelFormat {
VMAF_PIX_FMT_UNKNOWN,
VMAF_PIX_FMT_YUV420P,
VMAF_PIX_FMT_YUV422P,
VMAF_PIX_FMT_YUV444P,
VMAF_PIX_FMT_YUV400P,
};
typedef struct VmafRef VmafRef;
typedef struct {
enum VmafPixelFormat pix_fmt;
unsigned bpc;
unsigned w[3], h[3];
ptrdiff_t stride[3];
void *data[3];
VmafRef *ref;
} VmafPicture;
int vmaf_picture_alloc(VmafPicture *pic, enum VmafPixelFormat pix_fmt,
unsigned bpc, unsigned w, unsigned h); // This function will allocate memory for a pointer to VmafPicture
int vmaf_picture_unref(VmafPicture *pic); // This will free memory of this pointer
#ifdef __cplusplus
}
#endif
#endif /* __VMAF_PICTURE_H__ */
And the function in question:
int vmaf_read_pictures(VmafContext *vmaf, VmafPicture *ref, VmafPicture *dist,
unsigned index)
{
if (!vmaf) return -EINVAL;
if (vmaf->flushed) return -EINVAL;
if (!ref != !dist) return -EINVAL;
if (!ref && !dist) return flush_context(vmaf);
int err = 0;
vmaf->pic_cnt++;
err = validate_pic_params(vmaf, ref, dist);
if (err) return err;
if (vmaf->thread_pool)
return threaded_read_pictures(vmaf, ref, dist, index);
for (unsigned i = 0; i < vmaf->registered_feature_extractors.cnt; i++) {
VmafFeatureExtractorContext *fex_ctx =
vmaf->registered_feature_extractors.fex_ctx[i];
if ((vmaf->cfg.n_subsample > 1) && (index % vmaf->cfg.n_subsample) &&
!(fex_ctx->fex->flags & VMAF_FEATURE_EXTRACTOR_TEMPORAL))
{
continue;
}
err = vmaf_feature_extractor_context_extract(fex_ctx, ref, NULL, dist,
NULL, index,
vmaf->feature_collector);
if (err) return err;
}
// Pictures are deallocated here!
err = vmaf_picture_unref(ref);
if (err) return err;
err = vmaf_picture_unref(dist);
if (err) return err;
return 0;
}
And here's the code for vmaf_picture_unref. To tell the truth I have no idea what's happening here as I am unfamiliar with c
int vmaf_picture_unref(VmafPicture *pic) {
if (!pic) return -EINVAL;
if (!pic->ref) return -EINVAL;
vmaf_ref_fetch_decrement(pic->ref);
if (vmaf_ref_load(pic->ref) == 0) {
aligned_free(pic->data[0]);
vmaf_ref_close(pic->ref);
}
memset(pic, 0, sizeof(*pic));
return 0;
}