Aurelien Larcher
2021-01-08 b5a8497ec9558d0061024ac4b49f445bbe7d1094
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
This patch was developed in house for Bug 21658934. Python PyObject_Free()
implementation relies on being able to read memory that might not belong to
the current buffer. When ADIHEAP is enabled, this is detected as a violation.
Use an explicit nonfaulting load to ignore the ADI tag.
 
This patch should now work with both Studio and gcc compilers (and possibly
many others). It might be pushed upstream.
 
--- Python-3.9.0/Objects/obmalloc.c
+++ Python-3.9.0/Objects/obmalloc.c
@@ -1407,6 +1407,38 @@ obmalloc controls.  Since this test is n
 extremely desirable that it be this fast.
 */
 
+#ifdef __sparcv9
+/*
+ * Py_ADDRESS_IN_RANGE needs to access memory that might be arbitrarily
+ * tagged by an ADI aware allocator. The use of a nonfaulting load
+ * guarantees that the read will succeed.
+ */
+#ifdef __SUNPRO_C
+
+/* Studio can use built-in nonfaulting load instruction for vis.h */ 
+#include <vis.h>
+#define POOL_INDEX(x)   __vis_ldswa_ASI_PNF((void*)x)
+
+#else  /* __SUNPRO_C */
+/* 
+ * GCC doesn't have similar instruction built-in, but it can use
+ * following assembly code to do the same.
+ */
+
+static inline int vis_ldswa_ASI_PNF(void *arg);
+
+int vis_ldswa_ASI_PNF(void *arg) {
+  int res;
+  __asm__ ("ldswa  [%1]0x82,%0" : "=r" (res) : "r" (arg));
+  return res;
+}
+#define POOL_INDEX(x)   vis_ldswa_ASI_PNF((void*)x)
+
+#endif  /* __SUNPRO_C */
+#else   /* __sparcv9 */
+#define POOL_INDEX(x)   (*(x))
+#endif  /* __sparcv9 */
+
 static bool _Py_NO_SANITIZE_ADDRESS
             _Py_NO_SANITIZE_THREAD
             _Py_NO_SANITIZE_MEMORY
@@ -1417,7 +1449,7 @@ address_in_range(void *p, poolp pool)
     // another thread may be concurrently modifying the value without holding
     // the GIL. The following dance forces the compiler to read pool->arenaindex
     // only once.
-    uint arenaindex = *((volatile uint *)&pool->arenaindex);
+    uint arenaindex = (uint)POOL_INDEX((volatile uint *)&pool->arenaindex);
     return arenaindex < maxarenas &&
         (uintptr_t)p - arenas[arenaindex].address < ARENA_SIZE &&
         arenas[arenaindex].address != 0;