1 /*
2 * load methods from eval.c
3 */
4
5 #include "ruby/encoding.h"
6 #include "ruby/util.h"
7 #include "internal.h"
8 #include "dln.h"
9 #include "eval_intern.h"
10 #include "probes.h"
11 #include "iseq.h"
12
13 static VALUE ruby_dln_librefs;
14
15 #define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
16 #define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
17 #ifdef DLEXT2
18 #define IS_DLEXT(e) (strcmp((e), DLEXT) == 0 || strcmp((e), DLEXT2) == 0)
19 #else
20 #define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
21 #endif
22
23 static const char *const loadable_ext[] = {
24 ".rb", DLEXT,
25 #ifdef DLEXT2
26 DLEXT2,
27 #endif
28 0
29 };
30
31 VALUE
rb_get_load_path(void)32 rb_get_load_path(void)
33 {
34 VALUE load_path = GET_VM()->load_path;
35 return load_path;
36 }
37
38 enum expand_type {
39 EXPAND_ALL,
40 EXPAND_RELATIVE,
41 EXPAND_HOME,
42 EXPAND_NON_CACHE
43 };
44
45 /* Construct expanded load path and store it to cache.
46 We rebuild load path partially if the cache is invalid.
47 We don't cache non string object and expand it every time. We ensure that
48 string objects in $LOAD_PATH are frozen.
49 */
50 static void
rb_construct_expanded_load_path(enum expand_type type,int * has_relative,int * has_non_cache)51 rb_construct_expanded_load_path(enum expand_type type, int *has_relative, int *has_non_cache)
52 {
53 rb_vm_t *vm = GET_VM();
54 VALUE load_path = vm->load_path;
55 VALUE expanded_load_path = vm->expanded_load_path;
56 VALUE ary;
57 long i;
58 int level = rb_safe_level();
59
60 ary = rb_ary_tmp_new(RARRAY_LEN(load_path));
61 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
62 VALUE path, as_str, expanded_path;
63 int is_string, non_cache;
64 char *as_cstr;
65 as_str = path = RARRAY_AREF(load_path, i);
66 is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0;
67 non_cache = !is_string ? 1 : 0;
68 as_str = rb_get_path_check_to_string(path, level);
69 as_cstr = RSTRING_PTR(as_str);
70
71 if (!non_cache) {
72 if ((type == EXPAND_RELATIVE &&
73 rb_is_absolute_path(as_cstr)) ||
74 (type == EXPAND_HOME &&
75 (!as_cstr[0] || as_cstr[0] != '~')) ||
76 (type == EXPAND_NON_CACHE)) {
77 /* Use cached expanded path. */
78 rb_ary_push(ary, RARRAY_AREF(expanded_load_path, i));
79 continue;
80 }
81 }
82 if (!*has_relative && !rb_is_absolute_path(as_cstr))
83 *has_relative = 1;
84 if (!*has_non_cache && non_cache)
85 *has_non_cache = 1;
86 /* Freeze only string object. We expand other objects every time. */
87 if (is_string)
88 rb_str_freeze(path);
89 as_str = rb_get_path_check_convert(path, as_str, level);
90 expanded_path = rb_check_realpath(Qnil, as_str);
91 if (NIL_P(expanded_path)) expanded_path = as_str;
92 rb_ary_push(ary, rb_fstring(expanded_path));
93 }
94 rb_obj_freeze(ary);
95 vm->expanded_load_path = ary;
96 rb_ary_replace(vm->load_path_snapshot, vm->load_path);
97 }
98
99 VALUE
rb_get_expanded_load_path(void)100 rb_get_expanded_load_path(void)
101 {
102 rb_vm_t *vm = GET_VM();
103 const VALUE non_cache = Qtrue;
104
105 if (!rb_ary_shared_with_p(vm->load_path_snapshot, vm->load_path)) {
106 /* The load path was modified. Rebuild the expanded load path. */
107 int has_relative = 0, has_non_cache = 0;
108 rb_construct_expanded_load_path(EXPAND_ALL, &has_relative, &has_non_cache);
109 if (has_relative) {
110 vm->load_path_check_cache = rb_dir_getwd_ospath();
111 }
112 else if (has_non_cache) {
113 /* Non string object. */
114 vm->load_path_check_cache = non_cache;
115 }
116 else {
117 vm->load_path_check_cache = 0;
118 }
119 }
120 else if (vm->load_path_check_cache == non_cache) {
121 int has_relative = 1, has_non_cache = 1;
122 /* Expand only non-cacheable objects. */
123 rb_construct_expanded_load_path(EXPAND_NON_CACHE,
124 &has_relative, &has_non_cache);
125 }
126 else if (vm->load_path_check_cache) {
127 int has_relative = 1, has_non_cache = 1;
128 VALUE cwd = rb_dir_getwd_ospath();
129 if (!rb_str_equal(vm->load_path_check_cache, cwd)) {
130 /* Current working directory or filesystem encoding was changed.
131 Expand relative load path and non-cacheable objects again. */
132 vm->load_path_check_cache = cwd;
133 rb_construct_expanded_load_path(EXPAND_RELATIVE,
134 &has_relative, &has_non_cache);
135 }
136 else {
137 /* Expand only tilde (User HOME) and non-cacheable objects. */
138 rb_construct_expanded_load_path(EXPAND_HOME,
139 &has_relative, &has_non_cache);
140 }
141 }
142 return vm->expanded_load_path;
143 }
144
145 static VALUE
load_path_getter(ID id,rb_vm_t * vm)146 load_path_getter(ID id, rb_vm_t *vm)
147 {
148 return vm->load_path;
149 }
150
151 static VALUE
get_loaded_features(void)152 get_loaded_features(void)
153 {
154 return GET_VM()->loaded_features;
155 }
156
157 static void
reset_loaded_features_snapshot(void)158 reset_loaded_features_snapshot(void)
159 {
160 rb_vm_t *vm = GET_VM();
161 rb_ary_replace(vm->loaded_features_snapshot, vm->loaded_features);
162 }
163
164 static struct st_table *
get_loaded_features_index_raw(void)165 get_loaded_features_index_raw(void)
166 {
167 return GET_VM()->loaded_features_index;
168 }
169
170 static st_table *
get_loading_table(void)171 get_loading_table(void)
172 {
173 return GET_VM()->loading_table;
174 }
175
176 static st_data_t
feature_key(const char * str,size_t len)177 feature_key(const char *str, size_t len)
178 {
179 return st_hash(str, len, 0xfea7009e);
180 }
181
182 static void
features_index_add_single(const char * str,size_t len,VALUE offset)183 features_index_add_single(const char* str, size_t len, VALUE offset)
184 {
185 struct st_table *features_index;
186 VALUE this_feature_index = Qnil;
187 st_data_t short_feature_key;
188
189 Check_Type(offset, T_FIXNUM);
190 short_feature_key = feature_key(str, len);
191
192 features_index = get_loaded_features_index_raw();
193 st_lookup(features_index, short_feature_key, (st_data_t *)&this_feature_index);
194
195 if (NIL_P(this_feature_index)) {
196 st_insert(features_index, short_feature_key, (st_data_t)offset);
197 }
198 else if (RB_TYPE_P(this_feature_index, T_FIXNUM)) {
199 VALUE feature_indexes[2];
200 feature_indexes[0] = this_feature_index;
201 feature_indexes[1] = offset;
202 this_feature_index = (VALUE)xcalloc(1, sizeof(struct RArray));
203 RBASIC(this_feature_index)->flags = T_ARRAY; /* fake VALUE, do not mark/sweep */
204 rb_ary_cat(this_feature_index, feature_indexes, numberof(feature_indexes));
205 st_insert(features_index, short_feature_key, (st_data_t)this_feature_index);
206 }
207 else {
208 Check_Type(this_feature_index, T_ARRAY);
209 rb_ary_push(this_feature_index, offset);
210 }
211 }
212
213 /* Add to the loaded-features index all the required entries for
214 `feature`, located at `offset` in $LOADED_FEATURES. We add an
215 index entry at each string `short_feature` for which
216 feature == "#{prefix}#{short_feature}#{ext}"
217 where `ext` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
218 or ends in '/'. This maintains the invariant that `rb_feature_p()`
219 relies on for its fast lookup.
220 */
221 static void
features_index_add(VALUE feature,VALUE offset)222 features_index_add(VALUE feature, VALUE offset)
223 {
224 const char *feature_str, *feature_end, *ext, *p;
225
226 feature_str = StringValuePtr(feature);
227 feature_end = feature_str + RSTRING_LEN(feature);
228
229 for (ext = feature_end; ext > feature_str; ext--)
230 if (*ext == '.' || *ext == '/')
231 break;
232 if (*ext != '.')
233 ext = NULL;
234 /* Now `ext` points to the only string matching %r{^\.[^./]*$} that is
235 at the end of `feature`, or is NULL if there is no such string. */
236
237 p = ext ? ext : feature_end;
238 while (1) {
239 p--;
240 while (p >= feature_str && *p != '/')
241 p--;
242 if (p < feature_str)
243 break;
244 /* Now *p == '/'. We reach this point for every '/' in `feature`. */
245 features_index_add_single(p + 1, feature_end - p - 1, offset);
246 if (ext) {
247 features_index_add_single(p + 1, ext - p - 1, offset);
248 }
249 }
250 features_index_add_single(feature_str, feature_end - feature_str, offset);
251 if (ext) {
252 features_index_add_single(feature_str, ext - feature_str, offset);
253 }
254 }
255
256 static int
loaded_features_index_clear_i(st_data_t key,st_data_t val,st_data_t arg)257 loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
258 {
259 VALUE obj = (VALUE)val;
260 if (!SPECIAL_CONST_P(obj)) {
261 rb_ary_free(obj);
262 ruby_sized_xfree((void *)obj, sizeof(struct RArray));
263 }
264 return ST_DELETE;
265 }
266
267 static st_table *
get_loaded_features_index(void)268 get_loaded_features_index(void)
269 {
270 VALUE features;
271 int i;
272 rb_vm_t *vm = GET_VM();
273
274 if (!rb_ary_shared_with_p(vm->loaded_features_snapshot, vm->loaded_features)) {
275 /* The sharing was broken; something (other than us in rb_provide_feature())
276 modified loaded_features. Rebuild the index. */
277 st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
278 features = vm->loaded_features;
279 for (i = 0; i < RARRAY_LEN(features); i++) {
280 VALUE entry, as_str;
281 as_str = entry = rb_ary_entry(features, i);
282 StringValue(as_str);
283 as_str = rb_fstring(rb_str_freeze(as_str));
284 if (as_str != entry)
285 rb_ary_store(features, i, as_str);
286 features_index_add(as_str, INT2FIX(i));
287 }
288 reset_loaded_features_snapshot();
289 }
290 return vm->loaded_features_index;
291 }
292
293 /* This searches `load_path` for a value such that
294 name == "#{load_path[i]}/#{feature}"
295 if `feature` is a suffix of `name`, or otherwise
296 name == "#{load_path[i]}/#{feature}#{ext}"
297 for an acceptable string `ext`. It returns
298 `load_path[i].to_str` if found, else 0.
299
300 If type is 's', then `ext` is acceptable only if IS_DLEXT(ext);
301 if 'r', then only if IS_RBEXT(ext); otherwise `ext` may be absent
302 or have any value matching `%r{^\.[^./]*$}`.
303 */
304 static VALUE
loaded_feature_path(const char * name,long vlen,const char * feature,long len,int type,VALUE load_path)305 loaded_feature_path(const char *name, long vlen, const char *feature, long len,
306 int type, VALUE load_path)
307 {
308 long i;
309 long plen;
310 const char *e;
311
312 if (vlen < len+1) return 0;
313 if (strchr(feature, '.') && !strncmp(name+(vlen-len), feature, len)) {
314 plen = vlen - len;
315 }
316 else {
317 for (e = name + vlen; name != e && *e != '.' && *e != '/'; --e);
318 if (*e != '.' ||
319 e-name < len ||
320 strncmp(e-len, feature, len))
321 return 0;
322 plen = e - name - len;
323 }
324 if (plen > 0 && name[plen-1] != '/') {
325 return 0;
326 }
327 if (type == 's' ? !IS_DLEXT(&name[plen+len]) :
328 type == 'r' ? !IS_RBEXT(&name[plen+len]) :
329 0) {
330 return 0;
331 }
332 /* Now name == "#{prefix}/#{feature}#{ext}" where ext is acceptable
333 (possibly empty) and prefix is some string of length plen. */
334
335 if (plen > 0) --plen; /* exclude '.' */
336 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
337 VALUE p = RARRAY_AREF(load_path, i);
338 const char *s = StringValuePtr(p);
339 long n = RSTRING_LEN(p);
340
341 if (n != plen) continue;
342 if (n && strncmp(name, s, n)) continue;
343 return p;
344 }
345 return 0;
346 }
347
348 struct loaded_feature_searching {
349 const char *name;
350 long len;
351 int type;
352 VALUE load_path;
353 const char *result;
354 };
355
356 static int
loaded_feature_path_i(st_data_t v,st_data_t b,st_data_t f)357 loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
358 {
359 const char *s = (const char *)v;
360 struct loaded_feature_searching *fp = (struct loaded_feature_searching *)f;
361 VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len,
362 fp->type, fp->load_path);
363 if (!p) return ST_CONTINUE;
364 fp->result = s;
365 return ST_STOP;
366 }
367
368 static int
rb_feature_p(const char * feature,const char * ext,int rb,int expanded,const char ** fn)369 rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn)
370 {
371 VALUE features, this_feature_index = Qnil, v, p, load_path = 0;
372 const char *f, *e;
373 long i, len, elen, n;
374 st_table *loading_tbl, *features_index;
375 st_data_t data;
376 st_data_t key;
377 int type;
378
379 if (fn) *fn = 0;
380 if (ext) {
381 elen = strlen(ext);
382 len = strlen(feature) - elen;
383 type = rb ? 'r' : 's';
384 }
385 else {
386 len = strlen(feature);
387 elen = 0;
388 type = 0;
389 }
390 features = get_loaded_features();
391 features_index = get_loaded_features_index();
392
393 key = feature_key(feature, strlen(feature));
394 st_lookup(features_index, key, (st_data_t *)&this_feature_index);
395 /* We search `features` for an entry such that either
396 "#{features[i]}" == "#{load_path[j]}/#{feature}#{e}"
397 for some j, or
398 "#{features[i]}" == "#{feature}#{e}"
399 Here `e` is an "allowed" extension -- either empty or one
400 of the extensions accepted by IS_RBEXT, IS_SOEXT, or
401 IS_DLEXT. Further, if `ext && rb` then `IS_RBEXT(e)`,
402 and if `ext && !rb` then `IS_SOEXT(e) || IS_DLEXT(e)`.
403
404 If `expanded`, then only the latter form (without load_path[j])
405 is accepted. Otherwise either form is accepted, *unless* `ext`
406 is false and an otherwise-matching entry of the first form is
407 preceded by an entry of the form
408 "#{features[i2]}" == "#{load_path[j2]}/#{feature}#{e2}"
409 where `e2` matches %r{^\.[^./]*$} but is not an allowed extension.
410 After a "distractor" entry of this form, only entries of the
411 form "#{feature}#{e}" are accepted.
412
413 In `rb_provide_feature()` and `get_loaded_features_index()` we
414 maintain an invariant that the array `this_feature_index` will
415 point to every entry in `features` which has the form
416 "#{prefix}#{feature}#{e}"
417 where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
418 or ends in '/'. This includes both match forms above, as well
419 as any distractors, so we may ignore all other entries in `features`.
420 */
421 if (!NIL_P(this_feature_index)) {
422 for (i = 0; ; i++) {
423 VALUE entry;
424 long index;
425 if (RB_TYPE_P(this_feature_index, T_ARRAY)) {
426 if (i >= RARRAY_LEN(this_feature_index)) break;
427 entry = RARRAY_AREF(this_feature_index, i);
428 }
429 else {
430 if (i > 0) break;
431 entry = this_feature_index;
432 }
433 index = FIX2LONG(entry);
434
435 v = RARRAY_AREF(features, index);
436 f = StringValuePtr(v);
437 if ((n = RSTRING_LEN(v)) < len) continue;
438 if (strncmp(f, feature, len) != 0) {
439 if (expanded) continue;
440 if (!load_path) load_path = rb_get_expanded_load_path();
441 if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
442 continue;
443 expanded = 1;
444 f += RSTRING_LEN(p) + 1;
445 }
446 if (!*(e = f + len)) {
447 if (ext) continue;
448 return 'u';
449 }
450 if (*e != '.') continue;
451 if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
452 return 's';
453 }
454 if ((rb || !ext) && (IS_RBEXT(e))) {
455 return 'r';
456 }
457 }
458 }
459
460 loading_tbl = get_loading_table();
461 f = 0;
462 if (!expanded) {
463 struct loaded_feature_searching fs;
464 fs.name = feature;
465 fs.len = len;
466 fs.type = type;
467 fs.load_path = load_path ? load_path : rb_get_expanded_load_path();
468 fs.result = 0;
469 st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
470 if ((f = fs.result) != 0) {
471 if (fn) *fn = f;
472 goto loading;
473 }
474 }
475 if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
476 if (fn) *fn = (const char*)data;
477 loading:
478 if (!ext) return 'u';
479 return !IS_RBEXT(ext) ? 's' : 'r';
480 }
481 else {
482 VALUE bufstr;
483 char *buf;
484 static const char so_ext[][4] = {
485 ".so", ".o",
486 };
487
488 if (ext && *ext) return 0;
489 bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN);
490 buf = RSTRING_PTR(bufstr);
491 MEMCPY(buf, feature, char, len);
492 for (i = 0; (e = loadable_ext[i]) != 0; i++) {
493 strlcpy(buf + len, e, DLEXT_MAXLEN + 1);
494 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
495 rb_str_resize(bufstr, 0);
496 if (fn) *fn = (const char*)data;
497 return i ? 's' : 'r';
498 }
499 }
500 for (i = 0; i < numberof(so_ext); i++) {
501 strlcpy(buf + len, so_ext[i], DLEXT_MAXLEN + 1);
502 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
503 rb_str_resize(bufstr, 0);
504 if (fn) *fn = (const char*)data;
505 return 's';
506 }
507 }
508 rb_str_resize(bufstr, 0);
509 }
510 return 0;
511 }
512
513 int
rb_provided(const char * feature)514 rb_provided(const char *feature)
515 {
516 return rb_feature_provided(feature, 0);
517 }
518
519 int
rb_feature_provided(const char * feature,const char ** loading)520 rb_feature_provided(const char *feature, const char **loading)
521 {
522 const char *ext = strrchr(feature, '.');
523 VALUE fullpath = 0;
524
525 if (*feature == '.' &&
526 (feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) {
527 fullpath = rb_file_expand_path_fast(rb_get_path(rb_str_new2(feature)), Qnil);
528 feature = RSTRING_PTR(fullpath);
529 }
530 if (ext && !strchr(ext, '/')) {
531 if (IS_RBEXT(ext)) {
532 if (rb_feature_p(feature, ext, TRUE, FALSE, loading)) return TRUE;
533 return FALSE;
534 }
535 else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
536 if (rb_feature_p(feature, ext, FALSE, FALSE, loading)) return TRUE;
537 return FALSE;
538 }
539 }
540 if (rb_feature_p(feature, 0, TRUE, FALSE, loading))
541 return TRUE;
542 RB_GC_GUARD(fullpath);
543 return FALSE;
544 }
545
546 static void
rb_provide_feature(VALUE feature)547 rb_provide_feature(VALUE feature)
548 {
549 VALUE features;
550
551 features = get_loaded_features();
552 if (OBJ_FROZEN(features)) {
553 rb_raise(rb_eRuntimeError,
554 "$LOADED_FEATURES is frozen; cannot append feature");
555 }
556 rb_str_freeze(feature);
557
558 rb_ary_push(features, rb_fstring(feature));
559 features_index_add(feature, INT2FIX(RARRAY_LEN(features)-1));
560 reset_loaded_features_snapshot();
561 }
562
563 void
rb_provide(const char * feature)564 rb_provide(const char *feature)
565 {
566 rb_provide_feature(rb_fstring_cstr(feature));
567 }
568
569 NORETURN(static void load_failed(VALUE));
570
571 static int
rb_load_internal0(rb_execution_context_t * ec,VALUE fname,int wrap)572 rb_load_internal0(rb_execution_context_t *ec, VALUE fname, int wrap)
573 {
574 enum ruby_tag_type state;
575 rb_thread_t *th = rb_ec_thread_ptr(ec);
576 volatile VALUE wrapper = th->top_wrapper;
577 volatile VALUE self = th->top_self;
578 #if !defined __GNUC__
579 rb_thread_t *volatile th0 = th;
580 #endif
581
582 th->ec->errinfo = Qnil; /* ensure */
583
584 if (!wrap) {
585 th->top_wrapper = 0;
586 }
587 else {
588 /* load in anonymous module as toplevel */
589 th->top_self = rb_obj_clone(rb_vm_top_self());
590 th->top_wrapper = rb_module_new();
591 rb_extend_object(th->top_self, th->top_wrapper);
592 }
593
594 EC_PUSH_TAG(th->ec);
595 state = EC_EXEC_TAG();
596 if (state == TAG_NONE) {
597 rb_ast_t *ast;
598 const rb_iseq_t *iseq;
599
600 if ((iseq = rb_iseq_load_iseq(fname)) != NULL) {
601 /* OK */
602 }
603 else {
604 VALUE parser = rb_parser_new();
605 rb_parser_set_context(parser, NULL, FALSE);
606 ast = (rb_ast_t *)rb_parser_load_file(parser, fname);
607 iseq = rb_iseq_new_top(&ast->body, rb_fstring_lit("<top (required)>"),
608 fname, rb_realpath_internal(Qnil, fname, 1), NULL);
609 rb_ast_dispose(ast);
610 }
611 rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
612 rb_iseq_eval(iseq);
613 }
614 EC_POP_TAG();
615
616 #if !defined __GNUC__
617 th = th0;
618 fname = RB_GC_GUARD(fname);
619 #endif
620 th->top_self = self;
621 th->top_wrapper = wrapper;
622
623 if (state) {
624 /* usually state == TAG_RAISE only, except for
625 * rb_iseq_load_iseq case */
626 VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef);
627 if (NIL_P(exc)) return state;
628 th->ec->errinfo = exc;
629 return TAG_RAISE;
630 }
631
632 if (!NIL_P(th->ec->errinfo)) {
633 /* exception during load */
634 return TAG_RAISE;
635 }
636 return state;
637 }
638
639 static void
rb_load_internal(VALUE fname,int wrap)640 rb_load_internal(VALUE fname, int wrap)
641 {
642 rb_execution_context_t *ec = GET_EC();
643 int state = rb_load_internal0(ec, fname, wrap);
644 if (state) {
645 if (state == TAG_RAISE) rb_exc_raise(ec->errinfo);
646 EC_JUMP_TAG(ec, state);
647 }
648 }
649
650 static VALUE
file_to_load(VALUE fname)651 file_to_load(VALUE fname)
652 {
653 VALUE tmp = rb_find_file(FilePathValue(fname));
654 if (!tmp) load_failed(fname);
655 return tmp;
656 }
657
658 void
rb_load(VALUE fname,int wrap)659 rb_load(VALUE fname, int wrap)
660 {
661 rb_load_internal(file_to_load(fname), wrap);
662 }
663
664 void
rb_load_protect(VALUE fname,int wrap,int * pstate)665 rb_load_protect(VALUE fname, int wrap, int *pstate)
666 {
667 enum ruby_tag_type state;
668 volatile VALUE path = 0;
669
670 EC_PUSH_TAG(GET_EC());
671 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
672 path = file_to_load(fname);
673 }
674 EC_POP_TAG();
675
676 if (state == TAG_NONE) state = rb_load_internal0(GET_EC(), path, wrap);
677 if (state != TAG_NONE) *pstate = state;
678 }
679
680 /*
681 * call-seq:
682 * load(filename, wrap=false) -> true
683 *
684 * Loads and executes the Ruby
685 * program in the file _filename_. If the filename does not
686 * resolve to an absolute path, the file is searched for in the library
687 * directories listed in <code>$:</code>. If the optional _wrap_
688 * parameter is +true+, the loaded script will be executed
689 * under an anonymous module, protecting the calling program's global
690 * namespace. In no circumstance will any local variables in the loaded
691 * file be propagated to the loading environment.
692 */
693
694 static VALUE
rb_f_load(int argc,VALUE * argv)695 rb_f_load(int argc, VALUE *argv)
696 {
697 VALUE fname, wrap, path, orig_fname;
698
699 rb_scan_args(argc, argv, "11", &fname, &wrap);
700
701 orig_fname = rb_get_path_check_to_string(fname, rb_safe_level());
702 fname = rb_str_encode_ospath(orig_fname);
703 RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
704
705 path = rb_find_file(fname);
706 if (!path) {
707 if (!rb_file_load_ok(RSTRING_PTR(fname)))
708 load_failed(orig_fname);
709 path = fname;
710 }
711 rb_load_internal(path, RTEST(wrap));
712
713 RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
714
715 return Qtrue;
716 }
717
718 static char *
load_lock(const char * ftptr)719 load_lock(const char *ftptr)
720 {
721 st_data_t data;
722 st_table *loading_tbl = get_loading_table();
723
724 if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
725 /* partial state */
726 ftptr = ruby_strdup(ftptr);
727 data = (st_data_t)rb_thread_shield_new();
728 st_insert(loading_tbl, (st_data_t)ftptr, data);
729 return (char *)ftptr;
730 }
731 else if (imemo_type_p(data, imemo_memo)) {
732 struct MEMO *memo = MEMO_CAST(data);
733 void (*init)(void) = (void (*)(void))memo->u3.func;
734 data = (st_data_t)rb_thread_shield_new();
735 st_insert(loading_tbl, (st_data_t)ftptr, data);
736 (*init)();
737 return (char *)"";
738 }
739 if (RTEST(ruby_verbose)) {
740 VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
741 rb_backtrace_each(rb_str_append, warning);
742 rb_warning("%"PRIsVALUE, warning);
743 }
744 switch (rb_thread_shield_wait((VALUE)data)) {
745 case Qfalse:
746 case Qnil:
747 return 0;
748 }
749 return (char *)ftptr;
750 }
751
752 static int
release_thread_shield(st_data_t * key,st_data_t * value,st_data_t done,int existing)753 release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing)
754 {
755 VALUE thread_shield = (VALUE)*value;
756 if (!existing) return ST_STOP;
757 if (done) {
758 rb_thread_shield_destroy(thread_shield);
759 /* Delete the entry even if there are waiting threads, because they
760 * won't load the file and won't delete the entry. */
761 }
762 else if (rb_thread_shield_release(thread_shield)) {
763 /* still in-use */
764 return ST_CONTINUE;
765 }
766 xfree((char *)*key);
767 return ST_DELETE;
768 }
769
770 static void
load_unlock(const char * ftptr,int done)771 load_unlock(const char *ftptr, int done)
772 {
773 if (ftptr) {
774 st_data_t key = (st_data_t)ftptr;
775 st_table *loading_tbl = get_loading_table();
776
777 st_update(loading_tbl, key, release_thread_shield, done);
778 }
779 }
780
781
782 /*
783 * call-seq:
784 * require(name) -> true or false
785 *
786 * Loads the given +name+, returning +true+ if successful and +false+ if the
787 * feature is already loaded.
788 *
789 * If the filename does not resolve to an absolute path, it will be searched
790 * for in the directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
791 *
792 * If the filename has the extension ".rb", it is loaded as a source file; if
793 * the extension is ".so", ".o", or ".dll", or the default shared library
794 * extension on the current platform, Ruby loads the shared library as a
795 * Ruby extension. Otherwise, Ruby tries adding ".rb", ".so", and so on
796 * to the name until found. If the file named cannot be found, a LoadError
797 * will be raised.
798 *
799 * For Ruby extensions the filename given may use any shared library
800 * extension. For example, on Linux the socket extension is "socket.so" and
801 * <code>require 'socket.dll'</code> will load the socket extension.
802 *
803 * The absolute path of the loaded file is added to
804 * <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be
805 * loaded again if its path already appears in <code>$"</code>. For example,
806 * <code>require 'a'; require './a'</code> will not load <code>a.rb</code>
807 * again.
808 *
809 * require "my-library.rb"
810 * require "db-driver"
811 *
812 * Any constants or globals within the loaded source file will be available
813 * in the calling program's global namespace. However, local variables will
814 * not be propagated to the loading environment.
815 *
816 */
817
818 VALUE
rb_f_require(VALUE obj,VALUE fname)819 rb_f_require(VALUE obj, VALUE fname)
820 {
821 return rb_require_safe(fname, rb_safe_level());
822 }
823
824 /*
825 * call-seq:
826 * require_relative(string) -> true or false
827 *
828 * Ruby tries to load the library named _string_ relative to the requiring
829 * file's path. If the file's path cannot be determined a LoadError is raised.
830 * If a file is loaded +true+ is returned and false otherwise.
831 */
832 VALUE
rb_f_require_relative(VALUE obj,VALUE fname)833 rb_f_require_relative(VALUE obj, VALUE fname)
834 {
835 VALUE base = rb_current_realfilepath();
836 if (NIL_P(base)) {
837 rb_loaderror("cannot infer basepath");
838 }
839 base = rb_file_dirname(base);
840 return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
841 }
842
843 static int
search_required(VALUE fname,volatile VALUE * path,int safe_level)844 search_required(VALUE fname, volatile VALUE *path, int safe_level)
845 {
846 VALUE tmp;
847 char *ext, *ftptr;
848 int type, ft = 0;
849 const char *loading;
850
851 *path = 0;
852 ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
853 if (ext && !strchr(ext, '/')) {
854 if (IS_RBEXT(ext)) {
855 if (rb_feature_p(ftptr, ext, TRUE, FALSE, &loading)) {
856 if (loading) *path = rb_filesystem_str_new_cstr(loading);
857 return 'r';
858 }
859 if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) {
860 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
861 if (!rb_feature_p(ftptr, ext, TRUE, TRUE, &loading) || loading)
862 *path = tmp;
863 return 'r';
864 }
865 return 0;
866 }
867 else if (IS_SOEXT(ext)) {
868 if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) {
869 if (loading) *path = rb_filesystem_str_new_cstr(loading);
870 return 's';
871 }
872 tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
873 #ifdef DLEXT2
874 OBJ_FREEZE(tmp);
875 if (rb_find_file_ext_safe(&tmp, loadable_ext + 1, safe_level)) {
876 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
877 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
878 *path = tmp;
879 return 's';
880 }
881 #else
882 rb_str_cat2(tmp, DLEXT);
883 OBJ_FREEZE(tmp);
884 if ((tmp = rb_find_file_safe(tmp, safe_level)) != 0) {
885 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
886 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
887 *path = tmp;
888 return 's';
889 }
890 #endif
891 }
892 else if (IS_DLEXT(ext)) {
893 if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) {
894 if (loading) *path = rb_filesystem_str_new_cstr(loading);
895 return 's';
896 }
897 if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) {
898 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
899 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
900 *path = tmp;
901 return 's';
902 }
903 }
904 }
905 else if ((ft = rb_feature_p(ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
906 if (loading) *path = rb_filesystem_str_new_cstr(loading);
907 return 'r';
908 }
909 tmp = fname;
910 type = rb_find_file_ext_safe(&tmp, loadable_ext, safe_level);
911 switch (type) {
912 case 0:
913 if (ft)
914 goto statically_linked;
915 ftptr = RSTRING_PTR(tmp);
916 return rb_feature_p(ftptr, 0, FALSE, TRUE, 0);
917
918 default:
919 if (ft) {
920 statically_linked:
921 if (loading) *path = rb_filesystem_str_new_cstr(loading);
922 return ft;
923 }
924 case 1:
925 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
926 if (rb_feature_p(ftptr, ext, !--type, TRUE, &loading) && !loading)
927 break;
928 *path = tmp;
929 }
930 return type ? 's' : 'r';
931 }
932
933 static void
load_failed(VALUE fname)934 load_failed(VALUE fname)
935 {
936 rb_load_fail(fname, "cannot load such file");
937 }
938
939 static VALUE
load_ext(VALUE path)940 load_ext(VALUE path)
941 {
942 rb_scope_visibility_set(METHOD_VISI_PUBLIC);
943 return (VALUE)dln_load(RSTRING_PTR(path));
944 }
945
946 /*
947 * call-seq:
948 * RubyVM.resolve_feature_path(feature) -> [:rb or :so, path]
949 *
950 * Identifies the file that will be loaded by "require(feature)".
951 * This API is experimental and just for internal.
952 *
953 * RubyVM.resolve_feature_path("set")
954 * #=> [:rb, "/path/to/feature.rb"]
955 */
956
957 VALUE
rb_resolve_feature_path(VALUE klass,VALUE fname)958 rb_resolve_feature_path(VALUE klass, VALUE fname)
959 {
960 VALUE path;
961 int found;
962 VALUE sym;
963
964 fname = rb_get_path_check(fname, 0);
965 path = rb_str_encode_ospath(fname);
966 found = search_required(path, &path, 0);
967
968 switch (found) {
969 case 'r':
970 sym = ID2SYM(rb_intern("rb"));
971 break;
972 case 's':
973 sym = ID2SYM(rb_intern("so"));
974 break;
975 default:
976 load_failed(fname);
977 }
978
979 return rb_ary_new_from_args(2, sym, path);
980 }
981
982 /*
983 * returns
984 * 0: if already loaded (false)
985 * 1: successfully loaded (true)
986 * <0: not found (LoadError)
987 * >1: exception
988 */
989 int
rb_require_internal(VALUE fname,int safe)990 rb_require_internal(VALUE fname, int safe)
991 {
992 volatile int result = -1;
993 rb_execution_context_t *ec = GET_EC();
994 volatile VALUE errinfo = ec->errinfo;
995 enum ruby_tag_type state;
996 struct {
997 int safe;
998 } volatile saved;
999 char *volatile ftptr = 0;
1000 VALUE path;
1001
1002 fname = rb_get_path_check(fname, safe);
1003 path = rb_str_encode_ospath(fname);
1004 RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1005
1006 EC_PUSH_TAG(ec);
1007 saved.safe = rb_safe_level();
1008 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1009 long handle;
1010 int found;
1011
1012 rb_set_safe_level_force(0);
1013
1014 RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1015 found = search_required(path, &path, safe);
1016 RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
1017
1018 if (found) {
1019 if (!path || !(path = rb_fstring(path), ftptr = load_lock(RSTRING_PTR(path)))) {
1020 result = 0;
1021 }
1022 else if (!*ftptr) {
1023 rb_provide_feature(path);
1024 result = TAG_RETURN;
1025 }
1026 else {
1027 switch (found) {
1028 case 'r':
1029 state = rb_load_internal0(ec, path, 0);
1030 break;
1031
1032 case 's':
1033 handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
1034 path, VM_BLOCK_HANDLER_NONE, path);
1035 rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
1036 break;
1037 }
1038 if (!state) {
1039 rb_provide_feature(path);
1040 result = TAG_RETURN;
1041 }
1042 }
1043 }
1044 }
1045 EC_POP_TAG();
1046 load_unlock(ftptr, !state);
1047
1048 rb_set_safe_level_force(saved.safe);
1049 if (state) {
1050 RB_GC_GUARD(fname);
1051 /* never TAG_RETURN */
1052 return state;
1053 }
1054
1055 ec->errinfo = errinfo;
1056
1057 RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1058
1059 return result;
1060 }
1061
1062 int
ruby_require_internal(const char * fname,unsigned int len)1063 ruby_require_internal(const char *fname, unsigned int len)
1064 {
1065 struct RString fake;
1066 VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
1067 int result = rb_require_internal(str, 0);
1068 rb_set_errinfo(Qnil);
1069 return result == TAG_RETURN ? 1 : result ? -1 : 0;
1070 }
1071
1072 VALUE
rb_require_safe(VALUE fname,int safe)1073 rb_require_safe(VALUE fname, int safe)
1074 {
1075 int result = rb_require_internal(fname, safe);
1076
1077 if (result > TAG_RETURN) {
1078 if (result == TAG_RAISE) rb_exc_raise(rb_errinfo());
1079 EC_JUMP_TAG(GET_EC(), result);
1080 }
1081 if (result < 0) {
1082 load_failed(fname);
1083 }
1084
1085 return result ? Qtrue : Qfalse;
1086 }
1087
1088 VALUE
rb_require(const char * fname)1089 rb_require(const char *fname)
1090 {
1091 VALUE fn = rb_str_new_cstr(fname);
1092 return rb_require_safe(fn, rb_safe_level());
1093 }
1094
1095 static int
register_init_ext(st_data_t * key,st_data_t * value,st_data_t init,int existing)1096 register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1097 {
1098 const char *name = (char *)*key;
1099 if (existing) {
1100 /* already registered */
1101 rb_warn("%s is already registered", name);
1102 }
1103 else {
1104 *value = (st_data_t)MEMO_NEW(0, 0, init);
1105 *key = (st_data_t)ruby_strdup(name);
1106 }
1107 return ST_CONTINUE;
1108 }
1109
1110 RUBY_FUNC_EXPORTED void
ruby_init_ext(const char * name,void (* init)(void))1111 ruby_init_ext(const char *name, void (*init)(void))
1112 {
1113 st_table *loading_tbl = get_loading_table();
1114
1115 if (rb_provided(name))
1116 return;
1117 st_update(loading_tbl, (st_data_t)name, register_init_ext, (st_data_t)init);
1118 }
1119
1120 /*
1121 * call-seq:
1122 * mod.autoload(module, filename) -> nil
1123 *
1124 * Registers _filename_ to be loaded (using <code>Kernel::require</code>)
1125 * the first time that _module_ (which may be a <code>String</code> or
1126 * a symbol) is accessed in the namespace of _mod_.
1127 *
1128 * module A
1129 * end
1130 * A.autoload(:B, "b")
1131 * A::B.doit # autoloads "b"
1132 */
1133
1134 static VALUE
rb_mod_autoload(VALUE mod,VALUE sym,VALUE file)1135 rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1136 {
1137 ID id = rb_to_id(sym);
1138
1139 FilePathValue(file);
1140 rb_autoload_str(mod, id, file);
1141 return Qnil;
1142 }
1143
1144 /*
1145 * call-seq:
1146 * mod.autoload?(name) -> String or nil
1147 *
1148 * Returns _filename_ to be loaded if _name_ is registered as
1149 * +autoload+ in the namespace of _mod_.
1150 *
1151 * module A
1152 * end
1153 * A.autoload(:B, "b")
1154 * A.autoload?(:B) #=> "b"
1155 */
1156
1157 static VALUE
rb_mod_autoload_p(VALUE mod,VALUE sym)1158 rb_mod_autoload_p(VALUE mod, VALUE sym)
1159 {
1160 ID id = rb_check_id(&sym);
1161 if (!id) {
1162 return Qnil;
1163 }
1164 return rb_autoload_p(mod, id);
1165 }
1166
1167 /*
1168 * call-seq:
1169 * autoload(module, filename) -> nil
1170 *
1171 * Registers _filename_ to be loaded (using <code>Kernel::require</code>)
1172 * the first time that _module_ (which may be a <code>String</code> or
1173 * a symbol) is accessed.
1174 *
1175 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1176 */
1177
1178 static VALUE
rb_f_autoload(VALUE obj,VALUE sym,VALUE file)1179 rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1180 {
1181 VALUE klass = rb_class_real(rb_vm_cbase());
1182 if (NIL_P(klass)) {
1183 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1184 }
1185 return rb_mod_autoload(klass, sym, file);
1186 }
1187
1188 /*
1189 * call-seq:
1190 * autoload?(name) -> String or nil
1191 *
1192 * Returns _filename_ to be loaded if _name_ is registered as
1193 * +autoload+.
1194 *
1195 * autoload(:B, "b")
1196 * autoload?(:B) #=> "b"
1197 */
1198
1199 static VALUE
rb_f_autoload_p(VALUE obj,VALUE sym)1200 rb_f_autoload_p(VALUE obj, VALUE sym)
1201 {
1202 /* use rb_vm_cbase() as same as rb_f_autoload. */
1203 VALUE klass = rb_vm_cbase();
1204 if (NIL_P(klass)) {
1205 return Qnil;
1206 }
1207 return rb_mod_autoload_p(klass, sym);
1208 }
1209
1210 void
Init_load(void)1211 Init_load(void)
1212 {
1213 #undef rb_intern
1214 #define rb_intern(str) rb_intern2((str), strlen(str))
1215 rb_vm_t *vm = GET_VM();
1216 static const char var_load_path[] = "$:";
1217 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1218
1219 rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
1220 rb_alias_variable(rb_intern("$-I"), id_load_path);
1221 rb_alias_variable(rb_intern("$LOAD_PATH"), id_load_path);
1222 vm->load_path = rb_ary_new();
1223 vm->expanded_load_path = rb_ary_tmp_new(0);
1224 vm->load_path_snapshot = rb_ary_tmp_new(0);
1225 vm->load_path_check_cache = 0;
1226
1227 rb_define_virtual_variable("$\"", get_loaded_features, 0);
1228 rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
1229 vm->loaded_features = rb_ary_new();
1230 vm->loaded_features_snapshot = rb_ary_tmp_new(0);
1231 vm->loaded_features_index = st_init_numtable();
1232
1233 rb_define_global_function("load", rb_f_load, -1);
1234 rb_define_global_function("require", rb_f_require, 1);
1235 rb_define_global_function("require_relative", rb_f_require_relative, 1);
1236 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1237 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, 1);
1238 rb_define_global_function("autoload", rb_f_autoload, 2);
1239 rb_define_global_function("autoload?", rb_f_autoload_p, 1);
1240
1241 ruby_dln_librefs = rb_ary_tmp_new(0);
1242 rb_gc_register_mark_object(ruby_dln_librefs);
1243 }
1244