Ruby: load.c Source File

Ruby 3.4.5p51 (2025-07-16 revision 20cda200d3ce092571d0b5d342dadca69636cb0f)

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