162306a36Sopenharmony_ci/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
262306a36Sopenharmony_ci#ifndef __LIBPERF_INTERNAL_RC_CHECK_H
362306a36Sopenharmony_ci#define __LIBPERF_INTERNAL_RC_CHECK_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <stdlib.h>
662306a36Sopenharmony_ci#include <linux/zalloc.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * Enable reference count checking implicitly with leak checking, which is
1062306a36Sopenharmony_ci * integrated into address sanitizer.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci#if defined(__SANITIZE_ADDRESS__) || defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER)
1362306a36Sopenharmony_ci#define REFCNT_CHECKING 1
1462306a36Sopenharmony_ci#elif defined(__has_feature)
1562306a36Sopenharmony_ci#if __has_feature(address_sanitizer) || __has_feature(leak_sanitizer)
1662306a36Sopenharmony_ci#define REFCNT_CHECKING 1
1762306a36Sopenharmony_ci#endif
1862306a36Sopenharmony_ci#endif
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/*
2162306a36Sopenharmony_ci * Shared reference count checking macros.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Reference count checking is an approach to sanitizing the use of reference
2462306a36Sopenharmony_ci * counted structs. It leverages address and leak sanitizers to make sure gets
2562306a36Sopenharmony_ci * are paired with a put. Reference count checking adds a malloc-ed layer of
2662306a36Sopenharmony_ci * indirection on a get, and frees it on a put. A missed put will be reported as
2762306a36Sopenharmony_ci * a memory leak. A double put will be reported as a double free. Accessing
2862306a36Sopenharmony_ci * after a put will cause a use-after-free and/or a segfault.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#ifndef REFCNT_CHECKING
3262306a36Sopenharmony_ci/* Replaces "struct foo" so that the pointer may be interposed. */
3362306a36Sopenharmony_ci#define DECLARE_RC_STRUCT(struct_name)		\
3462306a36Sopenharmony_ci	struct struct_name
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* Declare a reference counted struct variable. */
3762306a36Sopenharmony_ci#define RC_STRUCT(struct_name) struct struct_name
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/*
4062306a36Sopenharmony_ci * Interpose the indirection. Result will hold the indirection and object is the
4162306a36Sopenharmony_ci * reference counted struct.
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_ci#define ADD_RC_CHK(result, object) (result = object, object)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* Strip the indirection layer. */
4662306a36Sopenharmony_ci#define RC_CHK_ACCESS(object) object
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* Frees the object and the indirection layer. */
4962306a36Sopenharmony_ci#define RC_CHK_FREE(object) free(object)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* A get operation adding the indirection layer. */
5262306a36Sopenharmony_ci#define RC_CHK_GET(result, object) ADD_RC_CHK(result, object)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* A put operation removing the indirection layer. */
5562306a36Sopenharmony_ci#define RC_CHK_PUT(object) {}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#else
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* Replaces "struct foo" so that the pointer may be interposed. */
6062306a36Sopenharmony_ci#define DECLARE_RC_STRUCT(struct_name)			\
6162306a36Sopenharmony_ci	struct original_##struct_name;			\
6262306a36Sopenharmony_ci	struct struct_name {				\
6362306a36Sopenharmony_ci		struct original_##struct_name *orig;	\
6462306a36Sopenharmony_ci	};						\
6562306a36Sopenharmony_ci	struct original_##struct_name
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* Declare a reference counted struct variable. */
6862306a36Sopenharmony_ci#define RC_STRUCT(struct_name) struct original_##struct_name
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/*
7162306a36Sopenharmony_ci * Interpose the indirection. Result will hold the indirection and object is the
7262306a36Sopenharmony_ci * reference counted struct.
7362306a36Sopenharmony_ci */
7462306a36Sopenharmony_ci#define ADD_RC_CHK(result, object)					\
7562306a36Sopenharmony_ci	(								\
7662306a36Sopenharmony_ci		object ? (result = malloc(sizeof(*result)),		\
7762306a36Sopenharmony_ci			result ? (result->orig = object, result)	\
7862306a36Sopenharmony_ci			: (result = NULL, NULL))			\
7962306a36Sopenharmony_ci		: (result = NULL, NULL)					\
8062306a36Sopenharmony_ci		)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/* Strip the indirection layer. */
8362306a36Sopenharmony_ci#define RC_CHK_ACCESS(object) object->orig
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/* Frees the object and the indirection layer. */
8662306a36Sopenharmony_ci#define RC_CHK_FREE(object)			\
8762306a36Sopenharmony_ci	do {					\
8862306a36Sopenharmony_ci		zfree(&object->orig);		\
8962306a36Sopenharmony_ci		free(object);			\
9062306a36Sopenharmony_ci	} while(0)
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* A get operation adding the indirection layer. */
9362306a36Sopenharmony_ci#define RC_CHK_GET(result, object) ADD_RC_CHK(result, (object ? object->orig : NULL))
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* A put operation removing the indirection layer. */
9662306a36Sopenharmony_ci#define RC_CHK_PUT(object)			\
9762306a36Sopenharmony_ci	do {					\
9862306a36Sopenharmony_ci		if (object) {			\
9962306a36Sopenharmony_ci			object->orig = NULL;	\
10062306a36Sopenharmony_ci			free(object);		\
10162306a36Sopenharmony_ci		}				\
10262306a36Sopenharmony_ci	} while(0)
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#endif
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci#endif /* __LIBPERF_INTERNAL_RC_CHECK_H */
107