thread_safety 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,116 @@
1
+ /*
2
+ * Vendored from Ruby v3_4_8 (tag: v3_4_8)
3
+ * Source: https://github.com/ruby/ruby/blob/v3_4_8/internal/compilers.h
4
+ *
5
+ * Reason: Ruby 3.4's modular GC was designed for in-tree builds only.
6
+ * See ext/gc-3.4/internal/bits.h for full explanation.
7
+ *
8
+ * License: Ruby's License (BSD-2-Clause) - see https://www.ruby-lang.org/en/about/license.txt
9
+ */
10
+ #ifndef INTERNAL_COMPILERS_H /*-*-C-*-vi:se ft=c:*/
11
+ #define INTERNAL_COMPILERS_H
12
+ /**
13
+ * @author Ruby developers <ruby-core@ruby-lang.org>
14
+ * @copyright This file is a part of the programming language Ruby.
15
+ * Permission is hereby granted, to either redistribute and/or
16
+ * modify this file, provided that the conditions mentioned in the
17
+ * file COPYING are met. Consult the file for details.
18
+ * @brief Internal header absorbing C compiler differences.
19
+ */
20
+ #include "ruby/internal/compiler_since.h"
21
+ #include "ruby/internal/has/attribute.h"
22
+ #include "ruby/internal/has/builtin.h"
23
+ #include "ruby/internal/has/c_attribute.h"
24
+ #include "ruby/internal/has/declspec_attribute.h"
25
+ #include "ruby/internal/has/extension.h"
26
+ #include "ruby/internal/has/feature.h"
27
+ #include "ruby/internal/has/warning.h"
28
+ #include "ruby/backward/2/gcc_version_since.h"
29
+
30
+ #define MSC_VERSION_SINCE(_) RBIMPL_COMPILER_SINCE(MSVC, (_) / 100, (_) % 100, 0)
31
+ #define MSC_VERSION_BEFORE(_) RBIMPL_COMPILER_BEFORE(MSVC, (_) / 100, (_) % 100, 0)
32
+
33
+ #ifndef __has_attribute
34
+ # define __has_attribute(...) RBIMPL_HAS_ATTRIBUTE(__VA_ARGS__)
35
+ #endif
36
+
37
+ #ifndef __has_c_attribute
38
+ # /* As of writing everything that lacks __has_c_attribute also completely
39
+ # * lacks C2x attributes as well. Might change in future? */
40
+ # define __has_c_attribute(...) 0
41
+ #endif
42
+
43
+ #ifndef __has_declspec_attribute
44
+ # define __has_declspec_attribute(...) RBIMPL_HAS_DECLSPEC_ATTRIBUTE(__VA_ARGS__)
45
+ #endif
46
+
47
+ #ifndef __has_builtin
48
+ # define __has_builtin(...) RBIMPL_HAS_BUILTIN(__VA_ARGS__)
49
+ #endif
50
+
51
+ #ifndef __has_feature
52
+ # define __has_feature(...) RBIMPL_HAS_FEATURE(__VA_ARGS__)
53
+ #endif
54
+
55
+ #ifndef __has_extension
56
+ # define __has_extension(...) RBIMPL_HAS_EXTENSION(__VA_ARGS__)
57
+ #endif
58
+
59
+ #ifndef __has_warning
60
+ # define __has_warning(...) RBIMPL_HAS_WARNING(__VA_ARGS__)
61
+ #endif
62
+
63
+ #ifndef __GNUC__
64
+ # define __extension__ /* void */
65
+ #endif
66
+
67
+ #ifndef MAYBE_UNUSED
68
+ # define MAYBE_UNUSED(x) x
69
+ #endif
70
+
71
+ #ifndef WARN_UNUSED_RESULT
72
+ # define WARN_UNUSED_RESULT(x) x
73
+ #endif
74
+
75
+ #define RB_OBJ_BUILTIN_TYPE(obj) rb_obj_builtin_type(obj)
76
+ #define OBJ_BUILTIN_TYPE(obj) RB_OBJ_BUILTIN_TYPE(obj)
77
+ #ifdef __GNUC__
78
+ #define rb_obj_builtin_type(obj) \
79
+ __extension__({ \
80
+ VALUE arg_obj = (obj); \
81
+ RB_SPECIAL_CONST_P(arg_obj) ? -1 : \
82
+ (int)RB_BUILTIN_TYPE(arg_obj); \
83
+ })
84
+ #else
85
+ # include "ruby/ruby.h"
86
+ static inline int
87
+ rb_obj_builtin_type(VALUE obj)
88
+ {
89
+ return RB_SPECIAL_CONST_P(obj) ? -1 :
90
+ (int)RB_BUILTIN_TYPE(obj);
91
+ }
92
+ #endif
93
+
94
+ /* A macro for defining a flexible array, like: VALUE ary[FLEX_ARY_LEN]; */
95
+ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
96
+ # define FLEX_ARY_LEN /* VALUE ary[]; */
97
+ #elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
98
+ # define FLEX_ARY_LEN 0 /* VALUE ary[0]; */
99
+ #else
100
+ # define FLEX_ARY_LEN 1 /* VALUE ary[1]; */
101
+ #endif
102
+
103
+ /*
104
+ * For declaring bitfields out of non-unsigned int types:
105
+ * struct date {
106
+ * BITFIELD(enum months, month, 4);
107
+ * ...
108
+ * };
109
+ */
110
+ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
111
+ # define BITFIELD(type, name, size) type name : size
112
+ #else
113
+ # define BITFIELD(type, name, size) unsigned int name : size
114
+ #endif
115
+
116
+ #endif /* INTERNAL_COMPILERS_H */
@@ -0,0 +1,201 @@
1
+ /*
2
+ * Vendored from Ruby v3_4_8 (tag: v3_4_8)
3
+ * Source: https://github.com/ruby/ruby/blob/v3_4_8/internal/hash.h
4
+ *
5
+ * Reason: Ruby 3.4's modular GC was designed for in-tree builds only.
6
+ * See ext/gc-3.4/internal/bits.h for full explanation.
7
+ *
8
+ * License: Ruby's License (BSD-2-Clause) - see https://www.ruby-lang.org/en/about/license.txt
9
+ */
10
+ #ifndef INTERNAL_HASH_H /*-*-C-*-vi:se ft=c:*/
11
+ #define INTERNAL_HASH_H
12
+ /**
13
+ * @author Ruby developers <ruby-core@ruby-lang.org>
14
+ * @copyright This file is a part of the programming language Ruby.
15
+ * Permission is hereby granted, to either redistribute and/or
16
+ * modify this file, provided that the conditions mentioned in the
17
+ * file COPYING are met. Consult the file for details.
18
+ * @brief Internal header for Hash.
19
+ */
20
+ #include "ruby/internal/config.h"
21
+ #include <stddef.h> /* for size_t */
22
+ #include "ruby/internal/stdbool.h" /* for bool */
23
+ #include "ruby/ruby.h" /* for struct RBasic */
24
+ #include "ruby/st.h" /* for struct st_table */
25
+
26
+ #define RHASH_AR_TABLE_MAX_SIZE SIZEOF_VALUE
27
+
28
+ struct ar_table_struct;
29
+ typedef unsigned char ar_hint_t;
30
+
31
+ enum ruby_rhash_flags {
32
+ RHASH_PASS_AS_KEYWORDS = FL_USER1, /* FL 1 */
33
+ RHASH_PROC_DEFAULT = FL_USER2, /* FL 2 */
34
+ RHASH_ST_TABLE_FLAG = FL_USER3, /* FL 3 */
35
+ RHASH_AR_TABLE_SIZE_MASK = (FL_USER4|FL_USER5|FL_USER6|FL_USER7), /* FL 4..7 */
36
+ RHASH_AR_TABLE_SIZE_SHIFT = (FL_USHIFT+4),
37
+ RHASH_AR_TABLE_BOUND_MASK = (FL_USER8|FL_USER9|FL_USER10|FL_USER11), /* FL 8..11 */
38
+ RHASH_AR_TABLE_BOUND_SHIFT = (FL_USHIFT+8),
39
+
40
+ // we can not put it in "enum" because it can exceed "int" range.
41
+ #define RHASH_LEV_MASK (FL_USER13 | FL_USER14 | FL_USER15 | /* FL 13..19 */ \
42
+ FL_USER16 | FL_USER17 | FL_USER18 | FL_USER19)
43
+
44
+ RHASH_LEV_SHIFT = (FL_USHIFT + 13),
45
+ RHASH_LEV_MAX = 127, /* 7 bits */
46
+ };
47
+
48
+ typedef struct ar_table_pair_struct {
49
+ VALUE key;
50
+ VALUE val;
51
+ } ar_table_pair;
52
+
53
+ typedef struct ar_table_struct {
54
+ union {
55
+ ar_hint_t ary[RHASH_AR_TABLE_MAX_SIZE];
56
+ VALUE word;
57
+ } ar_hint;
58
+ /* 64bit CPU: 8B * 2 * 8 = 128B */
59
+ ar_table_pair pairs[RHASH_AR_TABLE_MAX_SIZE];
60
+ } ar_table;
61
+
62
+ struct RHash {
63
+ struct RBasic basic;
64
+ const VALUE ifnone;
65
+ };
66
+
67
+ #define RHASH(obj) ((struct RHash *)(obj))
68
+
69
+ #ifdef RHASH_IFNONE
70
+ # undef RHASH_IFNONE
71
+ #endif
72
+
73
+ #ifdef RHASH_SIZE
74
+ # undef RHASH_SIZE
75
+ #endif
76
+
77
+ #ifdef RHASH_EMPTY_P
78
+ # undef RHASH_EMPTY_P
79
+ #endif
80
+
81
+ /* hash.c */
82
+ void rb_hash_st_table_set(VALUE hash, st_table *st);
83
+ VALUE rb_hash_default_value(VALUE hash, VALUE key);
84
+ VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc);
85
+ long rb_dbl_long_hash(double d);
86
+ st_table *rb_init_identtable(void);
87
+ st_index_t rb_any_hash(VALUE a);
88
+ int rb_any_cmp(VALUE a, VALUE b);
89
+ VALUE rb_to_hash_type(VALUE obj);
90
+ VALUE rb_hash_key_str(VALUE);
91
+ VALUE rb_hash_values(VALUE hash);
92
+ VALUE rb_hash_rehash(VALUE hash);
93
+ int rb_hash_add_new_element(VALUE hash, VALUE key, VALUE val);
94
+ VALUE rb_hash_set_pair(VALUE hash, VALUE pair);
95
+ int rb_hash_stlike_delete(VALUE hash, st_data_t *pkey, st_data_t *pval);
96
+ int rb_hash_stlike_foreach_with_replace(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg);
97
+ int rb_hash_stlike_update(VALUE hash, st_data_t key, st_update_callback_func *func, st_data_t arg);
98
+ VALUE rb_ident_hash_new_with_size(st_index_t size);
99
+ void rb_hash_free(VALUE hash);
100
+ RUBY_EXTERN VALUE rb_cHash_empty_frozen;
101
+
102
+ static inline unsigned RHASH_AR_TABLE_SIZE_RAW(VALUE h);
103
+ static inline VALUE RHASH_IFNONE(VALUE h);
104
+ static inline size_t RHASH_SIZE(VALUE h);
105
+ static inline bool RHASH_EMPTY_P(VALUE h);
106
+ static inline bool RHASH_AR_TABLE_P(VALUE h);
107
+ static inline bool RHASH_ST_TABLE_P(VALUE h);
108
+ static inline struct ar_table_struct *RHASH_AR_TABLE(VALUE h);
109
+ static inline st_table *RHASH_ST_TABLE(VALUE h);
110
+ static inline size_t RHASH_ST_SIZE(VALUE h);
111
+ static inline void RHASH_ST_CLEAR(VALUE h);
112
+
113
+ RUBY_SYMBOL_EXPORT_BEGIN
114
+ /* hash.c (export) */
115
+ VALUE rb_hash_delete_entry(VALUE hash, VALUE key);
116
+ VALUE rb_ident_hash_new(void);
117
+ int rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg);
118
+ RUBY_SYMBOL_EXPORT_END
119
+
120
+ VALUE rb_hash_new_with_size(st_index_t size);
121
+ VALUE rb_hash_resurrect(VALUE hash);
122
+ int rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval);
123
+ VALUE rb_hash_keys(VALUE hash);
124
+ VALUE rb_hash_has_key(VALUE hash, VALUE key);
125
+ VALUE rb_hash_compare_by_id_p(VALUE hash);
126
+
127
+ st_table *rb_hash_tbl_raw(VALUE hash, const char *file, int line);
128
+ #define RHASH_TBL_RAW(h) rb_hash_tbl_raw(h, __FILE__, __LINE__)
129
+
130
+ VALUE rb_hash_compare_by_id(VALUE hash);
131
+
132
+ static inline bool
133
+ RHASH_AR_TABLE_P(VALUE h)
134
+ {
135
+ return ! FL_TEST_RAW(h, RHASH_ST_TABLE_FLAG);
136
+ }
137
+
138
+ RBIMPL_ATTR_RETURNS_NONNULL()
139
+ static inline struct ar_table_struct *
140
+ RHASH_AR_TABLE(VALUE h)
141
+ {
142
+ return (struct ar_table_struct *)((uintptr_t)h + sizeof(struct RHash));
143
+ }
144
+
145
+ RBIMPL_ATTR_RETURNS_NONNULL()
146
+ static inline st_table *
147
+ RHASH_ST_TABLE(VALUE h)
148
+ {
149
+ return (st_table *)((uintptr_t)h + sizeof(struct RHash));
150
+ }
151
+
152
+ static inline VALUE
153
+ RHASH_IFNONE(VALUE h)
154
+ {
155
+ return RHASH(h)->ifnone;
156
+ }
157
+
158
+ static inline size_t
159
+ RHASH_SIZE(VALUE h)
160
+ {
161
+ if (RHASH_AR_TABLE_P(h)) {
162
+ return RHASH_AR_TABLE_SIZE_RAW(h);
163
+ }
164
+ else {
165
+ return RHASH_ST_SIZE(h);
166
+ }
167
+ }
168
+
169
+ static inline bool
170
+ RHASH_EMPTY_P(VALUE h)
171
+ {
172
+ return RHASH_SIZE(h) == 0;
173
+ }
174
+
175
+ static inline bool
176
+ RHASH_ST_TABLE_P(VALUE h)
177
+ {
178
+ return ! RHASH_AR_TABLE_P(h);
179
+ }
180
+
181
+ static inline size_t
182
+ RHASH_ST_SIZE(VALUE h)
183
+ {
184
+ return RHASH_ST_TABLE(h)->num_entries;
185
+ }
186
+
187
+ static inline void
188
+ RHASH_ST_CLEAR(VALUE h)
189
+ {
190
+ memset(RHASH_ST_TABLE(h), 0, sizeof(st_table));
191
+ }
192
+
193
+ static inline unsigned
194
+ RHASH_AR_TABLE_SIZE_RAW(VALUE h)
195
+ {
196
+ VALUE ret = FL_TEST_RAW(h, RHASH_AR_TABLE_SIZE_MASK);
197
+ ret >>= RHASH_AR_TABLE_SIZE_SHIFT;
198
+ return (unsigned)ret;
199
+ }
200
+
201
+ #endif /* INTERNAL_HASH_H */
@@ -0,0 +1,327 @@
1
+ /*
2
+ * Vendored from Ruby v3_4_8 (tag: v3_4_8)
3
+ * Source: https://github.com/ruby/ruby/blob/v3_4_8/internal/sanitizers.h
4
+ *
5
+ * Reason: Ruby 3.4's modular GC was designed for in-tree builds only.
6
+ * See ext/gc-3.4/internal/bits.h for full explanation.
7
+ *
8
+ * License: Ruby's License (BSD-2-Clause) - see https://www.ruby-lang.org/en/about/license.txt
9
+ */
10
+ #ifndef INTERNAL_SANITIZERS_H /*-*-C-*-vi:se ft=c:*/
11
+ #define INTERNAL_SANITIZERS_H
12
+ /**
13
+ * @author Ruby developers <ruby-core@ruby-lang.org>
14
+ * @copyright This file is a part of the programming language Ruby.
15
+ * Permission is hereby granted, to either redistribute and/or
16
+ * modify this file, provided that the conditions mentioned in the
17
+ * file COPYING are met. Consult the file for details.
18
+ * @brief Internal header for ASAN / MSAN / etc.
19
+ */
20
+ #include "ruby/internal/config.h"
21
+ #include "internal/compilers.h" /* for __has_feature */
22
+
23
+ #ifdef HAVE_VALGRIND_MEMCHECK_H
24
+ # include <valgrind/memcheck.h>
25
+ #endif
26
+
27
+ #ifdef HAVE_SANITIZER_ASAN_INTERFACE_H
28
+ # if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
29
+ # define RUBY_ASAN_ENABLED
30
+ # include <sanitizer/asan_interface.h>
31
+ # endif
32
+ #endif
33
+
34
+ #ifdef HAVE_SANITIZER_MSAN_INTERFACE_H
35
+ # if __has_feature(memory_sanitizer)
36
+ # define RUBY_MSAN_ENABLED
37
+ # include <sanitizer/msan_interface.h>
38
+ # endif
39
+ #endif
40
+
41
+ #include "ruby/internal/stdbool.h" /* for bool */
42
+ #include "ruby/ruby.h" /* for VALUE */
43
+
44
+ #if 0
45
+ #elif defined(RUBY_ASAN_ENABLED) && defined(RUBY_MSAN_ENABLED)
46
+ # define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
47
+ __attribute__((__no_sanitize__("memory, address"), __noinline__)) x
48
+ #elif defined(RUBY_ASAN_ENABLED)
49
+ # define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
50
+ __attribute__((__no_sanitize__("address"), __noinline__)) x
51
+ #elif defined(RUBY_MSAN_ENABLED)
52
+ # define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
53
+ __attribute__((__no_sanitize__("memory"), __noinline__)) x
54
+ #elif defined(NO_SANITIZE_ADDRESS)
55
+ # define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
56
+ NO_SANITIZE_ADDRESS(NOINLINE(x))
57
+ #elif defined(NO_ADDRESS_SAFETY_ANALYSIS)
58
+ # define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
59
+ NO_ADDRESS_SAFETY_ANALYSIS(NOINLINE(x))
60
+ #else
61
+ # define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) x
62
+ #endif
63
+
64
+ #if defined(NO_SANITIZE) && RBIMPL_COMPILER_IS(GCC)
65
+ /* GCC warns about unknown sanitizer, which is annoying. */
66
+ # include "internal/warnings.h"
67
+ # undef NO_SANITIZE
68
+ # define NO_SANITIZE(x, y) \
69
+ COMPILER_WARNING_PUSH \
70
+ COMPILER_WARNING_IGNORED(-Wattributes) \
71
+ __attribute__((__no_sanitize__(x))) y; \
72
+ COMPILER_WARNING_POP \
73
+ y
74
+ #endif
75
+
76
+ #ifndef NO_SANITIZE
77
+ # define NO_SANITIZE(x, y) y
78
+ #endif
79
+
80
+ #ifndef RUBY_ASAN_ENABLED
81
+ # define __asan_poison_memory_region(x, y)
82
+ # define __asan_unpoison_memory_region(x, y)
83
+ # define __asan_region_is_poisoned(x, y) 0
84
+ # define __asan_get_current_fake_stack() NULL
85
+ # define __asan_addr_is_in_fake_stack(fake_stack, slot, start, end) NULL
86
+ #endif
87
+
88
+ #ifndef RUBY_MSAN_ENABLED
89
+ # define __msan_allocated_memory(x, y) ((void)(x), (void)(y))
90
+ # define __msan_poison(x, y) ((void)(x), (void)(y))
91
+ # define __msan_unpoison(x, y) ((void)(x), (void)(y))
92
+ # define __msan_unpoison_string(x) ((void)(x))
93
+ #endif
94
+
95
+ #ifdef VALGRIND_MAKE_READABLE
96
+ # define VALGRIND_MAKE_MEM_DEFINED(p, n) VALGRIND_MAKE_READABLE((p), (n))
97
+ #endif
98
+
99
+ #ifdef VALGRIND_MAKE_WRITABLE
100
+ # define VALGRIND_MAKE_MEM_UNDEFINED(p, n) VALGRIND_MAKE_WRITABLE((p), (n))
101
+ #endif
102
+
103
+ #ifndef VALGRIND_MAKE_MEM_DEFINED
104
+ # define VALGRIND_MAKE_MEM_DEFINED(p, n) 0
105
+ #endif
106
+
107
+ #ifndef VALGRIND_MAKE_MEM_UNDEFINED
108
+ # define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0
109
+ #endif
110
+
111
+ /**
112
+ * This function asserts that a (continuous) memory region from ptr to size
113
+ * being "poisoned". Both read / write access to such memory region are
114
+ * prohibited until properly unpoisoned. The region must be previously
115
+ * allocated (do not pass a freed pointer here), but not necessarily be an
116
+ * entire object that the malloc returns. You can punch hole a part of a
117
+ * gigantic heap arena. This is handy when you do not free an allocated memory
118
+ * region to reuse later: poison when you keep it unused, and unpoison when you
119
+ * reuse.
120
+ *
121
+ * @param[in] ptr pointer to the beginning of the memory region to poison.
122
+ * @param[in] size the length of the memory region to poison.
123
+ */
124
+ static inline void
125
+ asan_poison_memory_region(const volatile void *ptr, size_t size)
126
+ {
127
+ __msan_poison(ptr, size);
128
+ __asan_poison_memory_region(ptr, size);
129
+ }
130
+
131
+ #ifdef RUBY_ASAN_ENABLED
132
+ #define asan_poison_object_if(ptr, obj) do { \
133
+ if (ptr) rb_asan_poison_object(obj); \
134
+ } while (0)
135
+ #else
136
+ #define asan_poison_object_if(ptr, obj) ((void)(ptr), (void)(obj))
137
+ #endif
138
+
139
+ RUBY_SYMBOL_EXPORT_BEGIN
140
+ /**
141
+ * This is a variant of asan_poison_memory_region that takes a VALUE.
142
+ *
143
+ * @param[in] obj target object.
144
+ */
145
+ void rb_asan_poison_object(VALUE obj);
146
+
147
+ /**
148
+ * This function predicates if the given object is fully addressable or not.
149
+ *
150
+ * @param[in] obj target object.
151
+ * @retval 0 the given object is fully addressable.
152
+ * @retval otherwise pointer to first such byte who is poisoned.
153
+ */
154
+ void *rb_asan_poisoned_object_p(VALUE obj);
155
+
156
+ /**
157
+ * This is a variant of asan_unpoison_memory_region that takes a VALUE.
158
+ *
159
+ * @param[in] obj target object.
160
+ * @param[in] malloc_p if the memory region is like a malloc's return value or not.
161
+ */
162
+ void rb_asan_unpoison_object(VALUE obj, bool newobj_p);
163
+
164
+ RUBY_SYMBOL_EXPORT_END
165
+
166
+ /**
167
+ * This function asserts that a (formally poisoned) memory region from ptr to
168
+ * size is now addressable. Write access to such memory region gets allowed.
169
+ * However read access might or might not be possible depending on situations,
170
+ * because the region can have contents of previous usages. That information
171
+ * should be passed by the malloc_p flag. If that is true, the contents of the
172
+ * region is _not_ fully defined (like the return value of malloc behaves).
173
+ * Reading from there is NG; write something first. If malloc_p is false on
174
+ * the other hand, that memory region is fully defined and can be read
175
+ * immediately.
176
+ *
177
+ * @param[in] ptr pointer to the beginning of the memory region to unpoison.
178
+ * @param[in] size the length of the memory region.
179
+ * @param[in] malloc_p if the memory region is like a malloc's return value or not.
180
+ */
181
+ static inline void
182
+ asan_unpoison_memory_region(const volatile void *ptr, size_t size, bool malloc_p)
183
+ {
184
+ __asan_unpoison_memory_region(ptr, size);
185
+ if (malloc_p) {
186
+ __msan_allocated_memory(ptr, size);
187
+ }
188
+ else {
189
+ __msan_unpoison(ptr, size);
190
+ }
191
+ }
192
+
193
+ static inline void *
194
+ asan_unpoison_object_temporary(VALUE obj)
195
+ {
196
+ void *ptr = rb_asan_poisoned_object_p(obj);
197
+ rb_asan_unpoison_object(obj, false);
198
+ return ptr;
199
+ }
200
+
201
+ static inline void *
202
+ asan_poison_object_restore(VALUE obj, void *ptr)
203
+ {
204
+ if (ptr) {
205
+ rb_asan_poison_object(obj);
206
+ }
207
+ return NULL;
208
+ }
209
+
210
+ #define asan_unpoisoning_object(obj) \
211
+ for (void *poisoned = asan_unpoison_object_temporary(obj), \
212
+ *unpoisoning = &poisoned; /* flag to loop just once */ \
213
+ unpoisoning; \
214
+ unpoisoning = asan_poison_object_restore(obj, poisoned))
215
+
216
+
217
+ static inline void *
218
+ asan_unpoison_memory_region_temporary(void *ptr, size_t len)
219
+ {
220
+ void *poisoned_ptr = __asan_region_is_poisoned(ptr, len);
221
+ asan_unpoison_memory_region(ptr, len, false);
222
+ return poisoned_ptr;
223
+ }
224
+
225
+ static inline void *
226
+ asan_poison_memory_region_restore(void *ptr, size_t len, void *poisoned_ptr)
227
+ {
228
+ if (poisoned_ptr) {
229
+ asan_poison_memory_region(ptr, len);
230
+ }
231
+ return NULL;
232
+ }
233
+
234
+ #define asan_unpoisoning_memory_region(ptr, len) \
235
+ for (void *poisoned = asan_unpoison_memory_region_temporary(ptr, len), \
236
+ *unpoisoning = &poisoned; /* flag to loop just once */ \
237
+ unpoisoning; \
238
+ unpoisoning = asan_poison_memory_region_restore(ptr, len, poisoned))
239
+
240
+ /**
241
+ * Checks if the given pointer is on an ASAN fake stack. If so, it returns the
242
+ * address this variable has on the real frame; if not, it returns the origin
243
+ * address unmodified.
244
+ *
245
+ * n.b. - _dereferencing_ the returned address is meaningless and should not
246
+ * be done; even though ASAN reserves space for the variable in both the real and
247
+ * fake stacks, the _value_ of that variable is only in the fake stack.
248
+ *
249
+ * n.b. - this only works for addresses passed in from local variables on the same
250
+ * thread, because the ASAN fake stacks are threadlocal.
251
+ *
252
+ * @param[in] slot the address of some local variable
253
+ * @retval a pointer to something from that frame on the _real_ machine stack
254
+ */
255
+ static inline void *
256
+ asan_get_real_stack_addr(void* slot)
257
+ {
258
+ VALUE *addr;
259
+ addr = __asan_addr_is_in_fake_stack(__asan_get_current_fake_stack(), slot, NULL, NULL);
260
+ return addr ? addr : slot;
261
+ }
262
+
263
+ /**
264
+ * Gets the current thread's fake stack handle, which can be passed into get_fake_stack_extents
265
+ *
266
+ * @retval An opaque value which can be passed to asan_get_fake_stack_extents
267
+ */
268
+ static inline void *
269
+ asan_get_thread_fake_stack_handle(void)
270
+ {
271
+ return __asan_get_current_fake_stack();
272
+ }
273
+
274
+ /**
275
+ * Checks if the given VALUE _actually_ represents a pointer to an ASAN fake stack.
276
+ *
277
+ * If the given slot _is_ actually a reference to an ASAN fake stack, and that fake stack
278
+ * contains the real values for the passed-in range of machine stack addresses, returns true
279
+ * and the range of the fake stack through the outparams.
280
+ *
281
+ * Otherwise, returns false, and sets the outparams to NULL.
282
+ *
283
+ * Note that this function expects "start" to be > "end" on downward-growing stack architectures;
284
+ *
285
+ * @param[in] thread_fake_stack_handle The asan fake stack reference for the thread we're scanning
286
+ * @param[in] slot The value on the machine stack we want to inspect
287
+ * @param[in] machine_stack_start The extents of the real machine stack on which slot lives
288
+ * @param[in] machine_stack_end The extents of the real machine stack on which slot lives
289
+ * @param[out] fake_stack_start_out The extents of the fake stack which contains real VALUEs
290
+ * @param[out] fake_stack_end_out The extents of the fake stack which contains real VALUEs
291
+ * @return Whether slot is a pointer to a fake stack for the given machine stack range
292
+ */
293
+
294
+ static inline bool
295
+ asan_get_fake_stack_extents(void *thread_fake_stack_handle, VALUE slot,
296
+ void *machine_stack_start, void *machine_stack_end,
297
+ void **fake_stack_start_out, void **fake_stack_end_out)
298
+ {
299
+ /* the ifdef is needed here to suppress a warning about fake_frame_{start/end} being
300
+ uninitialized if __asan_addr_is_in_fake_stack is an empty macro */
301
+ #ifdef RUBY_ASAN_ENABLED
302
+ void *fake_frame_start;
303
+ void *fake_frame_end;
304
+ void *real_stack_frame = __asan_addr_is_in_fake_stack(
305
+ thread_fake_stack_handle, (void *)slot, &fake_frame_start, &fake_frame_end
306
+ );
307
+ if (real_stack_frame) {
308
+ bool in_range;
309
+ #if STACK_GROW_DIRECTION < 0
310
+ in_range = machine_stack_start >= real_stack_frame && real_stack_frame >= machine_stack_end;
311
+ #else
312
+ in_range = machine_stack_start <= real_stack_frame && real_stack_frame <= machine_stack_end;
313
+ #endif
314
+ if (in_range) {
315
+ *fake_stack_start_out = fake_frame_start;
316
+ *fake_stack_end_out = fake_frame_end;
317
+ return true;
318
+ }
319
+ }
320
+ #endif
321
+ *fake_stack_start_out = 0;
322
+ *fake_stack_end_out = 0;
323
+ return false;
324
+ }
325
+
326
+
327
+ #endif /* INTERNAL_SANITIZERS_H */
@@ -0,0 +1,25 @@
1
+ /*
2
+ * Vendored from Ruby v3_4_8 (tag: v3_4_8)
3
+ * Source: https://github.com/ruby/ruby/blob/v3_4_8/internal/static_assert.h
4
+ *
5
+ * Reason: Ruby 3.4's modular GC was designed for in-tree builds only.
6
+ * See ext/gc-3.4/internal/bits.h for full explanation.
7
+ *
8
+ * License: Ruby's License (BSD-2-Clause) - see https://www.ruby-lang.org/en/about/license.txt
9
+ */
10
+ #ifndef INTERNAL_STATIC_ASSERT_H /*-*-C-*-vi:se ft=c:*/
11
+ #define INTERNAL_STATIC_ASSERT_H
12
+ /**
13
+ * @author Ruby developers <ruby-core@ruby-lang.org>
14
+ * @copyright This file is a part of the programming language Ruby.
15
+ * Permission is hereby granted, to either redistribute and/or
16
+ * modify this file, provided that the conditions mentioned in the
17
+ * file COPYING are met. Consult the file for details.
18
+ * @brief C11 shim for _Static_assert.
19
+ */
20
+ #include "ruby/internal/static_assert.h"
21
+ #ifndef STATIC_ASSERT
22
+ # define STATIC_ASSERT RBIMPL_STATIC_ASSERT
23
+ #endif
24
+
25
+ #endif /* INTERNAL_STATIC_ASSERT_H */
@@ -0,0 +1,25 @@
1
+ /*
2
+ * Vendored from Ruby v3_4_8 (tag: v3_4_8)
3
+ * Source: https://github.com/ruby/ruby/blob/v3_4_8/internal/warnings.h
4
+ *
5
+ * Reason: Ruby 3.4's modular GC was designed for in-tree builds only.
6
+ * See ext/gc-3.4/internal/bits.h for full explanation.
7
+ *
8
+ * License: Ruby's License (BSD-2-Clause) - see https://www.ruby-lang.org/en/about/license.txt
9
+ */
10
+ #ifndef INTERNAL_WARNINGS_H /*-*-C-*-vi:se ft=c:*/
11
+ #define INTERNAL_WARNINGS_H
12
+ /**
13
+ * @author Ruby developers <ruby-core@ruby-lang.org>
14
+ * @copyright This file is a part of the programming language Ruby.
15
+ * Permission is hereby granted, to either redistribute and/or
16
+ * modify this file, provided that the conditions mentioned in the
17
+ * file COPYING are met. Consult the file for details.
18
+ * @brief Internal header to suppress / mandate warnings.
19
+ */
20
+ #include "ruby/internal/warning_push.h"
21
+ #define COMPILER_WARNING_PUSH RBIMPL_WARNING_PUSH()
22
+ #define COMPILER_WARNING_POP RBIMPL_WARNING_POP()
23
+ #define COMPILER_WARNING_ERROR(flag) RBIMPL_WARNING_ERROR(flag)
24
+ #define COMPILER_WARNING_IGNORED(flag) RBIMPL_WARNING_IGNORED(flag)
25
+ #endif /* INTERNAL_WARNINGS_H */