Ruby  3.4.0dev (2024-11-05 revision 348a53415339076afc4a02fcd09f3ae36e9c4c61)
load.c (348a53415339076afc4a02fcd09f3ae36e9c4c61)
1 /*
2  * load methods from eval.c
3  */
4 
5 #include "dln.h"
6 #include "eval_intern.h"
7 #include "internal.h"
8 #include "internal/dir.h"
9 #include "internal/error.h"
10 #include "internal/file.h"
11 #include "internal/hash.h"
12 #include "internal/load.h"
13 #include "internal/ruby_parser.h"
14 #include "internal/thread.h"
15 #include "internal/variable.h"
16 #include "iseq.h"
17 #include "probes.h"
18 #include "darray.h"
19 #include "ruby/encoding.h"
20 #include "ruby/util.h"
21 
22 static VALUE ruby_dln_libmap;
23 
24 #define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
25 #define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
26 #define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
27 
28 #if SIZEOF_VALUE <= SIZEOF_LONG
29 # define SVALUE2NUM(x) LONG2NUM((long)(x))
30 # define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LONG(x)
31 #elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
32 # define SVALUE2NUM(x) LL2NUM((LONG_LONG)(x))
33 # define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LL(x)
34 #else
35 # error Need integer for VALUE
36 #endif
37 
38 enum {
39  loadable_ext_rb = (0+ /* .rb extension is the first in both tables */
40  1) /* offset by rb_find_file_ext() */
41 };
42 
43 static const char *const loadable_ext[] = {
44  ".rb", DLEXT,
45  0
46 };
47 
48 static const char *const ruby_ext[] = {
49  ".rb",
50  0
51 };
52 
53 enum expand_type {
54  EXPAND_ALL,
55  EXPAND_RELATIVE,
56  EXPAND_HOME,
57  EXPAND_NON_CACHE
58 };
59 
60 /* Construct expanded load path and store it to cache.
61  We rebuild load path partially if the cache is invalid.
62  We don't cache non string object and expand it every time. We ensure that
63  string objects in $LOAD_PATH are frozen.
64  */
65 static void
66 rb_construct_expanded_load_path(rb_vm_t *vm, enum expand_type type, int *has_relative, int *has_non_cache)
67 {
68  VALUE load_path = vm->load_path;
69  VALUE expanded_load_path = vm->expanded_load_path;
70  VALUE ary;
71  long i;
72 
73  ary = rb_ary_hidden_new(RARRAY_LEN(load_path));
74  for (i = 0; i < RARRAY_LEN(load_path); ++i) {
75  VALUE path, as_str, expanded_path;
76  int is_string, non_cache;
77  char *as_cstr;
78  as_str = path = RARRAY_AREF(load_path, i);
79  is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0;
80  non_cache = !is_string ? 1 : 0;
81  as_str = rb_get_path_check_to_string(path);
82  as_cstr = RSTRING_PTR(as_str);
83 
84  if (!non_cache) {
85  if ((type == EXPAND_RELATIVE &&
86  rb_is_absolute_path(as_cstr)) ||
87  (type == EXPAND_HOME &&
88  (!as_cstr[0] || as_cstr[0] != '~')) ||
89  (type == EXPAND_NON_CACHE)) {
90  /* Use cached expanded path. */
91  rb_ary_push(ary, RARRAY_AREF(expanded_load_path, i));
92  continue;
93  }
94  }
95  if (!*has_relative && !rb_is_absolute_path(as_cstr))
96  *has_relative = 1;
97  if (!*has_non_cache && non_cache)
98  *has_non_cache = 1;
99  /* Freeze only string object. We expand other objects every time. */
100  if (is_string)
101  rb_str_freeze(path);
102  as_str = rb_get_path_check_convert(as_str);
103  expanded_path = rb_check_realpath(Qnil, as_str, NULL);
104  if (NIL_P(expanded_path)) expanded_path = as_str;
105  rb_ary_push(ary, rb_fstring(expanded_path));
106  }
107  rb_ary_freeze(ary);
108  vm->expanded_load_path = ary;
109  rb_ary_replace(vm->load_path_snapshot, vm->load_path);
110 }
111 
112 static VALUE
113 get_expanded_load_path(rb_vm_t *vm)
114 {
115  const VALUE non_cache = Qtrue;
116 
117  if (!rb_ary_shared_with_p(vm->load_path_snapshot, vm->load_path)) {
118  /* The load path was modified. Rebuild the expanded load path. */
119  int has_relative = 0, has_non_cache = 0;
120  rb_construct_expanded_load_path(vm, EXPAND_ALL, &has_relative, &has_non_cache);
121  if (has_relative) {
122  vm->load_path_check_cache = rb_dir_getwd_ospath();
123  }
124  else if (has_non_cache) {
125  /* Non string object. */
126  vm->load_path_check_cache = non_cache;
127  }
128  else {
129  vm->load_path_check_cache = 0;
130  }
131  }
132  else if (vm->load_path_check_cache == non_cache) {
133  int has_relative = 1, has_non_cache = 1;
134  /* Expand only non-cacheable objects. */
135  rb_construct_expanded_load_path(vm, EXPAND_NON_CACHE,
136  &has_relative, &has_non_cache);
137  }
138  else if (vm->load_path_check_cache) {
139  int has_relative = 1, has_non_cache = 1;
140  VALUE cwd = rb_dir_getwd_ospath();
141  if (!rb_str_equal(vm->load_path_check_cache, cwd)) {
142  /* Current working directory or filesystem encoding was changed.
143  Expand relative load path and non-cacheable objects again. */
144  vm->load_path_check_cache = cwd;
145  rb_construct_expanded_load_path(vm, EXPAND_RELATIVE,
146  &has_relative, &has_non_cache);
147  }
148  else {
149  /* Expand only tilde (User HOME) and non-cacheable objects. */
150  rb_construct_expanded_load_path(vm, EXPAND_HOME,
151  &has_relative, &has_non_cache);
152  }
153  }
154  return vm->expanded_load_path;
155 }
156 
157 VALUE
158 rb_get_expanded_load_path(void)
159 {
160  return get_expanded_load_path(GET_VM());
161 }
162 
163 static VALUE
164 load_path_getter(ID id, VALUE * p)
165 {
166  rb_vm_t *vm = (void *)p;
167  return vm->load_path;
168 }
169 
170 static VALUE
171 get_loaded_features(rb_vm_t *vm)
172 {
173  return vm->loaded_features;
174 }
175 
176 static VALUE
177 get_loaded_features_realpaths(rb_vm_t *vm)
178 {
179  return vm->loaded_features_realpaths;
180 }
181 
182 static VALUE
183 get_loaded_features_realpath_map(rb_vm_t *vm)
184 {
185  return vm->loaded_features_realpath_map;
186 }
187 
188 static VALUE
189 get_LOADED_FEATURES(ID _x, VALUE *_y)
190 {
191  return get_loaded_features(GET_VM());
192 }
193 
194 static void
195 reset_loaded_features_snapshot(rb_vm_t *vm)
196 {
197  rb_ary_replace(vm->loaded_features_snapshot, vm->loaded_features);
198 }
199 
200 static struct st_table *
201 get_loaded_features_index_raw(rb_vm_t *vm)
202 {
203  return vm->loaded_features_index;
204 }
205 
206 static st_table *
207 get_loading_table(rb_vm_t *vm)
208 {
209  return vm->loading_table;
210 }
211 
212 static st_data_t
213 feature_key(const char *str, size_t len)
214 {
215  return st_hash(str, len, 0xfea7009e);
216 }
217 
218 static bool
219 is_rbext_path(VALUE feature_path)
220 {
221  long len = RSTRING_LEN(feature_path);
222  long rbext_len = rb_strlen_lit(".rb");
223  if (len <= rbext_len) return false;
224  return IS_RBEXT(RSTRING_PTR(feature_path) + len - rbext_len);
225 }
226 
227 typedef rb_darray(long) feature_indexes_t;
228 
229 struct features_index_add_single_args {
230  rb_vm_t *vm;
231  VALUE offset;
232  bool rb;
233 };
234 
235 static int
236 features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t raw_args, int existing)
237 {
238  struct features_index_add_single_args *args = (struct features_index_add_single_args *)raw_args;
239  rb_vm_t *vm = args->vm;
240  VALUE offset = args->offset;
241  bool rb = args->rb;
242 
243  if (existing) {
244  VALUE this_feature_index = *value;
245 
246  if (FIXNUM_P(this_feature_index)) {
247  VALUE loaded_features = get_loaded_features(vm);
248  VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(this_feature_index));
249 
250  feature_indexes_t feature_indexes;
251  rb_darray_make(&feature_indexes, 2);
252  int top = (rb && !is_rbext_path(this_feature_path)) ? 1 : 0;
253  rb_darray_set(feature_indexes, top^0, FIX2LONG(this_feature_index));
254  rb_darray_set(feature_indexes, top^1, FIX2LONG(offset));
255 
256  RUBY_ASSERT(rb_darray_size(feature_indexes) == 2);
257  // assert feature_indexes does not look like a special const
258  RUBY_ASSERT(!SPECIAL_CONST_P((VALUE)feature_indexes));
259 
260  *value = (st_data_t)feature_indexes;
261  }
262  else {
263  feature_indexes_t feature_indexes = (feature_indexes_t)this_feature_index;
264  long pos = -1;
265 
266  if (rb) {
267  VALUE loaded_features = get_loaded_features(vm);
268  for (size_t i = 0; i < rb_darray_size(feature_indexes); ++i) {
269  long idx = rb_darray_get(feature_indexes, i);
270  VALUE this_feature_path = RARRAY_AREF(loaded_features, idx);
271  Check_Type(this_feature_path, T_STRING);
272  if (!is_rbext_path(this_feature_path)) {
273  pos = i;
274  break;
275  }
276  }
277  }
278 
279  rb_darray_append(&feature_indexes, FIX2LONG(offset));
280  /* darray may realloc which will change the pointer */
281  *value = (st_data_t)feature_indexes;
282 
283  if (pos >= 0) {
284  long *ptr = rb_darray_data_ptr(feature_indexes);
285  long len = rb_darray_size(feature_indexes);
286  MEMMOVE(ptr + pos, ptr + pos + 1, long, len - pos - 1);
287  ptr[pos] = FIX2LONG(offset);
288  }
289  }
290  }
291  else {
292  *value = offset;
293  }
294 
295  return ST_CONTINUE;
296 }
297 
298 static void
299 features_index_add_single(rb_vm_t *vm, const char* str, size_t len, VALUE offset, bool rb)
300 {
301  struct st_table *features_index;
302  st_data_t short_feature_key;
303 
304  Check_Type(offset, T_FIXNUM);
305  short_feature_key = feature_key(str, len);
306 
307  features_index = get_loaded_features_index_raw(vm);
308 
309  struct features_index_add_single_args args = {
310  .vm = vm,
311  .offset = offset,
312  .rb = rb,
313  };
314 
315  st_update(features_index, short_feature_key, features_index_add_single_callback, (st_data_t)&args);
316 }
317 
318 /* Add to the loaded-features index all the required entries for
319  `feature`, located at `offset` in $LOADED_FEATURES. We add an
320  index entry at each string `short_feature` for which
321  feature == "#{prefix}#{short_feature}#{ext}"
322  where `ext` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
323  or ends in '/'. This maintains the invariant that `rb_feature_p()`
324  relies on for its fast lookup.
325 */
326 static void
327 features_index_add(rb_vm_t *vm, VALUE feature, VALUE offset)
328 {
329  const char *feature_str, *feature_end, *ext, *p;
330  bool rb = false;
331 
332  feature_str = StringValuePtr(feature);
333  feature_end = feature_str + RSTRING_LEN(feature);
334 
335  for (ext = feature_end; ext > feature_str; ext--)
336  if (*ext == '.' || *ext == '/')
337  break;
338  if (*ext != '.')
339  ext = NULL;
340  else
341  rb = IS_RBEXT(ext);
342  /* Now `ext` points to the only string matching %r{^\.[^./]*$} that is
343  at the end of `feature`, or is NULL if there is no such string. */
344 
345  p = ext ? ext : feature_end;
346  while (1) {
347  p--;
348  while (p >= feature_str && *p != '/')
349  p--;
350  if (p < feature_str)
351  break;
352  /* Now *p == '/'. We reach this point for every '/' in `feature`. */
353  features_index_add_single(vm, p + 1, feature_end - p - 1, offset, false);
354  if (ext) {
355  features_index_add_single(vm, p + 1, ext - p - 1, offset, rb);
356  }
357  }
358  features_index_add_single(vm, feature_str, feature_end - feature_str, offset, false);
359  if (ext) {
360  features_index_add_single(vm, feature_str, ext - feature_str, offset, rb);
361  }
362 }
363 
364 static int
365 loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
366 {
367  VALUE obj = (VALUE)val;
368  if (!SPECIAL_CONST_P(obj)) {
369  rb_darray_free((void *)obj);
370  }
371  return ST_DELETE;
372 }
373 
374 void
375 rb_free_loaded_features_index(rb_vm_t *vm)
376 {
377  st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
378  st_free_table(vm->loaded_features_index);
379 }
380 
381 static st_table *
382 get_loaded_features_index(rb_vm_t *vm)
383 {
384  VALUE features;
385  int i;
386 
387  if (!rb_ary_shared_with_p(vm->loaded_features_snapshot, vm->loaded_features)) {
388  /* The sharing was broken; something (other than us in rb_provide_feature())
389  modified loaded_features. Rebuild the index. */
390  st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
391 
392  VALUE realpaths = vm->loaded_features_realpaths;
393  VALUE realpath_map = vm->loaded_features_realpath_map;
394  VALUE previous_realpath_map = rb_hash_dup(realpath_map);
395  rb_hash_clear(realpaths);
396  rb_hash_clear(realpath_map);
397  features = vm->loaded_features;
398  for (i = 0; i < RARRAY_LEN(features); i++) {
399  VALUE entry, as_str;
400  as_str = entry = rb_ary_entry(features, i);
401  StringValue(as_str);
402  as_str = rb_fstring(as_str);
403  if (as_str != entry)
404  rb_ary_store(features, i, as_str);
405  features_index_add(vm, as_str, INT2FIX(i));
406  }
407  reset_loaded_features_snapshot(vm);
408 
409  features = rb_ary_dup(vm->loaded_features_snapshot);
410  long j = RARRAY_LEN(features);
411  for (i = 0; i < j; i++) {
412  VALUE as_str = rb_ary_entry(features, i);
413  VALUE realpath = rb_hash_aref(previous_realpath_map, as_str);
414  if (NIL_P(realpath)) {
415  realpath = rb_check_realpath(Qnil, as_str, NULL);
416  if (NIL_P(realpath)) realpath = as_str;
417  realpath = rb_fstring(realpath);
418  }
419  rb_hash_aset(realpaths, realpath, Qtrue);
420  rb_hash_aset(realpath_map, as_str, realpath);
421  }
422  }
423  return vm->loaded_features_index;
424 }
425 
426 /* This searches `load_path` for a value such that
427  name == "#{load_path[i]}/#{feature}"
428  if `feature` is a suffix of `name`, or otherwise
429  name == "#{load_path[i]}/#{feature}#{ext}"
430  for an acceptable string `ext`. It returns
431  `load_path[i].to_str` if found, else 0.
432 
433  If type is 's', then `ext` is acceptable only if IS_DLEXT(ext);
434  if 'r', then only if IS_RBEXT(ext); otherwise `ext` may be absent
435  or have any value matching `%r{^\.[^./]*$}`.
436 */
437 static VALUE
438 loaded_feature_path(const char *name, long vlen, const char *feature, long len,
439  int type, VALUE load_path)
440 {
441  long i;
442  long plen;
443  const char *e;
444 
445  if (vlen < len+1) return 0;
446  if (strchr(feature, '.') && !strncmp(name+(vlen-len), feature, len)) {
447  plen = vlen - len;
448  }
449  else {
450  for (e = name + vlen; name != e && *e != '.' && *e != '/'; --e);
451  if (*e != '.' ||
452  e-name < len ||
453  strncmp(e-len, feature, len))
454  return 0;
455  plen = e - name - len;
456  }
457  if (plen > 0 && name[plen-1] != '/') {
458  return 0;
459  }
460  if (type == 's' ? !IS_DLEXT(&name[plen+len]) :
461  type == 'r' ? !IS_RBEXT(&name[plen+len]) :
462  0) {
463  return 0;
464  }
465  /* Now name == "#{prefix}/#{feature}#{ext}" where ext is acceptable
466  (possibly empty) and prefix is some string of length plen. */
467 
468  if (plen > 0) --plen; /* exclude '.' */
469  for (i = 0; i < RARRAY_LEN(load_path); ++i) {
470  VALUE p = RARRAY_AREF(load_path, i);
471  const char *s = StringValuePtr(p);
472  long n = RSTRING_LEN(p);
473 
474  if (n != plen) continue;
475  if (n && strncmp(name, s, n)) continue;
476  return p;
477  }
478  return 0;
479 }
480 
482  const char *name;
483  long len;
484  int type;
485  VALUE load_path;
486  const char *result;
487 };
488 
489 static int
490 loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
491 {
492  const char *s = (const char *)v;
493  struct loaded_feature_searching *fp = (struct loaded_feature_searching *)f;
494  VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len,
495  fp->type, fp->load_path);
496  if (!p) return ST_CONTINUE;
497  fp->result = s;
498  return ST_STOP;
499 }
500 
501 /*
502  * Returns the type of already provided feature.
503  * 'r': ruby script (".rb")
504  * 's': shared object (".so"/"."DLEXT)
505  * 'u': unsuffixed
506  */
507 static int
508 rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
509 {
510  VALUE features, this_feature_index = Qnil, v, p, load_path = 0;
511  const char *f, *e;
512  long i, len, elen, n;
513  st_table *loading_tbl, *features_index;
514  st_data_t data;
515  st_data_t key;
516  int type;
517 
518  if (fn) *fn = 0;
519  if (ext) {
520  elen = strlen(ext);
521  len = strlen(feature) - elen;
522  type = rb ? 'r' : 's';
523  }
524  else {
525  len = strlen(feature);
526  elen = 0;
527  type = 0;
528  }
529  features = get_loaded_features(vm);
530  features_index = get_loaded_features_index(vm);
531 
532  key = feature_key(feature, strlen(feature));
533  /* We search `features` for an entry such that either
534  "#{features[i]}" == "#{load_path[j]}/#{feature}#{e}"
535  for some j, or
536  "#{features[i]}" == "#{feature}#{e}"
537  Here `e` is an "allowed" extension -- either empty or one
538  of the extensions accepted by IS_RBEXT, IS_SOEXT, or
539  IS_DLEXT. Further, if `ext && rb` then `IS_RBEXT(e)`,
540  and if `ext && !rb` then `IS_SOEXT(e) || IS_DLEXT(e)`.
541 
542  If `expanded`, then only the latter form (without load_path[j])
543  is accepted. Otherwise either form is accepted, *unless* `ext`
544  is false and an otherwise-matching entry of the first form is
545  preceded by an entry of the form
546  "#{features[i2]}" == "#{load_path[j2]}/#{feature}#{e2}"
547  where `e2` matches %r{^\.[^./]*$} but is not an allowed extension.
548  After a "distractor" entry of this form, only entries of the
549  form "#{feature}#{e}" are accepted.
550 
551  In `rb_provide_feature()` and `get_loaded_features_index()` we
552  maintain an invariant that the array `this_feature_index` will
553  point to every entry in `features` which has the form
554  "#{prefix}#{feature}#{e}"
555  where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
556  or ends in '/'. This includes both match forms above, as well
557  as any distractors, so we may ignore all other entries in `features`.
558  */
559  if (st_lookup(features_index, key, &data) && !NIL_P(this_feature_index = (VALUE)data)) {
560  for (size_t i = 0; ; i++) {
561  long index;
562  if (FIXNUM_P(this_feature_index)) {
563  if (i > 0) break;
564  index = FIX2LONG(this_feature_index);
565  }
566  else {
567  feature_indexes_t feature_indexes = (feature_indexes_t)this_feature_index;
568  if (i >= rb_darray_size(feature_indexes)) break;
569  index = rb_darray_get(feature_indexes, i);
570  }
571 
572  v = RARRAY_AREF(features, index);
573  f = StringValuePtr(v);
574  if ((n = RSTRING_LEN(v)) < len) continue;
575  if (strncmp(f, feature, len) != 0) {
576  if (expanded) continue;
577  if (!load_path) load_path = get_expanded_load_path(vm);
578  if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
579  continue;
580  expanded = 1;
581  f += RSTRING_LEN(p) + 1;
582  }
583  if (!*(e = f + len)) {
584  if (ext) continue;
585  return 'u';
586  }
587  if (*e != '.') continue;
588  if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
589  return 's';
590  }
591  if ((rb || !ext) && (IS_RBEXT(e))) {
592  return 'r';
593  }
594  }
595  }
596 
597  loading_tbl = get_loading_table(vm);
598  f = 0;
599  if (!expanded) {
600  struct loaded_feature_searching fs;
601  fs.name = feature;
602  fs.len = len;
603  fs.type = type;
604  fs.load_path = load_path ? load_path : get_expanded_load_path(vm);
605  fs.result = 0;
606  st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
607  if ((f = fs.result) != 0) {
608  if (fn) *fn = f;
609  goto loading;
610  }
611  }
612  if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
613  if (fn) *fn = (const char*)data;
614  goto loading;
615  }
616  else {
617  VALUE bufstr;
618  char *buf;
619  static const char so_ext[][4] = {
620  ".so", ".o",
621  };
622 
623  if (ext && *ext) return 0;
624  bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN);
625  buf = RSTRING_PTR(bufstr);
626  MEMCPY(buf, feature, char, len);
627  for (i = 0; (e = loadable_ext[i]) != 0; i++) {
628  strlcpy(buf + len, e, DLEXT_MAXLEN + 1);
629  if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
630  rb_str_resize(bufstr, 0);
631  if (fn) *fn = (const char*)data;
632  return i ? 's' : 'r';
633  }
634  }
635  for (i = 0; i < numberof(so_ext); i++) {
636  strlcpy(buf + len, so_ext[i], DLEXT_MAXLEN + 1);
637  if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
638  rb_str_resize(bufstr, 0);
639  if (fn) *fn = (const char*)data;
640  return 's';
641  }
642  }
643  rb_str_resize(bufstr, 0);
644  }
645  return 0;
646 
647  loading:
648  if (!ext) return 'u';
649  return !IS_RBEXT(ext) ? 's' : 'r';
650 }
651 
652 int
653 rb_provided(const char *feature)
654 {
655  return rb_feature_provided(feature, 0);
656 }
657 
658 static int
659 feature_provided(rb_vm_t *vm, const char *feature, const char **loading)
660 {
661  const char *ext = strrchr(feature, '.');
662  VALUE fullpath = 0;
663 
664  if (*feature == '.' &&
665  (feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) {
666  fullpath = rb_file_expand_path_fast(rb_get_path(rb_str_new2(feature)), Qnil);
667  feature = RSTRING_PTR(fullpath);
668  }
669  if (ext && !strchr(ext, '/')) {
670  if (IS_RBEXT(ext)) {
671  if (rb_feature_p(vm, feature, ext, TRUE, FALSE, loading)) return TRUE;
672  return FALSE;
673  }
674  else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
675  if (rb_feature_p(vm, feature, ext, FALSE, FALSE, loading)) return TRUE;
676  return FALSE;
677  }
678  }
679  if (rb_feature_p(vm, feature, 0, TRUE, FALSE, loading))
680  return TRUE;
681  RB_GC_GUARD(fullpath);
682  return FALSE;
683 }
684 
685 int
686 rb_feature_provided(const char *feature, const char **loading)
687 {
688  return feature_provided(GET_VM(), feature, loading);
689 }
690 
691 static void
692 rb_provide_feature(rb_vm_t *vm, VALUE feature)
693 {
694  VALUE features;
695 
696  features = get_loaded_features(vm);
697  if (OBJ_FROZEN(features)) {
699  "$LOADED_FEATURES is frozen; cannot append feature");
700  }
701  feature = rb_fstring(feature);
702 
703  get_loaded_features_index(vm);
704  // If loaded_features and loaded_features_snapshot share the same backing
705  // array, pushing into it would cause the whole array to be copied.
706  // To avoid this we first clear loaded_features_snapshot.
707  rb_ary_clear(vm->loaded_features_snapshot);
708  rb_ary_push(features, feature);
709  features_index_add(vm, feature, INT2FIX(RARRAY_LEN(features)-1));
710  reset_loaded_features_snapshot(vm);
711 }
712 
713 void
714 rb_provide(const char *feature)
715 {
716  rb_provide_feature(GET_VM(), rb_fstring_cstr(feature));
717 }
718 
719 NORETURN(static void load_failed(VALUE));
720 
721 static inline VALUE
722 realpath_internal_cached(VALUE hash, VALUE path)
723 {
724  VALUE ret = rb_hash_aref(hash, path);
725  if(RTEST(ret)) {
726  return ret;
727  }
728 
729  VALUE realpath = rb_realpath_internal(Qnil, path, 1);
730  rb_hash_aset(hash, rb_fstring(path), rb_fstring(realpath));
731  return realpath;
732 }
733 
734 static inline void
735 load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
736 {
737  const rb_iseq_t *iseq = rb_iseq_load_iseq(fname);
738 
739  if (!iseq) {
740  rb_execution_context_t *ec = GET_EC();
741  VALUE v = rb_vm_push_frame_fname(ec, fname);
742 
743  rb_thread_t *th = rb_ec_thread_ptr(ec);
744  VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
745 
746  if (rb_ruby_prism_p()) {
747  pm_parse_result_t result = { 0 };
748  result.options.line = 1;
749  result.node.coverage_enabled = 1;
750 
751  VALUE error = pm_load_parse_file(&result, fname, NULL);
752 
753  if (error == Qnil) {
754  iseq = pm_iseq_new_top(&result.node, rb_fstring_lit("<top (required)>"), fname, realpath_internal_cached(realpath_map, fname), NULL);
755  pm_parse_result_free(&result);
756  }
757  else {
758  rb_vm_pop_frame(ec);
759  RB_GC_GUARD(v);
760  pm_parse_result_free(&result);
761  rb_exc_raise(error);
762  }
763  }
764  else {
765  rb_ast_t *ast;
766  VALUE ast_value;
767  VALUE parser = rb_parser_new();
768  rb_parser_set_context(parser, NULL, FALSE);
769  ast_value = rb_parser_load_file(parser, fname);
770  ast = rb_ruby_ast_data_get(ast_value);
771 
772  iseq = rb_iseq_new_top(ast_value, rb_fstring_lit("<top (required)>"),
773  fname, realpath_internal_cached(realpath_map, fname), NULL);
774  rb_ast_dispose(ast);
775  }
776 
777  rb_vm_pop_frame(ec);
778  RB_GC_GUARD(v);
779  }
780  rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
781  rb_iseq_eval(iseq);
782 }
783 
784 static inline enum ruby_tag_type
785 load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
786 {
787  enum ruby_tag_type state;
788  rb_thread_t *th = rb_ec_thread_ptr(ec);
789  volatile VALUE wrapper = th->top_wrapper;
790  volatile VALUE self = th->top_self;
791 #if !defined __GNUC__
792  rb_thread_t *volatile th0 = th;
793 #endif
794 
795  ec->errinfo = Qnil; /* ensure */
796 
797  /* load in module as toplevel */
798  th->top_self = rb_obj_clone(rb_vm_top_self());
799  th->top_wrapper = load_wrapper;
800  rb_extend_object(th->top_self, th->top_wrapper);
801 
802  EC_PUSH_TAG(ec);
803  state = EC_EXEC_TAG();
804  if (state == TAG_NONE) {
805  load_iseq_eval(ec, fname);
806  }
807  EC_POP_TAG();
808 
809 #if !defined __GNUC__
810  th = th0;
811  fname = RB_GC_GUARD(fname);
812 #endif
813  th->top_self = self;
814  th->top_wrapper = wrapper;
815  return state;
816 }
817 
818 static inline void
819 raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state)
820 {
821  if (state) {
822  rb_vm_jump_tag_but_local_jump(state);
823  }
824 
825  if (!NIL_P(ec->errinfo)) {
826  rb_exc_raise(ec->errinfo);
827  }
828 }
829 
830 static void
831 rb_load_internal(VALUE fname, VALUE wrap)
832 {
833  rb_execution_context_t *ec = GET_EC();
834  enum ruby_tag_type state = TAG_NONE;
835  if (RTEST(wrap)) {
836  if (!RB_TYPE_P(wrap, T_MODULE)) {
837  wrap = rb_module_new();
838  }
839  state = load_wrapping(ec, fname, wrap);
840  }
841  else {
842  load_iseq_eval(ec, fname);
843  }
844  raise_load_if_failed(ec, state);
845 }
846 
847 void
848 rb_load(VALUE fname, int wrap)
849 {
850  VALUE tmp = rb_find_file(FilePathValue(fname));
851  if (!tmp) load_failed(fname);
852  rb_load_internal(tmp, RBOOL(wrap));
853 }
854 
855 void
856 rb_load_protect(VALUE fname, int wrap, int *pstate)
857 {
858  enum ruby_tag_type state;
859 
860  EC_PUSH_TAG(GET_EC());
861  if ((state = EC_EXEC_TAG()) == TAG_NONE) {
862  rb_load(fname, wrap);
863  }
864  EC_POP_TAG();
865 
866  if (state != TAG_NONE) *pstate = state;
867 }
868 
869 /*
870  * call-seq:
871  * load(filename, wrap=false) -> true
872  *
873  * Loads and executes the Ruby program in the file _filename_.
874  *
875  * If the filename is an absolute path (e.g. starts with '/'), the file
876  * will be loaded directly using the absolute path.
877  *
878  * If the filename is an explicit relative path (e.g. starts with './' or
879  * '../'), the file will be loaded using the relative path from the current
880  * directory.
881  *
882  * Otherwise, the file will be searched for in the library
883  * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
884  * If the file is found in a directory, it will attempt to load the file
885  * relative to that directory. If the file is not found in any of the
886  * directories in <code>$LOAD_PATH</code>, the file will be loaded using
887  * the relative path from the current directory.
888  *
889  * If the file doesn't exist when there is an attempt to load it, a
890  * LoadError will be raised.
891  *
892  * If the optional _wrap_ parameter is +true+, the loaded script will
893  * be executed under an anonymous module. If the optional _wrap_ parameter
894  * is a module, the loaded script will be executed under the given module.
895  * In no circumstance will any local variables in the loaded file be
896  * propagated to the loading environment.
897  */
898 
899 static VALUE
900 rb_f_load(int argc, VALUE *argv, VALUE _)
901 {
902  VALUE fname, wrap, path, orig_fname;
903 
904  rb_scan_args(argc, argv, "11", &fname, &wrap);
905 
906  orig_fname = rb_get_path_check_to_string(fname);
907  fname = rb_str_encode_ospath(orig_fname);
908  RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
909 
910  path = rb_find_file(fname);
911  if (!path) {
912  if (!rb_file_load_ok(RSTRING_PTR(fname)))
913  load_failed(orig_fname);
914  path = fname;
915  }
916  rb_load_internal(path, wrap);
917 
918  RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
919 
920  return Qtrue;
921 }
922 
923 static char *
924 load_lock(rb_vm_t *vm, const char *ftptr, bool warn)
925 {
926  st_data_t data;
927  st_table *loading_tbl = get_loading_table(vm);
928 
929  if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
930  /* partial state */
931  ftptr = ruby_strdup(ftptr);
932  data = (st_data_t)rb_thread_shield_new();
933  st_insert(loading_tbl, (st_data_t)ftptr, data);
934  return (char *)ftptr;
935  }
936 
937  if (warn && rb_thread_shield_owned((VALUE)data)) {
938  VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
939  rb_backtrace_each(rb_str_append, warning);
940  rb_warning("%"PRIsVALUE, warning);
941  }
942  switch (rb_thread_shield_wait((VALUE)data)) {
943  case Qfalse:
944  case Qnil:
945  return 0;
946  }
947  return (char *)ftptr;
948 }
949 
950 static int
951 release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing)
952 {
953  VALUE thread_shield = (VALUE)*value;
954  if (!existing) return ST_STOP;
955  if (done) {
956  rb_thread_shield_destroy(thread_shield);
957  /* Delete the entry even if there are waiting threads, because they
958  * won't load the file and won't delete the entry. */
959  }
960  else if (rb_thread_shield_release(thread_shield)) {
961  /* still in-use */
962  return ST_CONTINUE;
963  }
964  xfree((char *)*key);
965  return ST_DELETE;
966 }
967 
968 static void
969 load_unlock(rb_vm_t *vm, const char *ftptr, int done)
970 {
971  if (ftptr) {
972  st_data_t key = (st_data_t)ftptr;
973  st_table *loading_tbl = get_loading_table(vm);
974 
975  st_update(loading_tbl, key, release_thread_shield, done);
976  }
977 }
978 
979 static VALUE rb_require_string_internal(VALUE fname, bool resurrect);
980 
981 /*
982  * call-seq:
983  * require(name) -> true or false
984  *
985  * Loads the given +name+, returning +true+ if successful and +false+ if the
986  * feature is already loaded.
987  *
988  * If the filename neither resolves to an absolute path nor starts with
989  * './' or '../', the file will be searched for in the library
990  * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
991  * If the filename starts with './' or '../', resolution is based on Dir.pwd.
992  *
993  * If the filename has the extension ".rb", it is loaded as a source file; if
994  * the extension is ".so", ".o", or the default shared library extension on
995  * the current platform, Ruby loads the shared library as a Ruby extension.
996  * Otherwise, Ruby tries adding ".rb", ".so", and so on to the name until
997  * found. If the file named cannot be found, a LoadError will be raised.
998  *
999  * For Ruby extensions the filename given may use ".so" or ".o". For example,
1000  * on macOS the socket extension is "socket.bundle" and
1001  * <code>require 'socket.so'</code> will load the socket extension.
1002  *
1003  * The absolute path of the loaded file is added to
1004  * <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be
1005  * loaded again if its path already appears in <code>$"</code>. For example,
1006  * <code>require 'a'; require './a'</code> will not load <code>a.rb</code>
1007  * again.
1008  *
1009  * require "my-library.rb"
1010  * require "db-driver"
1011  *
1012  * Any constants or globals within the loaded source file will be available
1013  * in the calling program's global namespace. However, local variables will
1014  * not be propagated to the loading environment.
1015  *
1016  */
1017 
1018 VALUE
1020 {
1021  return rb_require_string(fname);
1022 }
1023 
1024 /*
1025  * call-seq:
1026  * require_relative(string) -> true or false
1027  *
1028  * Ruby tries to load the library named _string_ relative to the directory
1029  * containing the requiring file. If the file does not exist a LoadError is
1030  * raised. Returns +true+ if the file was loaded and +false+ if the file was
1031  * already loaded before.
1032  */
1033 VALUE
1034 rb_f_require_relative(VALUE obj, VALUE fname)
1035 {
1036  VALUE base = rb_current_realfilepath();
1037  if (NIL_P(base)) {
1038  rb_loaderror("cannot infer basepath");
1039  }
1040  base = rb_file_dirname(base);
1041  return rb_require_string_internal(rb_file_absolute_path(fname, base), false);
1042 }
1043 
1044 typedef int (*feature_func)(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn);
1045 
1046 static int
1047 search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
1048 {
1049  VALUE tmp;
1050  char *ext, *ftptr;
1051  int ft = 0;
1052  const char *loading;
1053 
1054  *path = 0;
1055  ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
1056  if (ext && !strchr(ext, '/')) {
1057  if (IS_RBEXT(ext)) {
1058  if (rb_feature_p(vm, ftptr, ext, TRUE, FALSE, &loading)) {
1059  if (loading) *path = rb_filesystem_str_new_cstr(loading);
1060  return 'r';
1061  }
1062  if ((tmp = rb_find_file(fname)) != 0) {
1063  ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1064  if (!rb_feature_p(vm, ftptr, ext, TRUE, TRUE, &loading) || loading)
1065  *path = tmp;
1066  return 'r';
1067  }
1068  return 0;
1069  }
1070  else if (IS_SOEXT(ext)) {
1071  if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
1072  if (loading) *path = rb_filesystem_str_new_cstr(loading);
1073  return 's';
1074  }
1075  tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
1076  rb_str_cat2(tmp, DLEXT);
1077  OBJ_FREEZE(tmp);
1078  if ((tmp = rb_find_file(tmp)) != 0) {
1079  ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1080  if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
1081  *path = tmp;
1082  return 's';
1083  }
1084  }
1085  else if (IS_DLEXT(ext)) {
1086  if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
1087  if (loading) *path = rb_filesystem_str_new_cstr(loading);
1088  return 's';
1089  }
1090  if ((tmp = rb_find_file(fname)) != 0) {
1091  ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1092  if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
1093  *path = tmp;
1094  return 's';
1095  }
1096  }
1097  }
1098  else if ((ft = rb_feature_p(vm, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
1099  if (loading) *path = rb_filesystem_str_new_cstr(loading);
1100  return 'r';
1101  }
1102  tmp = fname;
1103  const unsigned int type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
1104 
1105  // Check if it's a statically linked extension when
1106  // not already a feature and not found as a dynamic library.
1107  if (!ft && type != loadable_ext_rb && vm->static_ext_inits) {
1108  VALUE lookup_name = tmp;
1109  // Append ".so" if not already present so for example "etc" can find "etc.so".
1110  // We always register statically linked extensions with a ".so" extension.
1111  // See encinit.c and extinit.c (generated at build-time).
1112  if (!ext) {
1113  lookup_name = rb_str_dup(lookup_name);
1114  rb_str_cat_cstr(lookup_name, ".so");
1115  }
1116  ftptr = RSTRING_PTR(lookup_name);
1117  if (st_lookup(vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
1118  *path = rb_filesystem_str_new_cstr(ftptr);
1119  return 's';
1120  }
1121  }
1122 
1123  switch (type) {
1124  case 0:
1125  if (ft)
1126  goto feature_present;
1127  ftptr = RSTRING_PTR(tmp);
1128  return rb_feature_p(vm, ftptr, 0, FALSE, TRUE, 0);
1129 
1130  default:
1131  if (ft) {
1132  goto feature_present;
1133  }
1134  /* fall through */
1135  case loadable_ext_rb:
1136  ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1137  if (rb_feature_p(vm, ftptr, ext, type == loadable_ext_rb, TRUE, &loading) && !loading)
1138  break;
1139  *path = tmp;
1140  }
1141  return type > loadable_ext_rb ? 's' : 'r';
1142 
1143  feature_present:
1144  if (loading) *path = rb_filesystem_str_new_cstr(loading);
1145  return ft;
1146 }
1147 
1148 static void
1149 load_failed(VALUE fname)
1150 {
1151  rb_load_fail(fname, "cannot load such file");
1152 }
1153 
1154 static VALUE
1155 load_ext(VALUE path)
1156 {
1157  rb_scope_visibility_set(METHOD_VISI_PUBLIC);
1158  return (VALUE)dln_load(RSTRING_PTR(path));
1159 }
1160 
1161 static bool
1162 run_static_ext_init(rb_vm_t *vm, const char *feature)
1163 {
1164  st_data_t key = (st_data_t)feature;
1165  st_data_t init_func;
1166 
1167  if (vm->static_ext_inits && st_delete(vm->static_ext_inits, &key, &init_func)) {
1168  ((void (*)(void))init_func)();
1169  return true;
1170  }
1171  return false;
1172 }
1173 
1174 static int
1175 no_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
1176 {
1177  return 0;
1178 }
1179 
1180 // Documented in doc/globals.rdoc
1181 VALUE
1182 rb_resolve_feature_path(VALUE klass, VALUE fname)
1183 {
1184  VALUE path;
1185  int found;
1186  VALUE sym;
1187 
1188  fname = rb_get_path(fname);
1189  path = rb_str_encode_ospath(fname);
1190  found = search_required(GET_VM(), path, &path, no_feature_p);
1191 
1192  switch (found) {
1193  case 'r':
1194  sym = ID2SYM(rb_intern("rb"));
1195  break;
1196  case 's':
1197  sym = ID2SYM(rb_intern("so"));
1198  break;
1199  default:
1200  return Qnil;
1201  }
1202 
1203  return rb_ary_new_from_args(2, sym, path);
1204 }
1205 
1206 static void
1207 ext_config_push(rb_thread_t *th, struct rb_ext_config *prev)
1208 {
1209  *prev = th->ext_config;
1210  th->ext_config = (struct rb_ext_config){0};
1211 }
1212 
1213 static void
1214 ext_config_pop(rb_thread_t *th, struct rb_ext_config *prev)
1215 {
1216  th->ext_config = *prev;
1217 }
1218 
1219 void
1221 {
1222  GET_THREAD()->ext_config.ractor_safe = flag;
1223 }
1224 
1225 /*
1226  * returns
1227  * 0: if already loaded (false)
1228  * 1: successfully loaded (true)
1229  * <0: not found (LoadError)
1230  * >1: exception
1231  */
1232 static int
1233 require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool warn)
1234 {
1235  volatile int result = -1;
1236  rb_thread_t *th = rb_ec_thread_ptr(ec);
1237  volatile const struct {
1238  VALUE wrapper, self, errinfo;
1240  } saved = {
1241  th->top_wrapper, th->top_self, ec->errinfo,
1242  ec,
1243  };
1244  enum ruby_tag_type state;
1245  char *volatile ftptr = 0;
1246  VALUE path;
1247  volatile VALUE saved_path;
1248  volatile VALUE realpath = 0;
1249  VALUE realpaths = get_loaded_features_realpaths(th->vm);
1250  VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
1251  volatile bool reset_ext_config = false;
1252  struct rb_ext_config prev_ext_config;
1253 
1254  path = rb_str_encode_ospath(fname);
1255  RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1256  saved_path = path;
1257 
1258  EC_PUSH_TAG(ec);
1259  ec->errinfo = Qnil; /* ensure */
1260  th->top_wrapper = 0;
1261  if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1262  VALUE handle;
1263  int found;
1264 
1265  RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1266  found = search_required(th->vm, path, &saved_path, rb_feature_p);
1267  RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
1268  path = saved_path;
1269 
1270  if (found) {
1271  if (!path || !(ftptr = load_lock(th->vm, RSTRING_PTR(path), warn))) {
1272  result = 0;
1273  }
1274  else if (!*ftptr) {
1275  result = TAG_RETURN;
1276  }
1277  else if (found == 's' && run_static_ext_init(th->vm, RSTRING_PTR(path))) {
1278  result = TAG_RETURN;
1279  }
1280  else if (RTEST(rb_hash_aref(realpaths,
1281  realpath = realpath_internal_cached(realpath_map, path)))) {
1282  result = 0;
1283  }
1284  else {
1285  switch (found) {
1286  case 'r':
1287  load_iseq_eval(saved.ec, path);
1288  break;
1289 
1290  case 's':
1291  reset_ext_config = true;
1292  ext_config_push(th, &prev_ext_config);
1293  handle = rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
1294  path, VM_BLOCK_HANDLER_NONE, path);
1295  rb_hash_aset(ruby_dln_libmap, path, SVALUE2NUM((SIGNED_VALUE)handle));
1296  break;
1297  }
1298  result = TAG_RETURN;
1299  }
1300  }
1301  }
1302  EC_POP_TAG();
1303 
1304  ec = saved.ec;
1305  rb_thread_t *th2 = rb_ec_thread_ptr(ec);
1306  th2->top_self = saved.self;
1307  th2->top_wrapper = saved.wrapper;
1308  if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1309 
1310  path = saved_path;
1311  if (ftptr) load_unlock(th2->vm, RSTRING_PTR(path), !state);
1312 
1313  if (state) {
1314  if (state == TAG_FATAL || state == TAG_THROW) {
1315  EC_JUMP_TAG(ec, state);
1316  }
1317  else if (exception) {
1318  /* usually state == TAG_RAISE only, except for
1319  * rb_iseq_load_iseq in load_iseq_eval case */
1320  VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
1321  if (!NIL_P(exc)) ec->errinfo = exc;
1322  return TAG_RAISE;
1323  }
1324  else if (state == TAG_RETURN) {
1325  return TAG_RAISE;
1326  }
1327  RB_GC_GUARD(fname);
1328  /* never TAG_RETURN */
1329  return state;
1330  }
1331  if (!NIL_P(ec->errinfo)) {
1332  if (!exception) return TAG_RAISE;
1333  rb_exc_raise(ec->errinfo);
1334  }
1335 
1336  if (result == TAG_RETURN) {
1337  rb_provide_feature(th2->vm, path);
1338  VALUE real = realpath;
1339  if (real) {
1340  real = rb_fstring(real);
1341  rb_hash_aset(realpaths, real, Qtrue);
1342  }
1343  }
1344  ec->errinfo = saved.errinfo;
1345 
1346  RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1347 
1348  return result;
1349 }
1350 
1351 int
1352 rb_require_internal_silent(VALUE fname)
1353 {
1354  rb_execution_context_t *ec = GET_EC();
1355  return require_internal(ec, fname, 1, false);
1356 }
1357 
1358 int
1359 rb_require_internal(VALUE fname)
1360 {
1361  rb_execution_context_t *ec = GET_EC();
1362  return require_internal(ec, fname, 1, RTEST(ruby_verbose));
1363 }
1364 
1365 int
1366 ruby_require_internal(const char *fname, unsigned int len)
1367 {
1368  struct RString fake;
1369  VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
1370  rb_execution_context_t *ec = GET_EC();
1371  int result = require_internal(ec, str, 0, RTEST(ruby_verbose));
1373  return result == TAG_RETURN ? 1 : result ? -1 : 0;
1374 }
1375 
1376 VALUE
1378 {
1379  return rb_require_string_internal(FilePathValue(fname), false);
1380 }
1381 
1382 static VALUE
1383 rb_require_string_internal(VALUE fname, bool resurrect)
1384 {
1385  rb_execution_context_t *ec = GET_EC();
1386  int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
1387 
1388  if (result > TAG_RETURN) {
1389  EC_JUMP_TAG(ec, result);
1390  }
1391  if (result < 0) {
1392  if (resurrect) fname = rb_str_resurrect(fname);
1393  load_failed(fname);
1394  }
1395 
1396  return RBOOL(result);
1397 }
1398 
1399 VALUE
1400 rb_require(const char *fname)
1401 {
1402  struct RString fake;
1403  VALUE str = rb_setup_fake_str(&fake, fname, strlen(fname), 0);
1404  return rb_require_string_internal(str, true);
1405 }
1406 
1407 static int
1408 register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1409 {
1410  const char *name = (char *)*key;
1411  if (existing) {
1412  /* already registered */
1413  rb_warn("%s is already registered", name);
1414  }
1415  else {
1416  *value = (st_data_t)init;
1417  }
1418  return ST_CONTINUE;
1419 }
1420 
1421 // Private API for statically linked extensions.
1422 // Used with the ext/Setup file, the --with-setup and
1423 // --with-static-linked-ext configuration option, etc.
1424 void
1425 ruby_init_ext(const char *name, void (*init)(void))
1426 {
1427  st_table *inits_table;
1428  rb_vm_t *vm = GET_VM();
1429 
1430  if (feature_provided(vm, name, 0))
1431  return;
1432 
1433  inits_table = vm->static_ext_inits;
1434  if (!inits_table) {
1435  inits_table = st_init_strtable();
1436  vm->static_ext_inits = inits_table;
1437  }
1438  st_update(inits_table, (st_data_t)name, register_init_ext, (st_data_t)init);
1439 }
1440 
1441 /*
1442  * call-seq:
1443  * mod.autoload(const, filename) -> nil
1444  *
1445  * Registers _filename_ to be loaded (using Kernel::require)
1446  * the first time that _const_ (which may be a String or
1447  * a symbol) is accessed in the namespace of _mod_.
1448  *
1449  * module A
1450  * end
1451  * A.autoload(:B, "b")
1452  * A::B.doit # autoloads "b"
1453  *
1454  * If _const_ in _mod_ is defined as autoload, the file name to be
1455  * loaded is replaced with _filename_. If _const_ is defined but not
1456  * as autoload, does nothing.
1457  */
1458 
1459 static VALUE
1460 rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1461 {
1462  ID id = rb_to_id(sym);
1463 
1464  FilePathValue(file);
1465  rb_autoload_str(mod, id, file);
1466  return Qnil;
1467 }
1468 
1469 /*
1470  * call-seq:
1471  * mod.autoload?(name, inherit=true) -> String or nil
1472  *
1473  * Returns _filename_ to be loaded if _name_ is registered as
1474  * +autoload+ in the namespace of _mod_ or one of its ancestors.
1475  *
1476  * module A
1477  * end
1478  * A.autoload(:B, "b")
1479  * A.autoload?(:B) #=> "b"
1480  *
1481  * If +inherit+ is false, the lookup only checks the autoloads in the receiver:
1482  *
1483  * class A
1484  * autoload :CONST, "const.rb"
1485  * end
1486  *
1487  * class B < A
1488  * end
1489  *
1490  * B.autoload?(:CONST) #=> "const.rb", found in A (ancestor)
1491  * B.autoload?(:CONST, false) #=> nil, not found in B itself
1492  *
1493  */
1494 
1495 static VALUE
1496 rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
1497 {
1498  int recur = (rb_check_arity(argc, 1, 2) == 1) ? TRUE : RTEST(argv[1]);
1499  VALUE sym = argv[0];
1500 
1501  ID id = rb_check_id(&sym);
1502  if (!id) {
1503  return Qnil;
1504  }
1505  return rb_autoload_at_p(mod, id, recur);
1506 }
1507 
1508 /*
1509  * call-seq:
1510  * autoload(const, filename) -> nil
1511  *
1512  * Registers _filename_ to be loaded (using Kernel::require)
1513  * the first time that _const_ (which may be a String or
1514  * a symbol) is accessed.
1515  *
1516  * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1517  *
1518  * If _const_ is defined as autoload, the file name to be loaded is
1519  * replaced with _filename_. If _const_ is defined but not as
1520  * autoload, does nothing.
1521  */
1522 
1523 static VALUE
1524 rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1525 {
1526  VALUE klass = rb_class_real(rb_vm_cbase());
1527  if (!klass) {
1528  rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1529  }
1530  return rb_mod_autoload(klass, sym, file);
1531 }
1532 
1533 /*
1534  * call-seq:
1535  * autoload?(name, inherit=true) -> String or nil
1536  *
1537  * Returns _filename_ to be loaded if _name_ is registered as
1538  * +autoload+ in the current namespace or one of its ancestors.
1539  *
1540  * autoload(:B, "b")
1541  * autoload?(:B) #=> "b"
1542  *
1543  * module C
1544  * autoload(:D, "d")
1545  * autoload?(:D) #=> "d"
1546  * autoload?(:B) #=> nil
1547  * end
1548  *
1549  * class E
1550  * autoload(:F, "f")
1551  * autoload?(:F) #=> "f"
1552  * autoload?(:B) #=> "b"
1553  * end
1554  */
1555 
1556 static VALUE
1557 rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
1558 {
1559  /* use rb_vm_cbase() as same as rb_f_autoload. */
1560  VALUE klass = rb_vm_cbase();
1561  if (NIL_P(klass)) {
1562  return Qnil;
1563  }
1564  return rb_mod_autoload_p(argc, argv, klass);
1565 }
1566 
1567 void *
1568 rb_ext_resolve_symbol(const char* fname, const char* symbol)
1569 {
1570  VALUE handle;
1571  VALUE resolved;
1572  VALUE path;
1573  char *ext;
1574  VALUE fname_str = rb_str_new_cstr(fname);
1575 
1576  resolved = rb_resolve_feature_path((VALUE)NULL, fname_str);
1577  if (NIL_P(resolved)) {
1578  ext = strrchr(fname, '.');
1579  if (!ext || !IS_SOEXT(ext)) {
1580  rb_str_cat_cstr(fname_str, ".so");
1581  }
1582  if (rb_feature_p(GET_VM(), fname, 0, FALSE, FALSE, 0)) {
1583  return dln_symbol(NULL, symbol);
1584  }
1585  return NULL;
1586  }
1587  if (RARRAY_LEN(resolved) != 2 || rb_ary_entry(resolved, 0) != ID2SYM(rb_intern("so"))) {
1588  return NULL;
1589  }
1590  path = rb_ary_entry(resolved, 1);
1591  handle = rb_hash_lookup(ruby_dln_libmap, path);
1592  if (NIL_P(handle)) {
1593  return NULL;
1594  }
1595  return dln_symbol((void *)NUM2SVALUE(handle), symbol);
1596 }
1597 
1598 void
1599 Init_load(void)
1600 {
1601  rb_vm_t *vm = GET_VM();
1602  static const char var_load_path[] = "$:";
1603  ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1604 
1605  rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
1606  rb_alias_variable(rb_intern_const("$-I"), id_load_path);
1607  rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
1608  vm->load_path = rb_ary_new();
1609  vm->expanded_load_path = rb_ary_hidden_new(0);
1610  vm->load_path_snapshot = rb_ary_hidden_new(0);
1611  vm->load_path_check_cache = 0;
1612  rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
1613 
1614  rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
1615  rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0);
1616  vm->loaded_features = rb_ary_new();
1617  vm->loaded_features_snapshot = rb_ary_hidden_new(0);
1618  vm->loaded_features_index = st_init_numtable();
1619  vm->loaded_features_realpaths = rb_hash_new();
1620  rb_obj_hide(vm->loaded_features_realpaths);
1621  vm->loaded_features_realpath_map = rb_hash_new();
1622  rb_obj_hide(vm->loaded_features_realpath_map);
1623 
1624  rb_define_global_function("load", rb_f_load, -1);
1625  rb_define_global_function("require", rb_f_require, 1);
1626  rb_define_global_function("require_relative", rb_f_require_relative, 1);
1627  rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1628  rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
1629  rb_define_global_function("autoload", rb_f_autoload, 2);
1630  rb_define_global_function("autoload?", rb_f_autoload_p, -1);
1631 
1632  ruby_dln_libmap = rb_hash_new_with_size(0);
1633  rb_vm_register_global_object(ruby_dln_libmap);
1634 }
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition: assert.h:219
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:685
void rb_extend_object(VALUE obj, VALUE module)
Extend the object with the module.
Definition: eval.c:1750
VALUE rb_module_new(void)
Creates a new, anonymous module.
Definition: class.c:1076
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition: class.c:2635
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a method.
Definition: class.c:2142
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
Definition: class.c:2339
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition: string.h:1675
#define T_STRING
Old name of RUBY_T_STRING.
Definition: value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition: xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition: long.h:48
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition: fl_type.h:137
#define ID2SYM
Old name of RB_ID2SYM.
Definition: symbol.h:44
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition: fl_type.h:135
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition: value_type.h:63
#define T_MODULE
Old name of RUBY_T_MODULE.
Definition: value_type.h:70
#define Qtrue
Old name of RUBY_Qtrue.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition: long.h:46
#define NIL_P
Old name of RB_NIL_P.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition: error.c:3627
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition: eval.c:676
void rb_set_errinfo(VALUE err)
Sets the current exception ($!) to the given value.
Definition: eval.c:1941
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition: error.h:471
VALUE rb_eTypeError
TypeError exception.
Definition: error.c:1403
VALUE rb_eRuntimeError
RuntimeError exception.
Definition: error.c:1401
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition: error.c:465
void rb_loaderror(const char *fmt,...)
Raises an instance of rb_eLoadError.
Definition: error.c:3646
void rb_warning(const char *fmt,...)
Issues a warning.
Definition: error.c:496
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition: object.c:104
VALUE rb_cModule
Module class.
Definition: object.c:67
VALUE rb_class_real(VALUE klass)
Finds a "real" class.
Definition: object.c:237
VALUE rb_obj_clone(VALUE obj)
Produces a shallow copy of the given object.
Definition: object.c:519
Encoding relates APIs.
VALUE rb_ary_shared_with_p(VALUE lhs, VALUE rhs)
Queries if the passed two arrays share the same backend storage.
Definition: array.c:669
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
Definition: array.c:2777
VALUE rb_ary_replace(VALUE copy, VALUE orig)
Replaces the contents of the former object with the contents of the latter.
Definition: array.c:4587
VALUE rb_ary_new(void)
Allocates a new, empty array.
Definition: array.c:747
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
Definition: array.c:859
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
Definition: array.c:4642
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
Definition: array.c:1384
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
Definition: array.c:648
VALUE rb_ary_new_from_args(long n,...)
Constructs an array from the passed objects.
Definition: array.c:753
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
Definition: array.c:1737
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
Definition: array.c:1207
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition: error.h:284
VALUE rb_find_file(VALUE path)
Identical to rb_find_file_ext(), except it takes a feature name and is extension at once,...
Definition: file.c:6589
VALUE rb_str_encode_ospath(VALUE path)
Converts a string into an "OS Path" encoding, if any.
Definition: file.c:252
int rb_is_absolute_path(const char *path)
Queries if the given path is an absolute path.
Definition: file.c:6350
int rb_find_file_ext(VALUE *feature, const char *const *exts)
Resolves a feature's path.
Definition: file.c:6530
VALUE rb_file_dirname(VALUE fname)
Strips a file path's last component (and trailing separators if any).
Definition: file.c:4890
VALUE rb_file_absolute_path(VALUE fname, VALUE dname)
Maps a relative path to its absolute representation.
Definition: file.c:4265
VALUE rb_hash_aref(VALUE hash, VALUE key)
Queries the given key in the given hash table.
Definition: hash.c:2073
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Inserts or replaces ("upsert"s) the objects into the given hash table.
Definition: hash.c:2893
VALUE rb_hash_lookup(VALUE hash, VALUE key)
Identical to rb_hash_aref(), except it always returns RUBY_Qnil for misshits.
Definition: hash.c:2099
VALUE rb_hash_dup(VALUE hash)
Duplicates a hash.
Definition: hash.c:1563
VALUE rb_hash_clear(VALUE hash)
Swipes everything out of the passed hash table.
Definition: hash.c:2820
VALUE rb_hash_new(void)
Creates a new, empty hash object.
Definition: hash.c:1475
void * rb_ext_resolve_symbol(const char *feature, const char *symbol)
Resolves and returns a symbol of a function in the native extension specified by the feature and symb...
Definition: load.c:1568
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition: load.c:714
VALUE rb_f_require(VALUE self, VALUE feature)
Identical to rb_require_string(), except it ignores the first argument for no reason.
Definition: load.c:1019
void rb_ext_ractor_safe(bool flag)
Asserts that the extension library that calls this function is aware of Ractor.
Definition: load.c:1220
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
Definition: load.c:1377
int rb_feature_provided(const char *feature, const char **loading)
Identical to rb_provided(), except it additionally returns the "canonical" name of the loaded feature...
Definition: load.c:686
void rb_load_protect(VALUE path, int wrap, int *state)
Identical to rb_load(), except it avoids potential global escapes.
Definition: load.c:856
int rb_provided(const char *feature)
Queries if the given feature has already been loaded into the execution context.
Definition: load.c:653
void rb_load(VALUE path, int wrap)
Loads and executes the Ruby program in the given file.
Definition: load.c:848
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition: string.c:3662
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition: string.c:1655
VALUE rb_str_subseq(VALUE str, long beg, long len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
Definition: string.c:3046
VALUE rb_str_cat2(VALUE, const char *)
Just another name of rb_str_cat_cstr.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition: string.c:1911
VALUE rb_str_resurrect(VALUE str)
I guess there is no use case of this function in extension libraries, but this is a routine identical...
Definition: string.c:1929
VALUE rb_filesystem_str_new_cstr(const char *ptr)
Identical to rb_filesystem_str_new(), except it assumes the passed pointer is a pointer to a C string...
Definition: string.c:1357
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition: string.c:4133
#define rb_strlen_lit(str)
Length of a string literal.
Definition: string.h:1692
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition: string.c:3163
VALUE rb_str_new_cstr(const char *ptr)
Identical to rb_str_new(), except it assumes the passed pointer is a pointer to a C string.
Definition: string.c:1054
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
Definition: string.c:3302
VALUE rb_str_cat_cstr(VALUE dst, const char *src)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
Definition: string.c:3440
void rb_alias_variable(ID dst, ID src)
Aliases a global variable.
Definition: variable.c:987
ID rb_intern2(const char *name, long len)
Identical to rb_intern(), except it additionally takes the length of the string.
Definition: symbol.c:816
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition: symbol.h:276
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
Definition: symbol.c:1117
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
Definition: symbol.c:823
ID rb_to_id(VALUE str)
Identical to rb_intern(), except it takes an instance of rb_cString.
Definition: string.c:12450
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition: variable.h:135
void rb_define_virtual_variable(const char *name, rb_gvar_getter_t *getter, rb_gvar_setter_t *setter)
Defines a global variable that is purely function-backended.
Definition: variable.c:738
void rb_define_hooked_variable(const char *name, VALUE *var, rb_gvar_getter_t *getter, rb_gvar_setter_t *setter)
Identical to rb_define_virtual_variable(), but can also specify a storage.
Definition: variable.c:707
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition: io.h:2
int len
Length of the buffer.
Definition: io.h:8
char * ruby_strdup(const char *str)
This is our own version of strdup(3) that uses ruby_xmalloc() instead of system malloc (benefits our ...
Definition: util.c:536
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition: memory.h:367
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition: memory.h:162
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition: memory.h:379
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:56
int st_foreach(st_table *q, int_type *w, st_data_t e)
Iteration over the given table.
Definition: cxxanyargs.hpp:432
#define RARRAY_LEN
Just another name of rb_array_len.
Definition: rarray.h:51
#define RARRAY_AREF(a, i)
Definition: rarray.h:403
#define StringValue(v)
Ensures that the parameter object is a String.
Definition: rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition: rstring.h:76
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition: rstring.h:416
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition: rstring.h:367
VALUE rb_get_path(VALUE obj)
Converts an object to a path.
Definition: file.c:246
VALUE rb_require(const char *feature)
Identical to rb_require_string(), except it takes C's string instead of Ruby's.
Definition: load.c:1400
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition: ruby.h:90
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition: stdarg.h:35
Ruby's String.
Definition: rstring.h:196
int32_t line
The line within the file that the parse starts on.
Definition: options.h:97
pm_scope_node_t node
The resulting scope node that will hold the generated AST.
Definition: prism_compile.h:80
pm_options_t options
The options that will be passed to the parser.
Definition: prism_compile.h:74
Definition: st.h:79
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition: value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition: value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition: value.h:40
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition: value_type.h:433
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition: value_type.h:376