xref: /petsc/src/sys/error/checkptr.c (revision c080761bfe1cff46c829144de5ba80844362b4d0)
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 @*/
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 /* ---------------------------------------------------------------------------------------*/
34 
35 #if PetscDefined(HAVE_SETJMP_H)
36   #include <setjmp.h>
37 static jmp_buf   PetscSegvJumpBuf;
38 static PetscBool PetscSegvJumpBuf_set;
39 
40 /*@C
41   PetscSignalSegvCheckPointerOrMpi - To be called from a signal handler for SIGSEGV.
42 
43   Not Collective, No Fortran Support
44 
45   Level: developer
46 
47   Note:
48   If the signal was received while executing `PetscCheckPointer()`, this function longjmps back
49   there, otherwise it returns with no effect. This function is called automatically by
50   `PetscSignalHandlerDefault()`.
51 
52 .seealso: `PetscPushSignalHandler()`
53 @*/
54 void PetscSignalSegvCheckPointerOrMpi(void)
55 {
56   if (PetscSegvJumpBuf_set) longjmp(PetscSegvJumpBuf, 1);
57 }
58 
59 /*@C
60   PetscCheckPointer - Returns `PETSC_TRUE` if a pointer points to accessible data
61 
62   Not Collective, No Fortran Support
63 
64   Input Parameters:
65 + ptr   - the pointer
66 - dtype - the type of data the pointer is suppose to point to
67 
68   Level: developer
69 
70   Notes:
71   This is a non-standard PETSc function in that it returns the result and does not return an error code.
72 
73   This function always returns true when running under Valgrind, or when compiled with asan options.
74 
75 .seealso: `PetscCheckPointerSetIntensity()`
76 @*/
77 PetscBool PetscCheckPointer(const void *ptr, PetscDataType dtype)
78 {
79   if (PETSC_RUNNING_ON_VALGRIND) return PETSC_TRUE;
80   if (!ptr) return PETSC_FALSE;
81   if (petsc_checkpointer_intensity < 1) return PETSC_TRUE;
82   if (PetscDefined(HAVE_SANITIZER)) return PETSC_TRUE;
83 
84   #if PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)
85   /* Skip the verbose check if we are inside a hot function. */
86   if (petscstack.hotdepth > 0 && petsc_checkpointer_intensity < 2) return PETSC_TRUE;
87   #endif
88 
89   PetscSegvJumpBuf_set = PETSC_TRUE;
90 
91   if (setjmp(PetscSegvJumpBuf)) {
92     /* A segv was triggered in the code below hence we return with an error code */
93     PetscSegvJumpBuf_set = PETSC_FALSE;
94     return PETSC_FALSE;
95   } else {
96     switch (dtype) {
97     case PETSC_INT: {
98       PETSC_UNUSED PetscInt x = *(volatile PetscInt *)ptr;
99       break;
100     }
101   #if defined(PETSC_USE_COMPLEX)
102     case PETSC_SCALAR: { /* C++ is seriously dysfunctional with volatile std::complex. */
103     #if defined(PETSC_USE_CXXCOMPLEX)
104       PetscReal                         xreal = ((volatile PetscReal *)ptr)[0], ximag = ((volatile PetscReal *)ptr)[1];
105       PETSC_UNUSED volatile PetscScalar x = xreal + PETSC_i * ximag;
106     #else
107       PETSC_UNUSED PetscScalar x = *(volatile PetscScalar *)ptr;
108     #endif
109       break;
110     }
111   #endif
112     case PETSC_REAL: {
113       PETSC_UNUSED PetscReal x = *(volatile PetscReal *)ptr;
114       break;
115     }
116     case PETSC_BOOL: {
117       PETSC_UNUSED PetscBool x = *(volatile PetscBool *)ptr;
118       break;
119     }
120     case PETSC_ENUM: {
121       PETSC_UNUSED PetscEnum x = *(volatile PetscEnum *)ptr;
122       break;
123     }
124     case PETSC_CHAR: {
125       PETSC_UNUSED char x = *(volatile char *)ptr;
126       break;
127     }
128     case PETSC_OBJECT: {
129       PETSC_UNUSED volatile PetscClassId classid = ((PetscObject)ptr)->classid;
130       break;
131     }
132     default:;
133     }
134   }
135   PetscSegvJumpBuf_set = PETSC_FALSE;
136   return PETSC_TRUE;
137 }
138 #endif
139