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