114 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 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 */
 |