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.
- checksums.yaml +4 -4
- data/.rubocop.yml +7 -6
- data/README.md +69 -2
- data/Rakefile +15 -3
- data/exe/thread_safety +1 -0
- data/ext/extconf.rb +18 -3
- data/ext/gc-3.4/darray.h +220 -0
- data/ext/gc-3.4/debug_counter.h +442 -0
- data/ext/{gc → gc-3.4/gc}/default/default.c +276 -278
- data/ext/{gc → gc-3.4/gc}/gc.h +4 -5
- data/ext/{gc → gc-3.4/gc}/gc_impl.h +3 -11
- data/ext/gc-3.4/internal/bits.h +667 -0
- data/ext/gc-3.4/internal/compilers.h +116 -0
- data/ext/gc-3.4/internal/hash.h +201 -0
- data/ext/gc-3.4/internal/sanitizers.h +327 -0
- data/ext/gc-3.4/internal/static_assert.h +25 -0
- data/ext/gc-3.4/internal/warnings.h +25 -0
- data/ext/gc-3.4/patches/0001-allow-rvalue-overhead-override.patch +18 -0
- data/ext/gc-4.0/gc/default/default.c +9629 -0
- data/ext/gc-4.0/gc/gc.h +262 -0
- data/ext/gc-4.0/gc/gc_impl.h +124 -0
- data/ext/thread_safety.c +127 -28
- data/lib/thread_safety/offense.rb +10 -18
- data/lib/thread_safety/patches.rb +12 -0
- data/lib/thread_safety/version.rb +1 -1
- data/lib/thread_safety.rb +8 -8
- metadata +78 -8
- /data/ext/{darray.h → gc-4.0/darray.h} +0 -0
|
@@ -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 */
|