Ruby 3.3.7p123 (2025-01-15 revision be31f993d7fa0219d85f7b3c694d454da4ecc10b)
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
22static 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
38enum {
39 loadable_ext_rb = (0+ /* .rb extension is the first in both tables */
40 1) /* offset by rb_find_file_ext() */
41};
42
43static const char *const loadable_ext[] = {
44 ".rb", DLEXT,
45 0
46};
47
48static const char *const ruby_ext[] = {
49 ".rb",
50 0
51};
52
53enum 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 */
65static void
66rb_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_obj_freeze(ary);
108 vm->expanded_load_path = ary;
109 rb_ary_replace(vm->load_path_snapshot, vm->load_path);
110}
111
112static VALUE
113get_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
157VALUE
158rb_get_expanded_load_path(void)
159{
160 return get_expanded_load_path(GET_VM());
161}
162
163static VALUE
164load_path_getter(ID id, VALUE * p)
165{
166 rb_vm_t *vm = (void *)p;
167 return vm->load_path;
168}
169
170static VALUE
171get_loaded_features(rb_vm_t *vm)
172{
173 return vm->loaded_features;
174}
175
176static VALUE
177get_loaded_features_realpaths(rb_vm_t *vm)
178{
179 return vm->loaded_features_realpaths;
180}
181
182static VALUE
183get_loaded_features_realpath_map(rb_vm_t *vm)
184{
185 return vm->loaded_features_realpath_map;
186}
187
188static VALUE
189get_LOADED_FEATURES(ID _x, VALUE *_y)
190{
191 return get_loaded_features(GET_VM());
192}
193
194static void
195reset_loaded_features_snapshot(rb_vm_t *vm)
196{
197 rb_ary_replace(vm->loaded_features_snapshot, vm->loaded_features);
198}
199
200static struct st_table *
201get_loaded_features_index_raw(rb_vm_t *vm)
202{
203 return vm->loaded_features_index;
204}
205
206static st_table *
207get_loading_table(rb_vm_t *vm)
208{
209 return vm->loading_table;
210}
211
212static st_data_t
213feature_key(const char *str, size_t len)
214{
215 return st_hash(str, len, 0xfea7009e);
216}
217
218static bool
219is_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
227typedef rb_darray(long) feature_indexes_t;
228
229struct features_index_add_single_args {
230 rb_vm_t *vm;
231 VALUE offset;
232 bool rb;
233};
234
235static int
236features_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 assert(rb_darray_size(feature_indexes) == 2);
257 // assert feature_indexes does not look like a special const
258 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
298static void
299features_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*/
326static void
327features_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
364static int
365loaded_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
374void
375rb_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
381static st_table *
382get_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*/
437static VALUE
438loaded_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
489static int
490loaded_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 */
507static int
508rb_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
652int
653rb_provided(const char *feature)
654{
655 return rb_feature_provided(feature, 0);
656}
657
658static int
659feature_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
685int
686rb_feature_provided(const char *feature, const char **loading)
687{
688 return feature_provided(GET_VM(), feature, loading);
689}
690
691static void
692rb_provide_feature(rb_vm_t *vm, VALUE feature)
693{
694 VALUE features;
695
696 features = get_loaded_features(vm);
697 if (OBJ_FROZEN(features)) {
698 rb_raise(rb_eRuntimeError,
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
713void
714rb_provide(const char *feature)
715{
716 rb_provide_feature(GET_VM(), rb_fstring_cstr(feature));
717}
718
719NORETURN(static void load_failed(VALUE));
720
721static inline VALUE
722realpath_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
734static inline void
735load_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 if (*rb_ruby_prism_ptr()) {
741 pm_string_t input;
742 pm_options_t options = { 0 };
743
744 pm_string_mapped_init(&input, RSTRING_PTR(fname));
745 pm_options_filepath_set(&options, RSTRING_PTR(fname));
746
747 pm_parser_t parser;
748 pm_parser_init(&parser, pm_string_source(&input), pm_string_length(&input), &options);
749
750 iseq = rb_iseq_new_main_prism(&input, &options, fname);
751
752 pm_string_free(&input);
753 pm_options_free(&options);
754 }
755 else {
756 rb_execution_context_t *ec = GET_EC();
757 VALUE v = rb_vm_push_frame_fname(ec, fname);
758 rb_ast_t *ast;
759 VALUE parser = rb_parser_new();
760 rb_parser_set_context(parser, NULL, FALSE);
761 ast = (rb_ast_t *)rb_parser_load_file(parser, fname);
762
763 rb_thread_t *th = rb_ec_thread_ptr(ec);
764 VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
765
766 iseq = rb_iseq_new_top(&ast->body, rb_fstring_lit("<top (required)>"),
767 fname, realpath_internal_cached(realpath_map, fname), NULL);
768 rb_ast_dispose(ast);
769 rb_vm_pop_frame(ec);
770 RB_GC_GUARD(v);
771 }
772 }
773 rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
774 rb_iseq_eval(iseq);
775}
776
777static inline enum ruby_tag_type
778load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
779{
780 enum ruby_tag_type state;
781 rb_thread_t *th = rb_ec_thread_ptr(ec);
782 volatile VALUE wrapper = th->top_wrapper;
783 volatile VALUE self = th->top_self;
784#if !defined __GNUC__
785 rb_thread_t *volatile th0 = th;
786#endif
787
788 ec->errinfo = Qnil; /* ensure */
789
790 /* load in module as toplevel */
791 th->top_self = rb_obj_clone(rb_vm_top_self());
792 th->top_wrapper = load_wrapper;
793 rb_extend_object(th->top_self, th->top_wrapper);
794
795 EC_PUSH_TAG(ec);
796 state = EC_EXEC_TAG();
797 if (state == TAG_NONE) {
798 load_iseq_eval(ec, fname);
799 }
800 EC_POP_TAG();
801
802#if !defined __GNUC__
803 th = th0;
804 fname = RB_GC_GUARD(fname);
805#endif
806 th->top_self = self;
807 th->top_wrapper = wrapper;
808 return state;
809}
810
811static inline void
812raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state)
813{
814 if (state) {
815 rb_vm_jump_tag_but_local_jump(state);
816 }
817
818 if (!NIL_P(ec->errinfo)) {
819 rb_exc_raise(ec->errinfo);
820 }
821}
822
823static void
824rb_load_internal(VALUE fname, VALUE wrap)
825{
826 rb_execution_context_t *ec = GET_EC();
827 enum ruby_tag_type state = TAG_NONE;
828 if (RTEST(wrap)) {
829 if (!RB_TYPE_P(wrap, T_MODULE)) {
830 wrap = rb_module_new();
831 }
832 state = load_wrapping(ec, fname, wrap);
833 }
834 else {
835 load_iseq_eval(ec, fname);
836 }
837 raise_load_if_failed(ec, state);
838}
839
840void
841rb_load(VALUE fname, int wrap)
842{
843 VALUE tmp = rb_find_file(FilePathValue(fname));
844 if (!tmp) load_failed(fname);
845 rb_load_internal(tmp, RBOOL(wrap));
846}
847
848void
849rb_load_protect(VALUE fname, int wrap, int *pstate)
850{
851 enum ruby_tag_type state;
852
853 EC_PUSH_TAG(GET_EC());
854 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
855 rb_load(fname, wrap);
856 }
857 EC_POP_TAG();
858
859 if (state != TAG_NONE) *pstate = state;
860}
861
862/*
863 * call-seq:
864 * load(filename, wrap=false) -> true
865 *
866 * Loads and executes the Ruby program in the file _filename_.
867 *
868 * If the filename is an absolute path (e.g. starts with '/'), the file
869 * will be loaded directly using the absolute path.
870 *
871 * If the filename is an explicit relative path (e.g. starts with './' or
872 * '../'), the file will be loaded using the relative path from the current
873 * directory.
874 *
875 * Otherwise, the file will be searched for in the library
876 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
877 * If the file is found in a directory, it will attempt to load the file
878 * relative to that directory. If the file is not found in any of the
879 * directories in <code>$LOAD_PATH</code>, the file will be loaded using
880 * the relative path from the current directory.
881 *
882 * If the file doesn't exist when there is an attempt to load it, a
883 * LoadError will be raised.
884 *
885 * If the optional _wrap_ parameter is +true+, the loaded script will
886 * be executed under an anonymous module, protecting the calling
887 * program's global namespace. If the optional _wrap_ parameter is a
888 * module, the loaded script will be executed under the given module.
889 * In no circumstance will any local variables in the loaded file be
890 * propagated to the loading environment.
891 */
892
893static VALUE
894rb_f_load(int argc, VALUE *argv, VALUE _)
895{
896 VALUE fname, wrap, path, orig_fname;
897
898 rb_scan_args(argc, argv, "11", &fname, &wrap);
899
900 orig_fname = rb_get_path_check_to_string(fname);
901 fname = rb_str_encode_ospath(orig_fname);
902 RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
903
904 path = rb_find_file(fname);
905 if (!path) {
906 if (!rb_file_load_ok(RSTRING_PTR(fname)))
907 load_failed(orig_fname);
908 path = fname;
909 }
910 rb_load_internal(path, wrap);
911
912 RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
913
914 return Qtrue;
915}
916
917static char *
918load_lock(rb_vm_t *vm, const char *ftptr, bool warn)
919{
920 st_data_t data;
921 st_table *loading_tbl = get_loading_table(vm);
922
923 if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
924 /* partial state */
925 ftptr = ruby_strdup(ftptr);
926 data = (st_data_t)rb_thread_shield_new();
927 st_insert(loading_tbl, (st_data_t)ftptr, data);
928 return (char *)ftptr;
929 }
930
931 if (warn && rb_thread_shield_owned((VALUE)data)) {
932 VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
933 rb_backtrace_each(rb_str_append, warning);
934 rb_warning("%"PRIsVALUE, warning);
935 }
936 switch (rb_thread_shield_wait((VALUE)data)) {
937 case Qfalse:
938 case Qnil:
939 return 0;
940 }
941 return (char *)ftptr;
942}
943
944static int
945release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing)
946{
947 VALUE thread_shield = (VALUE)*value;
948 if (!existing) return ST_STOP;
949 if (done) {
950 rb_thread_shield_destroy(thread_shield);
951 /* Delete the entry even if there are waiting threads, because they
952 * won't load the file and won't delete the entry. */
953 }
954 else if (rb_thread_shield_release(thread_shield)) {
955 /* still in-use */
956 return ST_CONTINUE;
957 }
958 xfree((char *)*key);
959 return ST_DELETE;
960}
961
962static void
963load_unlock(rb_vm_t *vm, const char *ftptr, int done)
964{
965 if (ftptr) {
966 st_data_t key = (st_data_t)ftptr;
967 st_table *loading_tbl = get_loading_table(vm);
968
969 st_update(loading_tbl, key, release_thread_shield, done);
970 }
971}
972
973static VALUE rb_require_string_internal(VALUE fname, bool resurrect);
974
975/*
976 * call-seq:
977 * require(name) -> true or false
978 *
979 * Loads the given +name+, returning +true+ if successful and +false+ if the
980 * feature is already loaded.
981 *
982 * If the filename neither resolves to an absolute path nor starts with
983 * './' or '../', the file will be searched for in the library
984 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
985 * If the filename starts with './' or '../', resolution is based on Dir.pwd.
986 *
987 * If the filename has the extension ".rb", it is loaded as a source file; if
988 * the extension is ".so", ".o", or the default shared library extension on
989 * the current platform, Ruby loads the shared library as a Ruby extension.
990 * Otherwise, Ruby tries adding ".rb", ".so", and so on to the name until
991 * found. If the file named cannot be found, a LoadError will be raised.
992 *
993 * For Ruby extensions the filename given may use ".so" or ".o". For example,
994 * on macOS the socket extension is "socket.bundle" and
995 * <code>require 'socket.so'</code> will load the socket extension.
996 *
997 * The absolute path of the loaded file is added to
998 * <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be
999 * loaded again if its path already appears in <code>$"</code>. For example,
1000 * <code>require 'a'; require './a'</code> will not load <code>a.rb</code>
1001 * again.
1002 *
1003 * require "my-library.rb"
1004 * require "db-driver"
1005 *
1006 * Any constants or globals within the loaded source file will be available
1007 * in the calling program's global namespace. However, local variables will
1008 * not be propagated to the loading environment.
1009 *
1010 */
1011
1012VALUE
1014{
1015 return rb_require_string(fname);
1016}
1017
1018/*
1019 * call-seq:
1020 * require_relative(string) -> true or false
1021 *
1022 * Ruby tries to load the library named _string_ relative to the directory
1023 * containing the requiring file. If the file does not exist a LoadError is
1024 * raised. Returns +true+ if the file was loaded and +false+ if the file was
1025 * already loaded before.
1026 */
1027VALUE
1028rb_f_require_relative(VALUE obj, VALUE fname)
1029{
1030 VALUE base = rb_current_realfilepath();
1031 if (NIL_P(base)) {
1032 rb_loaderror("cannot infer basepath");
1033 }
1034 base = rb_file_dirname(base);
1035 return rb_require_string_internal(rb_file_absolute_path(fname, base), false);
1036}
1037
1038typedef int (*feature_func)(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn);
1039
1040static int
1041search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
1042{
1043 VALUE tmp;
1044 char *ext, *ftptr;
1045 int ft = 0;
1046 const char *loading;
1047
1048 *path = 0;
1049 ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
1050 if (ext && !strchr(ext, '/')) {
1051 if (IS_RBEXT(ext)) {
1052 if (rb_feature_p(vm, ftptr, ext, TRUE, FALSE, &loading)) {
1053 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1054 return 'r';
1055 }
1056 if ((tmp = rb_find_file(fname)) != 0) {
1057 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1058 if (!rb_feature_p(vm, ftptr, ext, TRUE, TRUE, &loading) || loading)
1059 *path = tmp;
1060 return 'r';
1061 }
1062 return 0;
1063 }
1064 else if (IS_SOEXT(ext)) {
1065 if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
1066 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1067 return 's';
1068 }
1069 tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
1070 rb_str_cat2(tmp, DLEXT);
1071 OBJ_FREEZE(tmp);
1072 if ((tmp = rb_find_file(tmp)) != 0) {
1073 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1074 if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
1075 *path = tmp;
1076 return 's';
1077 }
1078 }
1079 else if (IS_DLEXT(ext)) {
1080 if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) {
1081 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1082 return 's';
1083 }
1084 if ((tmp = rb_find_file(fname)) != 0) {
1085 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1086 if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading)
1087 *path = tmp;
1088 return 's';
1089 }
1090 }
1091 }
1092 else if ((ft = rb_feature_p(vm, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
1093 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1094 return 'r';
1095 }
1096 tmp = fname;
1097 const unsigned int type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
1098
1099 // Check if it's a statically linked extension when
1100 // not already a feature and not found as a dynamic library.
1101 if (!ft && type != loadable_ext_rb && vm->static_ext_inits) {
1102 VALUE lookup_name = tmp;
1103 // Append ".so" if not already present so for example "etc" can find "etc.so".
1104 // We always register statically linked extensions with a ".so" extension.
1105 // See encinit.c and extinit.c (generated at build-time).
1106 if (!ext) {
1107 lookup_name = rb_str_dup(lookup_name);
1108 rb_str_cat_cstr(lookup_name, ".so");
1109 }
1110 ftptr = RSTRING_PTR(lookup_name);
1111 if (st_lookup(vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
1112 *path = rb_filesystem_str_new_cstr(ftptr);
1113 return 's';
1114 }
1115 }
1116
1117 switch (type) {
1118 case 0:
1119 if (ft)
1120 goto feature_present;
1121 ftptr = RSTRING_PTR(tmp);
1122 return rb_feature_p(vm, ftptr, 0, FALSE, TRUE, 0);
1123
1124 default:
1125 if (ft) {
1126 goto feature_present;
1127 }
1128 /* fall through */
1129 case loadable_ext_rb:
1130 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
1131 if (rb_feature_p(vm, ftptr, ext, type == loadable_ext_rb, TRUE, &loading) && !loading)
1132 break;
1133 *path = tmp;
1134 }
1135 return type > loadable_ext_rb ? 's' : 'r';
1136
1137 feature_present:
1138 if (loading) *path = rb_filesystem_str_new_cstr(loading);
1139 return ft;
1140}
1141
1142static void
1143load_failed(VALUE fname)
1144{
1145 rb_load_fail(fname, "cannot load such file");
1146}
1147
1148static VALUE
1149load_ext(VALUE path)
1150{
1151 rb_scope_visibility_set(METHOD_VISI_PUBLIC);
1152 return (VALUE)dln_load(RSTRING_PTR(path));
1153}
1154
1155static bool
1156run_static_ext_init(rb_vm_t *vm, const char *feature)
1157{
1158 st_data_t key = (st_data_t)feature;
1159 st_data_t init_func;
1160
1161 if (vm->static_ext_inits && st_delete(vm->static_ext_inits, &key, &init_func)) {
1162 ((void (*)(void))init_func)();
1163 return true;
1164 }
1165 return false;
1166}
1167
1168static int
1169no_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
1170{
1171 return 0;
1172}
1173
1174// Documented in doc/globals.rdoc
1175VALUE
1176rb_resolve_feature_path(VALUE klass, VALUE fname)
1177{
1178 VALUE path;
1179 int found;
1180 VALUE sym;
1181
1182 fname = rb_get_path(fname);
1183 path = rb_str_encode_ospath(fname);
1184 found = search_required(GET_VM(), path, &path, no_feature_p);
1185
1186 switch (found) {
1187 case 'r':
1188 sym = ID2SYM(rb_intern("rb"));
1189 break;
1190 case 's':
1191 sym = ID2SYM(rb_intern("so"));
1192 break;
1193 default:
1194 return Qnil;
1195 }
1196
1197 return rb_ary_new_from_args(2, sym, path);
1198}
1199
1200static void
1201ext_config_push(rb_thread_t *th, struct rb_ext_config *prev)
1202{
1203 *prev = th->ext_config;
1204 th->ext_config = (struct rb_ext_config){0};
1205}
1206
1207static void
1208ext_config_pop(rb_thread_t *th, struct rb_ext_config *prev)
1209{
1210 th->ext_config = *prev;
1211}
1212
1213void
1215{
1216 GET_THREAD()->ext_config.ractor_safe = flag;
1217}
1218
1219/*
1220 * returns
1221 * 0: if already loaded (false)
1222 * 1: successfully loaded (true)
1223 * <0: not found (LoadError)
1224 * >1: exception
1225 */
1226static int
1227require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool warn)
1228{
1229 volatile int result = -1;
1230 rb_thread_t *th = rb_ec_thread_ptr(ec);
1231 volatile const struct {
1232 VALUE wrapper, self, errinfo;
1233 rb_execution_context_t *ec;
1234 } saved = {
1235 th->top_wrapper, th->top_self, ec->errinfo,
1236 ec,
1237 };
1238 enum ruby_tag_type state;
1239 char *volatile ftptr = 0;
1240 VALUE path;
1241 volatile VALUE saved_path;
1242 volatile VALUE realpath = 0;
1243 VALUE realpaths = get_loaded_features_realpaths(th->vm);
1244 VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
1245 volatile bool reset_ext_config = false;
1246 struct rb_ext_config prev_ext_config;
1247
1248 path = rb_str_encode_ospath(fname);
1249 RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1250 saved_path = path;
1251
1252 EC_PUSH_TAG(ec);
1253 ec->errinfo = Qnil; /* ensure */
1254 th->top_wrapper = 0;
1255 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1256 VALUE handle;
1257 int found;
1258
1259 RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1260 found = search_required(th->vm, path, &saved_path, rb_feature_p);
1261 RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
1262 path = saved_path;
1263
1264 if (found) {
1265 if (!path || !(ftptr = load_lock(th->vm, RSTRING_PTR(path), warn))) {
1266 result = 0;
1267 }
1268 else if (!*ftptr) {
1269 result = TAG_RETURN;
1270 }
1271 else if (found == 's' && run_static_ext_init(th->vm, RSTRING_PTR(path))) {
1272 result = TAG_RETURN;
1273 }
1274 else if (RTEST(rb_hash_aref(realpaths,
1275 realpath = realpath_internal_cached(realpath_map, path)))) {
1276 result = 0;
1277 }
1278 else {
1279 switch (found) {
1280 case 'r':
1281 load_iseq_eval(ec, path);
1282 break;
1283
1284 case 's':
1285 reset_ext_config = true;
1286 ext_config_push(th, &prev_ext_config);
1287 handle = rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
1288 path, VM_BLOCK_HANDLER_NONE, path);
1289 rb_hash_aset(ruby_dln_libmap, path, SVALUE2NUM((SIGNED_VALUE)handle));
1290 break;
1291 }
1292 result = TAG_RETURN;
1293 }
1294 }
1295 }
1296 EC_POP_TAG();
1297
1298 ec = saved.ec;
1299 rb_thread_t *th2 = rb_ec_thread_ptr(ec);
1300 th2->top_self = saved.self;
1301 th2->top_wrapper = saved.wrapper;
1302 if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1303
1304 path = saved_path;
1305 if (ftptr) load_unlock(th2->vm, RSTRING_PTR(path), !state);
1306
1307 if (state) {
1308 if (state == TAG_FATAL || state == TAG_THROW) {
1309 EC_JUMP_TAG(ec, state);
1310 }
1311 else if (exception) {
1312 /* usually state == TAG_RAISE only, except for
1313 * rb_iseq_load_iseq in load_iseq_eval case */
1314 VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
1315 if (!NIL_P(exc)) ec->errinfo = exc;
1316 return TAG_RAISE;
1317 }
1318 else if (state == TAG_RETURN) {
1319 return TAG_RAISE;
1320 }
1321 RB_GC_GUARD(fname);
1322 /* never TAG_RETURN */
1323 return state;
1324 }
1325 if (!NIL_P(ec->errinfo)) {
1326 if (!exception) return TAG_RAISE;
1327 rb_exc_raise(ec->errinfo);
1328 }
1329
1330 if (result == TAG_RETURN) {
1331 rb_provide_feature(th2->vm, path);
1332 VALUE real = realpath;
1333 if (real) {
1334 real = rb_fstring(real);
1335 rb_hash_aset(realpaths, real, Qtrue);
1336 }
1337 }
1338 ec->errinfo = saved.errinfo;
1339
1340 RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1341
1342 return result;
1343}
1344
1345int
1346rb_require_internal_silent(VALUE fname)
1347{
1348 rb_execution_context_t *ec = GET_EC();
1349 return require_internal(ec, fname, 1, false);
1350}
1351
1352int
1353rb_require_internal(VALUE fname)
1354{
1355 rb_execution_context_t *ec = GET_EC();
1356 return require_internal(ec, fname, 1, RTEST(ruby_verbose));
1357}
1358
1359int
1360ruby_require_internal(const char *fname, unsigned int len)
1361{
1362 struct RString fake;
1363 VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
1364 rb_execution_context_t *ec = GET_EC();
1365 int result = require_internal(ec, str, 0, RTEST(ruby_verbose));
1366 rb_set_errinfo(Qnil);
1367 return result == TAG_RETURN ? 1 : result ? -1 : 0;
1368}
1369
1370VALUE
1372{
1373 return rb_require_string_internal(FilePathValue(fname), false);
1374}
1375
1376static VALUE
1377rb_require_string_internal(VALUE fname, bool resurrect)
1378{
1379 rb_execution_context_t *ec = GET_EC();
1380 int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
1381
1382 if (result > TAG_RETURN) {
1383 EC_JUMP_TAG(ec, result);
1384 }
1385 if (result < 0) {
1386 if (resurrect) fname = rb_str_resurrect(fname);
1387 load_failed(fname);
1388 }
1389
1390 return RBOOL(result);
1391}
1392
1393VALUE
1394rb_require(const char *fname)
1395{
1396 struct RString fake;
1397 VALUE str = rb_setup_fake_str(&fake, fname, strlen(fname), 0);
1398 return rb_require_string_internal(str, true);
1399}
1400
1401static int
1402register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1403{
1404 const char *name = (char *)*key;
1405 if (existing) {
1406 /* already registered */
1407 rb_warn("%s is already registered", name);
1408 }
1409 else {
1410 *value = (st_data_t)init;
1411 }
1412 return ST_CONTINUE;
1413}
1414
1415// Private API for statically linked extensions.
1416// Used with the ext/Setup file, the --with-setup and
1417// --with-static-linked-ext configuration option, etc.
1418void
1419ruby_init_ext(const char *name, void (*init)(void))
1420{
1421 st_table *inits_table;
1422 rb_vm_t *vm = GET_VM();
1423
1424 if (feature_provided(vm, name, 0))
1425 return;
1426
1427 inits_table = vm->static_ext_inits;
1428 if (!inits_table) {
1429 inits_table = st_init_strtable();
1430 vm->static_ext_inits = inits_table;
1431 }
1432 st_update(inits_table, (st_data_t)name, register_init_ext, (st_data_t)init);
1433}
1434
1435/*
1436 * call-seq:
1437 * mod.autoload(const, filename) -> nil
1438 *
1439 * Registers _filename_ to be loaded (using Kernel::require)
1440 * the first time that _const_ (which may be a String or
1441 * a symbol) is accessed in the namespace of _mod_.
1442 *
1443 * module A
1444 * end
1445 * A.autoload(:B, "b")
1446 * A::B.doit # autoloads "b"
1447 *
1448 * If _const_ in _mod_ is defined as autoload, the file name to be
1449 * loaded is replaced with _filename_. If _const_ is defined but not
1450 * as autoload, does nothing.
1451 */
1452
1453static VALUE
1454rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1455{
1456 ID id = rb_to_id(sym);
1457
1458 FilePathValue(file);
1459 rb_autoload_str(mod, id, file);
1460 return Qnil;
1461}
1462
1463/*
1464 * call-seq:
1465 * mod.autoload?(name, inherit=true) -> String or nil
1466 *
1467 * Returns _filename_ to be loaded if _name_ is registered as
1468 * +autoload+ in the namespace of _mod_ or one of its ancestors.
1469 *
1470 * module A
1471 * end
1472 * A.autoload(:B, "b")
1473 * A.autoload?(:B) #=> "b"
1474 *
1475 * If +inherit+ is false, the lookup only checks the autoloads in the receiver:
1476 *
1477 * class A
1478 * autoload :CONST, "const.rb"
1479 * end
1480 *
1481 * class B < A
1482 * end
1483 *
1484 * B.autoload?(:CONST) #=> "const.rb", found in A (ancestor)
1485 * B.autoload?(:CONST, false) #=> nil, not found in B itself
1486 *
1487 */
1488
1489static VALUE
1490rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
1491{
1492 int recur = (rb_check_arity(argc, 1, 2) == 1) ? TRUE : RTEST(argv[1]);
1493 VALUE sym = argv[0];
1494
1495 ID id = rb_check_id(&sym);
1496 if (!id) {
1497 return Qnil;
1498 }
1499 return rb_autoload_at_p(mod, id, recur);
1500}
1501
1502/*
1503 * call-seq:
1504 * autoload(const, filename) -> nil
1505 *
1506 * Registers _filename_ to be loaded (using Kernel::require)
1507 * the first time that _const_ (which may be a String or
1508 * a symbol) is accessed.
1509 *
1510 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1511 *
1512 * If _const_ is defined as autoload, the file name to be loaded is
1513 * replaced with _filename_. If _const_ is defined but not as
1514 * autoload, does nothing.
1515 */
1516
1517static VALUE
1518rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1519{
1520 VALUE klass = rb_class_real(rb_vm_cbase());
1521 if (!klass) {
1522 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1523 }
1524 return rb_mod_autoload(klass, sym, file);
1525}
1526
1527/*
1528 * call-seq:
1529 * autoload?(name, inherit=true) -> String or nil
1530 *
1531 * Returns _filename_ to be loaded if _name_ is registered as
1532 * +autoload+.
1533 *
1534 * autoload(:B, "b")
1535 * autoload?(:B) #=> "b"
1536 */
1537
1538static VALUE
1539rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
1540{
1541 /* use rb_vm_cbase() as same as rb_f_autoload. */
1542 VALUE klass = rb_vm_cbase();
1543 if (NIL_P(klass)) {
1544 return Qnil;
1545 }
1546 return rb_mod_autoload_p(argc, argv, klass);
1547}
1548
1549void *
1550rb_ext_resolve_symbol(const char* fname, const char* symbol)
1551{
1552 VALUE handle;
1553 VALUE resolved;
1554 VALUE path;
1555 char *ext;
1556 VALUE fname_str = rb_str_new_cstr(fname);
1557
1558 resolved = rb_resolve_feature_path((VALUE)NULL, fname_str);
1559 if (NIL_P(resolved)) {
1560 ext = strrchr(fname, '.');
1561 if (!ext || !IS_SOEXT(ext)) {
1562 rb_str_cat_cstr(fname_str, ".so");
1563 }
1564 if (rb_feature_p(GET_VM(), fname, 0, FALSE, FALSE, 0)) {
1565 return dln_symbol(NULL, symbol);
1566 }
1567 return NULL;
1568 }
1569 if (RARRAY_LEN(resolved) != 2 || rb_ary_entry(resolved, 0) != ID2SYM(rb_intern("so"))) {
1570 return NULL;
1571 }
1572 path = rb_ary_entry(resolved, 1);
1573 handle = rb_hash_lookup(ruby_dln_libmap, path);
1574 if (NIL_P(handle)) {
1575 return NULL;
1576 }
1577 return dln_symbol((void *)NUM2SVALUE(handle), symbol);
1578}
1579
1580void
1581Init_load(void)
1582{
1583 rb_vm_t *vm = GET_VM();
1584 static const char var_load_path[] = "$:";
1585 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1586
1587 rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
1588 rb_alias_variable(rb_intern_const("$-I"), id_load_path);
1589 rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
1590 vm->load_path = rb_ary_new();
1591 vm->expanded_load_path = rb_ary_hidden_new(0);
1592 vm->load_path_snapshot = rb_ary_hidden_new(0);
1593 vm->load_path_check_cache = 0;
1594 rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
1595
1596 rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
1597 rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0);
1598 vm->loaded_features = rb_ary_new();
1599 vm->loaded_features_snapshot = rb_ary_hidden_new(0);
1600 vm->loaded_features_index = st_init_numtable();
1601 vm->loaded_features_realpaths = rb_hash_new();
1602 rb_obj_hide(vm->loaded_features_realpaths);
1603 vm->loaded_features_realpath_map = rb_hash_new();
1604 rb_obj_hide(vm->loaded_features_realpath_map);
1605
1606 rb_define_global_function("load", rb_f_load, -1);
1608 rb_define_global_function("require_relative", rb_f_require_relative, 1);
1609 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1610 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
1611 rb_define_global_function("autoload", rb_f_autoload, 2);
1612 rb_define_global_function("autoload?", rb_f_autoload_p, -1);
1613
1614 ruby_dln_libmap = rb_hash_new_with_size(0);
1615 rb_gc_register_mark_object(ruby_dln_libmap);
1616}
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_extend_object(VALUE obj, VALUE module)
Extend the object with the module.
Definition eval.c:1713
VALUE rb_module_new(void)
Creates a new, anonymous module.
Definition class.c:1066
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:2622
#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 rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#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.
#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:1344
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1342
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:423
void rb_loaderror(const char *fmt,...)
Raises an instance of rb_eLoadError.
Definition error.c:3474
void rb_warning(const char *fmt,...)
Issues a warning.
Definition error.c:454
VALUE rb_cModule
Module class.
Definition object.c:65
VALUE rb_class_real(VALUE klass)
Finds a "real" class.
Definition object.c:205
VALUE rb_obj_clone(VALUE obj)
Produces a shallow copy of the given object.
Definition object.c:486
Encoding relates APIs.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:280
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:1013
void rb_ext_ractor_safe(bool flag)
Asserts that the extension library that calls this function is aware of Ractor.
Definition load.c:1214
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
Definition load.c:1371
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:849
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:841
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:1550
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:3411
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1532
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:1802
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:3733
#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:3001
#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
#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
void rb_alias_variable(ID dst, ID src)
Aliases a global variable.
Definition variable.c:977
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:1095
ID rb_to_id(VALUE str)
Definition string.c:12034
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
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:535
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:366
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:161
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:378
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
struct pm_parser pm_parser_t
The parser used to parse Ruby source.
Definition parser.h:259
#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
VALUE rb_require(const char *feature)
Identical to rb_require_string(), except it takes C's string instead of Ruby's.
Definition load.c:1394
#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
The options that can be passed to the parser.
Definition options.h:30
A generic string type that can have various ownership semantics.
Definition pm_string.h:30
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:432