root/tools/lib/perf/include/internal/rc_check.h
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
#ifndef __LIBPERF_INTERNAL_RC_CHECK_H
#define __LIBPERF_INTERNAL_RC_CHECK_H

#include <stdlib.h>
#include <linux/zalloc.h>

/*
 * Enable reference count checking implicitly with leak checking, which is
 * integrated into address sanitizer.
 */
#if defined(__SANITIZE_ADDRESS__) || defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER)
#define REFCNT_CHECKING 1
#elif defined(__has_feature)
#if __has_feature(address_sanitizer) || __has_feature(leak_sanitizer)
#define REFCNT_CHECKING 1
#endif
#endif

/*
 * Shared reference count checking macros.
 *
 * Reference count checking is an approach to sanitizing the use of reference
 * counted structs. It leverages address and leak sanitizers to make sure gets
 * are paired with a put. Reference count checking adds a malloc-ed layer of
 * indirection on a get, and frees it on a put. A missed put will be reported as
 * a memory leak. A double put will be reported as a double free. Accessing
 * after a put will cause a use-after-free and/or a segfault.
 */

#ifndef REFCNT_CHECKING
/* Replaces "struct foo" so that the pointer may be interposed. */
#define DECLARE_RC_STRUCT(struct_name)          \
        struct struct_name

/* Declare a reference counted struct variable. */
#define RC_STRUCT(struct_name) struct struct_name

/*
 * Interpose the indirection. Result will hold the indirection and object is the
 * reference counted struct.
 */
#define ADD_RC_CHK(result, object) (result = object, object)

/* Strip the indirection layer. */
#define RC_CHK_ACCESS(object) object

/* Frees the object and the indirection layer. */
#define RC_CHK_FREE(object) free(object)

/* A get operation adding the indirection layer. */
#define RC_CHK_GET(result, object) ADD_RC_CHK(result, object)

/* A put operation removing the indirection layer. */
#define RC_CHK_PUT(object) {}

/* Pointer equality when the indirection may or may not be there. */
#define RC_CHK_EQUAL(object1, object2) (object1 == object2)

#else

/* Replaces "struct foo" so that the pointer may be interposed. */
#define DECLARE_RC_STRUCT(struct_name)                  \
        struct original_##struct_name;                  \
        struct struct_name {                            \
                struct original_##struct_name *orig;    \
        };                                              \
        struct original_##struct_name

/* Declare a reference counted struct variable. */
#define RC_STRUCT(struct_name) struct original_##struct_name

/*
 * Interpose the indirection. Result will hold the indirection and object is the
 * reference counted struct.
 */
#define ADD_RC_CHK(result, object)                                      \
        (                                                               \
                object ? (result = malloc(sizeof(*result)),             \
                        result ? (result->orig = object, result)        \
                        : (result = NULL, NULL))                        \
                : (result = NULL, NULL)                                 \
                )

/* Strip the indirection layer. */
#define RC_CHK_ACCESS(object) object->orig

/* Frees the object and the indirection layer. */
#define RC_CHK_FREE(object)                     \
        do {                                    \
                zfree(&object->orig);           \
                free(object);                   \
        } while(0)

/* A get operation adding the indirection layer. */
#define RC_CHK_GET(result, object) ADD_RC_CHK(result, (object ? object->orig : NULL))

/* A put operation removing the indirection layer. */
#define RC_CHK_PUT(object)                      \
        do {                                    \
                if (object) {                   \
                        object->orig = NULL;    \
                        free(object);           \
                }                               \
        } while(0)

/* Pointer equality when the indirection may or may not be there. */
#define RC_CHK_EQUAL(object1, object2) (object1 == object2 || \
                (object1 && object2 && object1->orig == object2->orig))

#endif

#endif /* __LIBPERF_INTERNAL_RC_CHECK_H */