xref: /petsc/src/sys/error/checkptr.c (revision 03047865b8d8757cf1cf9cda45785c1537b01dc1)
1 #include <petsc/private/petscimpl.h>
2 
3 static PetscInt petsc_checkpointer_intensity = 1;
4 
5 /*@
6   PetscCheckPointerSetIntensity - Set the intensity of debug pointer checks
7 
8   Not Collective
9 
10   Input Parameter:
11 . intensity - how much to check pointers for validity
12 
13   Options Database Key:
14 . -check_pointer_intensity - intensity (0, 1, or 2)
15 
16   Level: advanced
17 
18   Notes:
19   An intense pointer check registers a signal handler and attempts to dereference to confirm
20   whether the address is valid.  An intensity of 0 never uses signal handlers, 1 uses them when
21   not in a "hot" function, and intensity of 2 always uses a signal handler.
22 
23 .seealso: `PetscCheckPointer()`, `PetscFunctionBeginHot()`
24 @*/
PetscCheckPointerSetIntensity(PetscInt intensity)25 PetscErrorCode PetscCheckPointerSetIntensity(PetscInt intensity)
26 {
27   PetscFunctionBegin;
28   PetscCheck((intensity >= 0) && (intensity <= 2), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Intensity %" PetscInt_FMT " not in [0,2]", intensity);
29   petsc_checkpointer_intensity = intensity;
30   PetscFunctionReturn(PETSC_SUCCESS);
31 }
32 
33 #if PetscDefined(HAVE_SETJMP_H)
34   #include <setjmp.h>
35 static jmp_buf   PetscSegvJumpBuf;
36 static PetscBool PetscSegvJumpBuf_set;
37 
38 /*@C
39   PetscSignalSegvCheckPointerOrMpi - To be called from a signal handler for SIGSEGV.
40 
41   Not Collective, No Fortran Support
42 
43   Level: developer
44 
45   Note:
46   If the signal was received while executing `PetscCheckPointer()`, this function longjmps back
47   there, otherwise it returns with no effect. This function is called automatically by
48   `PetscSignalHandlerDefault()`.
49 
50 .seealso: `PetscPushSignalHandler()`
51 @*/
PetscSignalSegvCheckPointerOrMpi(void)52 void PetscSignalSegvCheckPointerOrMpi(void)
53 {
54   if (PetscSegvJumpBuf_set) longjmp(PetscSegvJumpBuf, 1);
55 }
56 
57 /*@C
58   PetscCheckPointer - Returns `PETSC_TRUE` if a pointer points to accessible data
59 
60   Not Collective, No Fortran Support
61 
62   Input Parameters:
63 + ptr   - the pointer
64 - dtype - the type of data the pointer is suppose to point to
65 
66   Level: developer
67 
68   Notes:
69   This is a non-standard PETSc function in that it returns the result and does not return an error code.
70 
71   This function always returns true when running under Valgrind, or when compiled with asan options.
72 
73 .seealso: `PetscCheckPointerSetIntensity()`
74 @*/
PetscCheckPointer(const void * ptr,PetscDataType dtype)75 PetscBool PetscCheckPointer(const void *ptr, PetscDataType dtype)
76 {
77   if (PETSC_RUNNING_ON_VALGRIND) return PETSC_TRUE;
78   if (!ptr) return PETSC_FALSE;
79   if (petsc_checkpointer_intensity < 1) return PETSC_TRUE;
80   if (PetscDefined(HAVE_SANITIZER)) return PETSC_TRUE;
81 
82   #if PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)
83   /* Skip the verbose check if we are inside a hot function. */
84   if (petscstack.hotdepth > 0 && petsc_checkpointer_intensity < 2) return PETSC_TRUE;
85   #endif
86 
87   PetscSegvJumpBuf_set = PETSC_TRUE;
88 
89   if (setjmp(PetscSegvJumpBuf)) {
90     /* A segv was triggered in the code below hence we return with an error code */
91     PetscSegvJumpBuf_set = PETSC_FALSE;
92     return PETSC_FALSE;
93   } else {
94     switch (dtype) {
95     case PETSC_INT: {
96       PETSC_UNUSED PetscInt x = *(volatile PetscInt *)ptr;
97       break;
98     }
99   #if defined(PETSC_USE_COMPLEX)
100     case PETSC_SCALAR: { /* C++ is seriously dysfunctional with volatile std::complex. */
101     #if defined(PETSC_USE_CXXCOMPLEX)
102       PetscReal                         xreal = ((volatile PetscReal *)ptr)[0], ximag = ((volatile PetscReal *)ptr)[1];
103       PETSC_UNUSED volatile PetscScalar x = xreal + PETSC_i * ximag;
104     #else
105       PETSC_UNUSED PetscScalar x = *(volatile PetscScalar *)ptr;
106     #endif
107       break;
108     }
109   #endif
110     case PETSC_REAL: {
111       PETSC_UNUSED PetscReal x = *(volatile PetscReal *)ptr;
112       break;
113     }
114     case PETSC_BOOL: {
115       PETSC_UNUSED PetscBool x = *(volatile PetscBool *)ptr;
116       break;
117     }
118     case PETSC_ENUM: {
119       PETSC_UNUSED PetscEnum x = *(volatile PetscEnum *)ptr;
120       break;
121     }
122     case PETSC_CHAR: {
123       PETSC_UNUSED char x = *(volatile char *)ptr;
124       break;
125     }
126     case PETSC_OBJECT: {
127       PETSC_UNUSED volatile PetscClassId classid = ((PetscObject)ptr)->classid;
128       break;
129     }
130     default:;
131     }
132   }
133   PetscSegvJumpBuf_set = PETSC_FALSE;
134   return PETSC_TRUE;
135 }
136 #endif
137