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