Actual source code: mempoison.h
1: #pragma once
3: #include <petsc/private/petscimpl.h>
5: /* SUBMANSEC = Sys */
7: #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
8: #include <sanitizer/asan_interface.h> // ASAN_POISON/UNPOISON_MEMORY_REGION
10: #define PETSC_HAVE_ASAN 1
11: #endif
13: #ifndef ASAN_POISON_MEMORY_REGION // use poison as canary
14: #define ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
15: #define ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
16: #endif
18: #if !PetscDefined(HAVE_WINDOWS_COMPILERS) && !defined(__MINGW32__)
19: #include <petsc/private/valgrind/memcheck.h>
21: // defined in memcheck.h
22: #if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) || defined(PLAT_amd64_darwin)
23: #define PETSC_HAVE_VALGRIND_MEMPOISON 1
24: #endif
25: #endif
27: #ifndef VALGRIND_MAKE_MEM_NOACCESS // use noaccess as canary
28: #define VALGRIND_MAKE_MEM_NOACCESS(addr, size) ((void)(addr), (void)(size))
29: #define VALGRIND_MAKE_MEM_UNDEFINED(addr, size) ((void)(addr), (void)(size))
30: #define VALGRIND_MAKE_MEM_DEFINED(addr, size) ((void)(addr), (void)(size))
31: #endif
33: /*@C
34: PetscPoisonMemoryRegion - Poison a region in memory, making it undereferencable
36: Not Available From Fortran
38: Input Parameters:
39: + ptr - The pointer to the start of the region
40: - size - The size (in bytes) of the region to poison
42: Level: developer
44: Notes:
45: `ptr` must not be `NULL`. It is OK to poison the same memory region repeatedly (it is a
46: no-op).
48: Any attempt to dereference the region after this routine returns results in an error being
49: raised. The memory region may be un-poisoned using `PetscUnpoisonMemoryRegion()`, making it
50: safe to dereference again.
52: Example Usage:
53: .vb
54: PetscInt *array;
56: PetscMalloc1(15, &array);
57: // OK, memory is normal
58: array[0] = 10;
59: array[1] = 15;
61: PetscPoisonMemoryRegion(array, 15 * sizeof(*array));
62: // ERROR this region is poisoned!
63: array[0] = 10;
64: // ERROR reading is not allowed either!
65: PetscInt v = array[15];
67: // OK can re-poison the region
68: PetscPoisonMemoryRegion(array, 15 * sizeof(*array));
69: // OK can re-poison any subregion too
70: PetscPoisonMemoryRegion(array + 5, 1 * sizeof(*array));
72: PetscUnpoisonMemoryRegion(array, 1 * sizeof(*array));
73: // OK the first entry has been unpoisoned
74: array[0] = 10;
75: // ERROR the rest of the region is still poisoned!
76: array[1] = 12345;
78: PetscUnpoisonMemoryRegion(array + 10, sizeof(*array));
79: // OK this region is unpoisoned (even though surrounding memory is still poisoned!)
80: array[10] = 0;
82: PetscInt stack_array[10];
84: // OK can poison stack memory as well
85: PetscPoisonMemoryRegion(stack_array, 10 * sizeof(*stack_array));
86: // ERROR stack array is poisoned!
87: stack_array[0] = 10;
88: .ve
90: .seealso: `PetscUnpoisonMemoryRegion()`, `PetscIsRegionPoisoned()`
91: @*/
92: static inline PetscErrorCode PetscPoisonMemoryRegion(const void *ptr, size_t size)
93: {
94: PetscFunctionBegin;
95: // cannot check ptr as it may be poisoned
96: // PetscAssertPointer(ptr, 1);
97: if (PetscDefined(HAVE_ASAN)) {
98: ASAN_POISON_MEMORY_REGION(ptr, size);
99: } else if (PetscDefined(HAVE_VALGRIND_MEMPOISON)) {
100: (void)VALGRIND_MAKE_MEM_NOACCESS(ptr, size);
101: (void)VALGRIND_MAKE_MEM_UNDEFINED(ptr, size);
102: } else {
103: (void)ptr;
104: (void)size;
105: }
106: PetscFunctionReturn(PETSC_SUCCESS);
107: }
109: /*@C
110: PetscUnpoisonMemoryRegion - Unpoison a previously poisoned memory region
112: Input Parameters:
113: + ptr - The pointer to the start of the region
114: - size - The size (in bytes) of the region to unpoison
116: Level: developer
118: Notes:
119: Removes poisoning from a previously poisoned region. `ptr` may not be `NULL`. It is OK to
120: unpoison an unpoisoned region.
122: See `PetscPoisonMemoryRegion()` for example usage and further discussion.
124: .seealso: `PetscPoisonMemoryRegion()`, `PetscIsRegionPoisoned()`
125: @*/
126: static inline PetscErrorCode PetscUnpoisonMemoryRegion(const void *ptr, size_t size)
127: {
128: PetscFunctionBegin;
129: // cannot check pointer as it is poisoned, duh!
130: // PetscAssertPointer(ptr, 1);
131: if (PetscDefined(HAVE_ASAN)) {
132: ASAN_UNPOISON_MEMORY_REGION(ptr, size);
133: } else if (PetscDefined(HAVE_VALGRIND_MEMPOISON)) {
134: (void)VALGRIND_MAKE_MEM_DEFINED(ptr, size);
135: } else {
136: (void)ptr;
137: (void)size;
138: }
139: PetscFunctionReturn(PETSC_SUCCESS);
140: }
142: /*@C
143: PetscIsRegionPoisoned - Query whether a particular memory region is poisoned
145: Input Parameters:
146: + ptr - The pointer to the start of the region
147: - size - The size (in bytes) of the region to query
149: Output Parameter:
150: . poisoned - Whether the region is known to be poisoned
152: Level: developer
154: Notes:
155: Sets `poisoned` to `PETSC_BOOL3_TRUE` if at least 1 byte in the range [`ptr`, `ptr + size`) is
156: poisoned. Therefore a region must be entirely unpoisoned for `poisoned` to be `PETSC_BOOL3_FALSE`.
158: If `ptr` is `NULL` or `size` is `0` then `poisoned` is set to `PETSC_BOOL3_FALSE`.
160: If it is not possible to query the poisoned status of a region, then `poisoned` is set to
161: `PETSC_BOOL3_UNKNOWN`.
163: .seealso: `PetscPoisonMemoryRegion()`, `PetscUnpoisonMemoryRegion()`
164: @*/
165: static inline PetscErrorCode PetscIsRegionPoisoned(const void *ptr, size_t size, PetscBool3 *poisoned)
166: {
167: PetscFunctionBegin;
168: // cannot check pointer as may be poisoned
169: // PetscAssertPointer(ptr, 1);
170: PetscAssertPointer(poisoned, 3);
171: *poisoned = PETSC_BOOL3_FALSE;
172: // if ptr is NULL, or if size = 0 then the "region" is not poisoned
173: if (ptr && size) {
174: #if PetscDefined(HAVE_ASAN)
175: if (__asan_region_is_poisoned((void *)ptr, size)) *poisoned = PETSC_BOOL3_TRUE;
176: #else
177: // valgrind does not appear to have a way of querying the status without raising an error
178: if (PetscDefined(HAVE_VALGRIND_MEMPOISON)) *poisoned = PETSC_BOOL3_UNKNOWN;
179: #endif
180: }
181: PetscFunctionReturn(PETSC_SUCCESS);
182: }