| /* 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 */ |