Ruby 3.5.0dev (2025-10-25 revision c6d1458421796786d26e084b48a0a4a7e3b40867)
namespace.c (c6d1458421796786d26e084b48a0a4a7e3b40867)
1/* indent-tabs-mode: nil */
2
3#include "eval_intern.h"
4#include "internal.h"
5#include "internal/class.h"
6#include "internal/eval.h"
7#include "internal/error.h"
8#include "internal/file.h"
9#include "internal/gc.h"
10#include "internal/hash.h"
11#include "internal/load.h"
12#include "internal/namespace.h"
13#include "internal/st.h"
14#include "internal/variable.h"
15#include "iseq.h"
17#include "ruby/util.h"
18#include "vm_core.h"
19#include "darray.h"
20
21#include <stdio.h>
22
24VALUE rb_cNamespaceEntry = 0;
25VALUE rb_mNamespaceLoader = 0;
26
27static rb_namespace_t root_namespace_data = {
28 /* Initialize values lazily in Init_namespace() */
29 (VALUE)NULL, 0,
30 (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL,
31 (struct st_table *)NULL, (struct st_table *)NULL, (VALUE)NULL, (VALUE)NULL,
32 false, false
33};
34
35static rb_namespace_t * root_namespace = &root_namespace_data;
36static rb_namespace_t * main_namespace = 0;
37static char *tmp_dir;
38static bool tmp_dir_has_dirsep;
39
40#define NAMESPACE_TMP_PREFIX "_ruby_ns_"
41
42#ifndef MAXPATHLEN
43# define MAXPATHLEN 1024
44#endif
45
46#if defined(_WIN32)
47# define DIRSEP "\\"
48#else
49# define DIRSEP "/"
50#endif
51
52bool ruby_namespace_enabled = false; // extern
53bool ruby_namespace_init_done = false; // extern
54bool ruby_namespace_crashed = false; // extern, changed only in vm.c
55
56VALUE rb_resolve_feature_path(VALUE klass, VALUE fname);
57static VALUE rb_namespace_inspect(VALUE obj);
58
59void
60rb_namespace_init_done(void)
61{
62 ruby_namespace_init_done = true;
63}
64
65const rb_namespace_t *
66rb_root_namespace(void)
67{
68 return root_namespace;
69}
70
71const rb_namespace_t *
72rb_main_namespace(void)
73{
74 return main_namespace;
75}
76
77const rb_namespace_t *
78rb_current_namespace(void)
79{
80 /*
81 * If RUBY_NAMESPACE is not set, the root namespace is the only available one.
82 *
83 * Until the main_namespace is not initialized, the root namespace is
84 * the only valid namespace.
85 * This early return is to avoid accessing EC before its setup.
86 */
87 if (!main_namespace)
88 return root_namespace;
89
90 return rb_vm_current_namespace(GET_EC());
91}
92
93const rb_namespace_t *
94rb_loading_namespace(void)
95{
96 if (!main_namespace)
97 return root_namespace;
98
99 return rb_vm_loading_namespace(GET_EC());
100}
101
102const rb_namespace_t *
103rb_current_namespace_in_crash_report(void)
104{
105 if (ruby_namespace_crashed)
106 return NULL;
107 return rb_current_namespace();
108}
109
110static long namespace_id_counter = 0;
111
112static long
113namespace_generate_id(void)
114{
115 long id;
116 RB_VM_LOCKING() {
117 id = ++namespace_id_counter;
118 }
119 return id;
120}
121
122static VALUE
123namespace_main_to_s(VALUE obj)
124{
125 return rb_str_new2("main");
126}
127
128static void
129namespace_entry_initialize(rb_namespace_t *ns)
130{
131 const rb_namespace_t *root = rb_root_namespace();
132
133 // These will be updated immediately
134 ns->ns_object = 0;
135 ns->ns_id = 0;
136
137 ns->top_self = rb_obj_alloc(rb_cObject);
138 rb_define_singleton_method(ns->top_self, "to_s", namespace_main_to_s, 0);
139 rb_define_alias(rb_singleton_class(ns->top_self), "inspect", "to_s");
140 ns->load_path = rb_ary_dup(root->load_path);
141 ns->expanded_load_path = rb_ary_dup(root->expanded_load_path);
142 ns->load_path_snapshot = rb_ary_new();
143 ns->load_path_check_cache = 0;
144 ns->loaded_features = rb_ary_dup(root->loaded_features);
145 ns->loaded_features_snapshot = rb_ary_new();
146 ns->loaded_features_index = st_init_numtable();
147 ns->loaded_features_realpaths = rb_hash_dup(root->loaded_features_realpaths);
148 ns->loaded_features_realpath_map = rb_hash_dup(root->loaded_features_realpath_map);
149 ns->loading_table = st_init_strtable();
150 ns->ruby_dln_libmap = rb_hash_new_with_size(0);
151 ns->gvar_tbl = rb_hash_new_with_size(0);
152
153 ns->is_user = true;
154 ns->is_optional = true;
155}
156
157void
158rb_namespace_gc_update_references(void *ptr)
159{
160 rb_namespace_t *ns = (rb_namespace_t *)ptr;
161 if (!ns) return;
162
163 if (ns->ns_object)
164 ns->ns_object = rb_gc_location(ns->ns_object);
165 if (ns->top_self)
166 ns->top_self = rb_gc_location(ns->top_self);
167 ns->load_path = rb_gc_location(ns->load_path);
168 ns->expanded_load_path = rb_gc_location(ns->expanded_load_path);
169 ns->load_path_snapshot = rb_gc_location(ns->load_path_snapshot);
170 if (ns->load_path_check_cache) {
171 ns->load_path_check_cache = rb_gc_location(ns->load_path_check_cache);
172 }
173 ns->loaded_features = rb_gc_location(ns->loaded_features);
174 ns->loaded_features_snapshot = rb_gc_location(ns->loaded_features_snapshot);
175 ns->loaded_features_realpaths = rb_gc_location(ns->loaded_features_realpaths);
176 ns->loaded_features_realpath_map = rb_gc_location(ns->loaded_features_realpath_map);
177 ns->ruby_dln_libmap = rb_gc_location(ns->ruby_dln_libmap);
178 ns->gvar_tbl = rb_gc_location(ns->gvar_tbl);
179}
180
181void
182rb_namespace_entry_mark(void *ptr)
183{
184 const rb_namespace_t *ns = (rb_namespace_t *)ptr;
185 if (!ns) return;
186
187 rb_gc_mark(ns->ns_object);
188 rb_gc_mark(ns->top_self);
189 rb_gc_mark(ns->load_path);
190 rb_gc_mark(ns->expanded_load_path);
191 rb_gc_mark(ns->load_path_snapshot);
192 rb_gc_mark(ns->load_path_check_cache);
193 rb_gc_mark(ns->loaded_features);
194 rb_gc_mark(ns->loaded_features_snapshot);
195 rb_gc_mark(ns->loaded_features_realpaths);
196 rb_gc_mark(ns->loaded_features_realpath_map);
197 if (ns->loading_table) {
198 rb_mark_tbl(ns->loading_table);
199 }
200 rb_gc_mark(ns->ruby_dln_libmap);
201 rb_gc_mark(ns->gvar_tbl);
202}
203
204static int
205free_loading_table_entry(st_data_t key, st_data_t value, st_data_t arg)
206{
207 xfree((char *)key);
208 return ST_DELETE;
209}
210
211static int
212free_loaded_feature_index_i(st_data_t key, st_data_t value, st_data_t arg)
213{
214 if (!FIXNUM_P(value)) {
215 rb_darray_free((void *)value);
216 }
217 return ST_CONTINUE;
218}
219
220static void
221namespace_root_free(void *ptr)
222{
223 rb_namespace_t *ns = (rb_namespace_t *)ptr;
224 if (ns->loading_table) {
225 st_foreach(ns->loading_table, free_loading_table_entry, 0);
226 st_free_table(ns->loading_table);
227 ns->loading_table = 0;
228 }
229
230 if (ns->loaded_features_index) {
231 st_foreach(ns->loaded_features_index, free_loaded_feature_index_i, 0);
232 st_free_table(ns->loaded_features_index);
233 }
234}
235
236static void
237namespace_entry_free(void *ptr)
238{
239 namespace_root_free(ptr);
240 xfree(ptr);
241}
242
243static size_t
244namespace_entry_memsize(const void *ptr)
245{
246 const rb_namespace_t *ns = (const rb_namespace_t *)ptr;
247 return sizeof(rb_namespace_t) + \
248 rb_st_memsize(ns->loaded_features_index) + \
249 rb_st_memsize(ns->loading_table);
250}
251
252const rb_data_type_t rb_namespace_data_type = {
253 "Namespace::Entry",
254 {
255 rb_namespace_entry_mark,
256 namespace_entry_free,
257 namespace_entry_memsize,
258 rb_namespace_gc_update_references,
259 },
260 0, 0, RUBY_TYPED_FREE_IMMEDIATELY // TODO: enable RUBY_TYPED_WB_PROTECTED when inserting write barriers
261};
262
263const rb_data_type_t rb_root_namespace_data_type = {
264 "Namespace::Root",
265 {
266 rb_namespace_entry_mark,
267 namespace_root_free,
268 namespace_entry_memsize,
269 rb_namespace_gc_update_references,
270 },
271 &rb_namespace_data_type, 0, RUBY_TYPED_FREE_IMMEDIATELY // TODO: enable RUBY_TYPED_WB_PROTECTED when inserting write barriers
272};
273
274VALUE
275rb_namespace_entry_alloc(VALUE klass)
276{
277 rb_namespace_t *entry;
278 VALUE obj = TypedData_Make_Struct(klass, rb_namespace_t, &rb_namespace_data_type, entry);
279 namespace_entry_initialize(entry);
280 return obj;
281}
282
283static rb_namespace_t *
284get_namespace_struct_internal(VALUE entry)
285{
286 rb_namespace_t *sval;
287 TypedData_Get_Struct(entry, rb_namespace_t, &rb_namespace_data_type, sval);
288 return sval;
289}
290
292rb_get_namespace_t(VALUE namespace)
293{
294 VALUE entry;
295 ID id_namespace_entry;
296
297 VM_ASSERT(namespace);
298
299 if (NIL_P(namespace))
300 return root_namespace;
301
302 VM_ASSERT(NAMESPACE_OBJ_P(namespace));
303
304 CONST_ID(id_namespace_entry, "__namespace_entry__");
305 entry = rb_attr_get(namespace, id_namespace_entry);
306 return get_namespace_struct_internal(entry);
307}
308
309VALUE
310rb_get_namespace_object(rb_namespace_t *ns)
311{
312 VM_ASSERT(ns && ns->ns_object);
313 return ns->ns_object;
314}
315
316/*
317 * call-seq:
318 * Namespace.new -> new_namespace
319 *
320 * Returns a new Namespace object.
321 */
322static VALUE
323namespace_initialize(VALUE namespace)
324{
325 rb_namespace_t *ns;
326 rb_classext_t *object_classext;
327 VALUE entry;
328 ID id_namespace_entry;
329 CONST_ID(id_namespace_entry, "__namespace_entry__");
330
331 if (!rb_namespace_available()) {
332 rb_raise(rb_eRuntimeError, "Namespace is disabled. Set RUBY_NAMESPACE=1 environment variable to use Namespace.");
333 }
334
335 entry = rb_class_new_instance_pass_kw(0, NULL, rb_cNamespaceEntry);
336 ns = get_namespace_struct_internal(entry);
337
338 ns->ns_object = namespace;
339 ns->ns_id = namespace_generate_id();
340 rb_define_singleton_method(ns->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
341
342 // Set the Namespace object unique/consistent from any namespaces to have just single
343 // constant table from any view of every (including main) namespace.
344 // If a code in the namespace adds a constant, the constant will be visible even from root/main.
345 RCLASS_SET_PRIME_CLASSEXT_WRITABLE(namespace, true);
346
347 // Get a clean constant table of Object even by writable one
348 // because ns was just created, so it has not touched any constants yet.
349 object_classext = RCLASS_EXT_WRITABLE_IN_NS(rb_cObject, ns);
350 RCLASS_SET_CONST_TBL(namespace, RCLASSEXT_CONST_TBL(object_classext), true);
351
352 rb_ivar_set(namespace, id_namespace_entry, entry);
353
354 return namespace;
355}
356
357/*
358 * call-seq:
359 * Namespace.enabled? -> true or false
360 *
361 * Returns +true+ if namespace is enabled.
362 */
363static VALUE
364rb_namespace_s_getenabled(VALUE recv)
365{
366 return RBOOL(rb_namespace_available());
367}
368
369/*
370 * call-seq:
371 * Namespace.current -> namespace, nil or false
372 *
373 * Returns the current namespace.
374 * Returns +nil+ if it is the built-in namespace.
375 * Returns +false+ if namespace is not enabled.
376 */
377static VALUE
378rb_namespace_s_current(VALUE recv)
379{
380 const rb_namespace_t *ns;
381
382 if (!rb_namespace_available())
383 return Qnil;
384
385 ns = rb_vm_current_namespace(GET_EC());
386 VM_ASSERT(ns && ns->ns_object);
387 return ns->ns_object;
388}
389
390/*
391 * call-seq:
392 * load_path -> array
393 *
394 * Returns namespace local load path.
395 */
396static VALUE
397rb_namespace_load_path(VALUE namespace)
398{
399 VM_ASSERT(NAMESPACE_OBJ_P(namespace));
400 return rb_get_namespace_t(namespace)->load_path;
401}
402
403#ifdef _WIN32
404UINT rb_w32_system_tmpdir(WCHAR *path, UINT len);
405#endif
406
407/* Copied from mjit.c Ruby 3.0.3 */
408static char *
409system_default_tmpdir(void)
410{
411 // c.f. ext/etc/etc.c:etc_systmpdir()
412#ifdef _WIN32
413 WCHAR tmppath[_MAX_PATH];
414 UINT len = rb_w32_system_tmpdir(tmppath, numberof(tmppath));
415 if (len) {
416 int blen = WideCharToMultiByte(CP_UTF8, 0, tmppath, len, NULL, 0, NULL, NULL);
417 char *tmpdir = xmalloc(blen + 1);
418 WideCharToMultiByte(CP_UTF8, 0, tmppath, len, tmpdir, blen, NULL, NULL);
419 tmpdir[blen] = '\0';
420 return tmpdir;
421 }
422#elif defined _CS_DARWIN_USER_TEMP_DIR
423 char path[MAXPATHLEN];
424 size_t len = confstr(_CS_DARWIN_USER_TEMP_DIR, path, sizeof(path));
425 if (len > 0) {
426 char *tmpdir = xmalloc(len);
427 if (len > sizeof(path)) {
428 confstr(_CS_DARWIN_USER_TEMP_DIR, tmpdir, len);
429 }
430 else {
431 memcpy(tmpdir, path, len);
432 }
433 return tmpdir;
434 }
435#endif
436 return 0;
437}
438
439static int
440check_tmpdir(const char *dir)
441{
442 struct stat st;
443
444 if (!dir) return FALSE;
445 if (stat(dir, &st)) return FALSE;
446#ifndef S_ISDIR
447# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
448#endif
449 if (!S_ISDIR(st.st_mode)) return FALSE;
450#ifndef _WIN32
451# ifndef S_IWOTH
452# define S_IWOTH 002
453# endif
454 if (st.st_mode & S_IWOTH) {
455# ifdef S_ISVTX
456 if (!(st.st_mode & S_ISVTX)) return FALSE;
457# else
458 return FALSE;
459# endif
460 }
461 if (access(dir, W_OK)) return FALSE;
462#endif
463 return TRUE;
464}
465
466static char *
467system_tmpdir(void)
468{
469 char *tmpdir;
470# define RETURN_ENV(name) \
471 if (check_tmpdir(tmpdir = getenv(name))) return ruby_strdup(tmpdir)
472 RETURN_ENV("TMPDIR");
473 RETURN_ENV("TMP");
474 tmpdir = system_default_tmpdir();
475 if (check_tmpdir(tmpdir)) return tmpdir;
476 return ruby_strdup("/tmp");
477# undef RETURN_ENV
478}
479
480/* end of copy */
481
482static int
483sprint_ext_filename(char *str, size_t size, long namespace_id, const char *prefix, const char *basename)
484{
485 if (tmp_dir_has_dirsep) {
486 return snprintf(str, size, "%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, prefix, getpid(), namespace_id, basename);
487 }
488 return snprintf(str, size, "%s%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, DIRSEP, prefix, getpid(), namespace_id, basename);
489}
490
491#ifdef _WIN32
492static const char *
493copy_ext_file_error(char *message, size_t size)
494{
495 int error = GetLastError();
496 char *p = message;
497 size_t len = snprintf(message, size, "%d: ", error);
498
499#define format_message(sublang) FormatMessage(\
500 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
501 NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
502 message + len, size - len, NULL)
503 if (format_message(SUBLANG_ENGLISH_US) == 0)
504 format_message(SUBLANG_DEFAULT);
505 for (p = message + len; *p; p++) {
506 if (*p == '\n' || *p == '\r')
507 *p = ' ';
508 }
509 return message;
510}
511#else
512static const char *
513copy_ext_file_error(char *message, size_t size, int copy_retvalue, char *src_path, char *dst_path)
514{
515 switch (copy_retvalue) {
516 case 1:
517 snprintf(message, size, "can't open the extension path: %s", src_path);
518 case 2:
519 snprintf(message, size, "can't open the file to write: %s", dst_path);
520 case 3:
521 snprintf(message, size, "failed to read the extension path: %s", src_path);
522 case 4:
523 snprintf(message, size, "failed to write the extension path: %s", dst_path);
524 case 5:
525 snprintf(message, size, "failed to stat the extension path to copy permissions: %s", src_path);
526 case 6:
527 snprintf(message, size, "failed to set permissions to the copied extension path: %s", dst_path);
528 default:
529 rb_bug("unknown return value of copy_ext_file: %d", copy_retvalue);
530 }
531 return message;
532}
533#endif
534
535static int
536copy_ext_file(char *src_path, char *dst_path)
537{
538#if defined(_WIN32)
539 int rvalue;
540
541 WCHAR *w_src = rb_w32_mbstr_to_wstr(CP_UTF8, src_path, -1, NULL);
542 WCHAR *w_dst = rb_w32_mbstr_to_wstr(CP_UTF8, dst_path, -1, NULL);
543 if (!w_src || !w_dst) {
544 rb_memerror();
545 }
546
547 rvalue = CopyFileW(w_src, w_dst, FALSE) ? 0 : 1;
548 free(w_src);
549 free(w_dst);
550 return rvalue;
551#else
552 FILE *src, *dst;
553 char buffer[1024];
554 size_t read = 0, wrote, written = 0;
555 size_t maxread = sizeof(buffer);
556 int eof = 0;
557 int clean_read = 1;
558 int retvalue = 0;
559
560 src = fopen(src_path, "rb");
561 if (!src) {
562 return 1;
563 }
564 dst = fopen(dst_path, "wb");
565 if (!dst) {
566 return 2;
567 }
568 while (!eof) {
569 if (clean_read) {
570 read = fread(buffer, 1, sizeof(buffer), src);
571 written = 0;
572 }
573 if (read > 0) {
574 wrote = fwrite(buffer+written, 1, read-written, dst);
575 if (wrote < read-written) {
576 if (ferror(dst)) {
577 retvalue = 4;
578 break;
579 }
580 else { // partial write
581 clean_read = 0;
582 written += wrote;
583 }
584 }
585 else { // Wrote the entire buffer to dst, next read is clean one
586 clean_read = 1;
587 }
588 }
589 if (read < maxread) {
590 if (clean_read && feof(src)) {
591 // If it's not clean, buffer should have bytes not written yet.
592 eof = 1;
593 }
594 else if (ferror(src)) {
595 retvalue = 3;
596 // Writes could be partial/dirty, but this load is failure anyway
597 break;
598 }
599 }
600 }
601 fclose(src);
602 fclose(dst);
603#if defined(__CYGWIN__)
604 // On Cygwin, CopyFile-like operations may strip executable bits.
605 // Explicitly match destination file permissions to source.
606 if (retvalue == 0) {
607 struct stat st;
608 if (stat(src_path, &st) != 0) {
609 retvalue = 5;
610 }
611 else if (chmod(dst_path, st.st_mode & 0777) != 0) {
612 retvalue = 6;
613 }
614 }
615#endif
616 return retvalue;
617#endif
618}
619
620#if defined __CYGWIN__ || defined DOSISH
621#define isdirsep(x) ((x) == '/' || (x) == '\\')
622#else
623#define isdirsep(x) ((x) == '/')
624#endif
625
626#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
627#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
628
629static void
630fname_without_suffix(const char *fname, char *rvalue, size_t rsize)
631{
632 size_t len = strlen(fname);
633 const char *pos;
634 for (pos = fname + len; pos > fname; pos--) {
635 if (IS_SOEXT(pos) || IS_DLEXT(pos)) {
636 len = pos - fname;
637 break;
638 }
639 if (fname + len - pos > DLEXT_MAXLEN) break;
640 }
641 if (len > rsize - 1) len = rsize - 1;
642 memcpy(rvalue, fname, len);
643 rvalue[len] = '\0';
644}
645
646static void
647escaped_basename(const char *path, const char *fname, char *rvalue, size_t rsize)
648{
649 char *pos;
650 const char *leaf = path, *found;
651 // `leaf + 1` looks uncomfortable (when leaf == path), but fname must not be the top-dir itself
652 while ((found = strstr(leaf + 1, fname)) != NULL) {
653 leaf = found; // find the last occurrence for the path like /etc/my-crazy-lib-dir/etc.so
654 }
655 strlcpy(rvalue, leaf, rsize);
656 for (pos = rvalue; *pos; pos++) {
657 if (isdirsep(*pos)) {
658 *pos = '+';
659 }
660 }
661}
662
663VALUE
664rb_namespace_local_extension(VALUE namespace, VALUE fname, VALUE path)
665{
666 char ext_path[MAXPATHLEN], fname2[MAXPATHLEN], basename[MAXPATHLEN];
667 int copy_error, wrote;
668 char *src_path = RSTRING_PTR(path), *fname_ptr = RSTRING_PTR(fname);
669 rb_namespace_t *ns = rb_get_namespace_t(namespace);
670
671 fname_without_suffix(fname_ptr, fname2, sizeof(fname2));
672 escaped_basename(src_path, fname2, basename, sizeof(basename));
673
674 wrote = sprint_ext_filename(ext_path, sizeof(ext_path), ns->ns_id, NAMESPACE_TMP_PREFIX, basename);
675 if (wrote >= (int)sizeof(ext_path)) {
676 rb_bug("Extension file path in namespace was too long");
677 }
678 copy_error = copy_ext_file(src_path, ext_path);
679 if (copy_error) {
680 char message[1024];
681#if defined(_WIN32)
682 copy_ext_file_error(message, sizeof(message));
683#else
684 copy_ext_file_error(message, sizeof(message), copy_error, src_path, ext_path);
685#endif
686 rb_raise(rb_eLoadError, "can't prepare the extension file for namespaces (%s from %s): %s", ext_path, src_path, message);
687 }
688 // TODO: register the path to be clean-uped
689 return rb_str_new_cstr(ext_path);
690}
691
692// TODO: delete it just after dln_load? or delay it?
693// At least for _WIN32, deleting extension files should be delayed until the namespace's destructor.
694// And it requires calling dlclose before deleting it.
695
696static VALUE
697rb_namespace_load(int argc, VALUE *argv, VALUE namespace)
698{
699 VALUE fname, wrap;
700 rb_scan_args(argc, argv, "11", &fname, &wrap);
701
702 rb_vm_frame_flag_set_ns_require(GET_EC());
703
704 VALUE args = rb_ary_new_from_args(2, fname, wrap);
705 return rb_load_entrypoint(args);
706}
707
708static VALUE
709rb_namespace_require(VALUE namespace, VALUE fname)
710{
711 rb_vm_frame_flag_set_ns_require(GET_EC());
712
713 return rb_require_string(fname);
714}
715
716static VALUE
717rb_namespace_require_relative(VALUE namespace, VALUE fname)
718{
719 rb_vm_frame_flag_set_ns_require(GET_EC());
720
721 return rb_require_relative_entrypoint(fname);
722}
723
724static void
725initialize_root_namespace(void)
726{
727 VALUE root_namespace, entry;
728 ID id_namespace_entry;
729 rb_vm_t *vm = GET_VM();
730 rb_namespace_t *root = (rb_namespace_t *)rb_root_namespace();
731
732 root->load_path = rb_ary_new();
733 root->expanded_load_path = rb_ary_hidden_new(0);
734 root->load_path_snapshot = rb_ary_hidden_new(0);
735 root->load_path_check_cache = 0;
736 rb_define_singleton_method(root->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
737
738 root->loaded_features = rb_ary_new();
739 root->loaded_features_snapshot = rb_ary_hidden_new(0);
740 root->loaded_features_index = st_init_numtable();
741 root->loaded_features_realpaths = rb_hash_new();
742 rb_obj_hide(root->loaded_features_realpaths);
743 root->loaded_features_realpath_map = rb_hash_new();
744 rb_obj_hide(root->loaded_features_realpath_map);
745
746 root->ruby_dln_libmap = rb_hash_new_with_size(0);
747 root->gvar_tbl = rb_hash_new_with_size(0);
748
749 vm->root_namespace = root;
750
751 if (rb_namespace_available()) {
752 CONST_ID(id_namespace_entry, "__namespace_entry__");
753
754 root_namespace = rb_obj_alloc(rb_cNamespace);
755 RCLASS_SET_PRIME_CLASSEXT_WRITABLE(root_namespace, true);
756 RCLASS_SET_CONST_TBL(root_namespace, RCLASSEXT_CONST_TBL(RCLASS_EXT_PRIME(rb_cObject)), true);
757
758 root->ns_id = namespace_generate_id();
759 root->ns_object = root_namespace;
760
761 entry = TypedData_Wrap_Struct(rb_cNamespaceEntry, &rb_root_namespace_data_type, root);
762 rb_ivar_set(root_namespace, id_namespace_entry, entry);
763 }
764 else {
765 root->ns_id = 1;
766 root->ns_object = Qnil;
767 }
768}
769
770static VALUE
771rb_namespace_eval(VALUE namespace, VALUE str)
772{
773 const rb_iseq_t *iseq;
774 const rb_namespace_t *ns;
775
776 StringValue(str);
777
778 iseq = rb_iseq_compile_iseq(str, rb_str_new_cstr("eval"));
779 VM_ASSERT(iseq);
780
781 ns = (const rb_namespace_t *)rb_get_namespace_t(namespace);
782
783 return rb_iseq_eval(iseq, ns);
784}
785
786static int namespace_experimental_warned = 0;
787
788void
789rb_initialize_main_namespace(void)
790{
791 rb_namespace_t *ns;
792 VALUE main_ns;
793 rb_vm_t *vm = GET_VM();
794
795 VM_ASSERT(rb_namespace_available());
796
797 if (!namespace_experimental_warned) {
799 "Namespace is experimental, and the behavior may change in the future!\n"
800 "See doc/namespace.md for known issues, etc.");
801 namespace_experimental_warned = 1;
802 }
803
804 main_ns = rb_class_new_instance(0, NULL, rb_cNamespace);
805 VM_ASSERT(NAMESPACE_OBJ_P(main_ns));
806 ns = rb_get_namespace_t(main_ns);
807 ns->ns_object = main_ns;
808 ns->is_user = true;
809 ns->is_optional = false;
810
811 rb_const_set(rb_cNamespace, rb_intern("MAIN"), main_ns);
812
813 vm->main_namespace = main_namespace = ns;
814
815 // create the writable classext of ::Object explicitly to finalize the set of visible top-level constants
816 RCLASS_EXT_WRITABLE_IN_NS(rb_cObject, ns);
817}
818
819static VALUE
820rb_namespace_inspect(VALUE obj)
821{
822 rb_namespace_t *ns;
823 VALUE r;
824 if (obj == Qfalse) {
825 r = rb_str_new_cstr("#<Namespace:root>");
826 return r;
827 }
828 ns = rb_get_namespace_t(obj);
829 r = rb_str_new_cstr("#<Namespace:");
830 rb_str_concat(r, rb_funcall(LONG2NUM(ns->ns_id), rb_intern("to_s"), 0));
831 if (NAMESPACE_ROOT_P(ns)) {
832 rb_str_cat_cstr(r, ",root");
833 }
834 if (NAMESPACE_USER_P(ns)) {
835 rb_str_cat_cstr(r, ",user");
836 }
837 if (NAMESPACE_MAIN_P(ns)) {
838 rb_str_cat_cstr(r, ",main");
839 }
840 else if (NAMESPACE_OPTIONAL_P(ns)) {
841 rb_str_cat_cstr(r, ",optional");
842 }
843 rb_str_cat_cstr(r, ">");
844 return r;
845}
846
847static VALUE
848rb_namespace_loading_func(int argc, VALUE *argv, VALUE _self)
849{
850 rb_vm_frame_flag_set_ns_require(GET_EC());
851 return rb_call_super(argc, argv);
852}
853
854static void
855namespace_define_loader_method(const char *name)
856{
857 rb_define_private_method(rb_mNamespaceLoader, name, rb_namespace_loading_func, -1);
858 rb_define_singleton_method(rb_mNamespaceLoader, name, rb_namespace_loading_func, -1);
859}
860
861void
862Init_root_namespace(void)
863{
864 root_namespace->loading_table = st_init_strtable();
865}
866
867void
868Init_enable_namespace(void)
869{
870 const char *env = getenv("RUBY_NAMESPACE");
871 if (env && strlen(env) == 1 && env[0] == '1') {
872 ruby_namespace_enabled = true;
873 }
874 else {
875 ruby_namespace_init_done = true;
876 }
877}
878
879#ifdef RUBY_DEBUG
880
881/* :nodoc: */
882static VALUE
883rb_namespace_s_root(VALUE recv)
884{
885 return root_namespace->ns_object;
886}
887
888/* :nodoc: */
889static VALUE
890rb_namespace_s_main(VALUE recv)
891{
892 return main_namespace->ns_object;
893}
894
895static const char *
896classname(VALUE klass)
897{
898 VALUE p;
899 if (!klass) {
900 return "Qfalse";
901 }
902 p = RCLASSEXT_CLASSPATH(RCLASS_EXT_PRIME(klass));
903 if (RTEST(p))
904 return RSTRING_PTR(p);
905 if (RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS))
906 return "AnyClassValue";
907 return "NonClassValue";
908}
909
910static enum rb_id_table_iterator_result
911dump_classext_methods_i(ID mid, VALUE _val, void *data)
912{
913 VALUE ary = (VALUE)data;
914 rb_ary_push(ary, rb_id2str(mid));
915 return ID_TABLE_CONTINUE;
916}
917
918static enum rb_id_table_iterator_result
919dump_classext_constants_i(ID mid, VALUE _val, void *data)
920{
921 VALUE ary = (VALUE)data;
922 rb_ary_push(ary, rb_id2str(mid));
923 return ID_TABLE_CONTINUE;
924}
925
926static void
927dump_classext_i(rb_classext_t *ext, bool is_prime, VALUE _ns, void *data)
928{
929 char buf[4096];
930 struct rb_id_table *tbl;
931 VALUE ary, res = (VALUE)data;
932
933 snprintf(buf, 4096, "Namespace %ld:%s classext %p\n",
934 RCLASSEXT_NS(ext)->ns_id, is_prime ? " prime" : "", (void *)ext);
935 rb_str_cat_cstr(res, buf);
936
937 snprintf(buf, 2048, " Super: %s\n", classname(RCLASSEXT_SUPER(ext)));
938 rb_str_cat_cstr(res, buf);
939
940 tbl = RCLASSEXT_M_TBL(ext);
941 if (tbl) {
942 ary = rb_ary_new_capa((long)rb_id_table_size(tbl));
943 rb_id_table_foreach(RCLASSEXT_M_TBL(ext), dump_classext_methods_i, (void *)ary);
944 rb_ary_sort_bang(ary);
945 snprintf(buf, 4096, " Methods(%ld): ", RARRAY_LEN(ary));
946 rb_str_cat_cstr(res, buf);
948 rb_str_cat_cstr(res, "\n");
949 }
950 else {
951 rb_str_cat_cstr(res, " Methods(0): .\n");
952 }
953
954 tbl = RCLASSEXT_CONST_TBL(ext);
955 if (tbl) {
956 ary = rb_ary_new_capa((long)rb_id_table_size(tbl));
957 rb_id_table_foreach(tbl, dump_classext_constants_i, (void *)ary);
958 rb_ary_sort_bang(ary);
959 snprintf(buf, 4096, " Constants(%ld): ", RARRAY_LEN(ary));
960 rb_str_cat_cstr(res, buf);
962 rb_str_cat_cstr(res, "\n");
963 }
964 else {
965 rb_str_cat_cstr(res, " Constants(0): .\n");
966 }
967}
968
969/* :nodoc: */
970static VALUE
971rb_f_dump_classext(VALUE recv, VALUE klass)
972{
973 /*
974 * The desired output String value is:
975 * Class: 0x88800932 (String) [singleton]
976 * Prime classext namespace(2,main), readable(t), writable(f)
977 * Non-prime classexts: 3
978 * Namespace 2: prime classext 0x88800933
979 * Super: Object
980 * Methods(43): aaaaa, bbbb, cccc, dddd, eeeee, ffff, gggg, hhhhh, ...
981 * Constants(12): FOO, Bar, ...
982 * Namespace 5: classext 0x88800934
983 * Super: Object
984 * Methods(43): aaaaa, bbbb, cccc, dddd, eeeee, ffff, gggg, hhhhh, ...
985 * Constants(12): FOO, Bar, ...
986 */
987 char buf[2048];
988 VALUE res;
989 const rb_classext_t *ext;
990 const rb_namespace_t *ns;
991 st_table *classext_tbl;
992
993 if (!(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE))) {
994 snprintf(buf, 2048, "Non-class/module value: %p (%s)\n", (void *)klass, rb_type_str(BUILTIN_TYPE(klass)));
995 return rb_str_new_cstr(buf);
996 }
997
998 if (RB_TYPE_P(klass, T_CLASS)) {
999 snprintf(buf, 2048, "Class: %p (%s)%s\n",
1000 (void *)klass, classname(klass), RCLASS_SINGLETON_P(klass) ? " [singleton]" : "");
1001 }
1002 else {
1003 snprintf(buf, 2048, "Module: %p (%s)\n", (void *)klass, classname(klass));
1004 }
1005 res = rb_str_new_cstr(buf);
1006
1007 ext = RCLASS_EXT_PRIME(klass);
1008 ns = RCLASSEXT_NS(ext);
1009 snprintf(buf, 2048, "Prime classext namespace(%ld,%s), readable(%s), writable(%s)\n",
1010 ns->ns_id,
1011 NAMESPACE_ROOT_P(ns) ? "root" : (NAMESPACE_MAIN_P(ns) ? "main" : "optional"),
1012 RCLASS_PRIME_CLASSEXT_READABLE_P(klass) ? "t" : "f",
1013 RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass) ? "t" : "f");
1014 rb_str_cat_cstr(res, buf);
1015
1016 classext_tbl = RCLASS_CLASSEXT_TBL(klass);
1017 if (!classext_tbl) {
1018 rb_str_cat_cstr(res, "Non-prime classexts: 0\n");
1019 }
1020 else {
1021 snprintf(buf, 2048, "Non-prime classexts: %zu\n", st_table_size(classext_tbl));
1022 rb_str_cat_cstr(res, buf);
1023 }
1024
1025 rb_class_classext_foreach(klass, dump_classext_i, (void *)res);
1026
1027 return res;
1028}
1029
1030/* :nodoc: */
1031static VALUE
1032rb_namespace_root_p(VALUE namespace)
1033{
1034 const rb_namespace_t *ns = (const rb_namespace_t *)rb_get_namespace_t(namespace);
1035 return RBOOL(NAMESPACE_ROOT_P(ns));
1036}
1037
1038/* :nodoc: */
1039static VALUE
1040rb_namespace_main_p(VALUE namespace)
1041{
1042 const rb_namespace_t *ns = (const rb_namespace_t *)rb_get_namespace_t(namespace);
1043 return RBOOL(NAMESPACE_MAIN_P(ns));
1044}
1045
1046/* :nodoc: */
1047static VALUE
1048rb_namespace_user_p(VALUE namespace)
1049{
1050 const rb_namespace_t *ns = (const rb_namespace_t *)rb_get_namespace_t(namespace);
1051 return RBOOL(NAMESPACE_USER_P(ns));
1052}
1053
1054#endif /* RUBY_DEBUG */
1055
1056/*
1057 * Document-class: Namespace
1058 *
1059 * Namespace is designed to provide separated spaces in a Ruby
1060 * process, to isolate applications and libraries.
1061 * See {Namespace}[rdoc-ref:namespace.md].
1062 */
1063void
1064Init_Namespace(void)
1065{
1066 tmp_dir = system_tmpdir();
1067 tmp_dir_has_dirsep = (strcmp(tmp_dir + (strlen(tmp_dir) - strlen(DIRSEP)), DIRSEP) == 0);
1068
1070 rb_define_method(rb_cNamespace, "initialize", namespace_initialize, 0);
1071
1072 /* :nodoc: */
1073 rb_cNamespaceEntry = rb_define_class_under(rb_cNamespace, "Entry", rb_cObject);
1074 rb_define_alloc_func(rb_cNamespaceEntry, rb_namespace_entry_alloc);
1075
1076 initialize_root_namespace();
1077
1078 /* :nodoc: */
1079 rb_mNamespaceLoader = rb_define_module_under(rb_cNamespace, "Loader");
1080 namespace_define_loader_method("require");
1081 namespace_define_loader_method("require_relative");
1082 namespace_define_loader_method("load");
1083
1084 if (rb_namespace_available()) {
1085 rb_include_module(rb_cObject, rb_mNamespaceLoader);
1086
1087#ifdef RUBY_DEBUG
1088 rb_define_singleton_method(rb_cNamespace, "root", rb_namespace_s_root, 0);
1089 rb_define_singleton_method(rb_cNamespace, "main", rb_namespace_s_main, 0);
1090 rb_define_global_function("dump_classext", rb_f_dump_classext, 1);
1091
1092 rb_define_method(rb_cNamespace, "root?", rb_namespace_root_p, 0);
1093 rb_define_method(rb_cNamespace, "main?", rb_namespace_main_p, 0);
1094 rb_define_method(rb_cNamespace, "user?", rb_namespace_user_p, 0);
1095#endif
1096 }
1097
1098 rb_define_singleton_method(rb_cNamespace, "enabled?", rb_namespace_s_getenabled, 0);
1099 rb_define_singleton_method(rb_cNamespace, "current", rb_namespace_s_current, 0);
1100
1101 rb_define_method(rb_cNamespace, "load_path", rb_namespace_load_path, 0);
1102 rb_define_method(rb_cNamespace, "load", rb_namespace_load, -1);
1103 rb_define_method(rb_cNamespace, "require", rb_namespace_require, 1);
1104 rb_define_method(rb_cNamespace, "require_relative", rb_namespace_require_relative, 1);
1105 rb_define_method(rb_cNamespace, "eval", rb_namespace_eval, 1);
1106
1107 rb_define_method(rb_cNamespace, "inspect", rb_namespace_inspect, 0);
1108}
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
Ruby-level global variables / constants, visible from C.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1799
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1582
VALUE rb_singleton_class(VALUE obj)
Finds or creates the singleton class of the passed object.
Definition class.c:2903
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1618
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1728
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2951
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:3241
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1674
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define T_MODULE
Old name of RUBY_T_MODULE.
Definition value_type.h:70
#define T_ICLASS
Old name of RUBY_T_ICLASS.
Definition value_type.h:66
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define NIL_P
Old name of RB_NIL_P.
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition value_type.h:58
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
VALUE rb_eLoadError
LoadError exception.
Definition error.c:1448
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
@ RB_WARN_CATEGORY_EXPERIMENTAL
Warning is for experimental features.
Definition error.h:51
VALUE rb_cNamespace
Namespace class.
Definition namespace.c:23
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2164
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2205
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:100
VALUE rb_class_new_instance_pass_kw(int argc, const VALUE *argv, VALUE klass)
Identical to rb_class_new_instance(), except it passes the passed keywords if any to the #initialize ...
Definition object.c:2182
VALUE rb_cModule
Module class.
Definition object.c:62
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
VALUE rb_call_super(int argc, const VALUE *argv)
This resembles ruby's super.
Definition vm_eval.c:362
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_sort_bang(VALUE ary)
Destructively sorts the passed array in-place, according to each elements' <=> result.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
Definition load.c:1446
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
Definition string.c:4024
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1655
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1513
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1986
void rb_const_set(VALUE space, ID name, VALUE val)
Names a constant.
Definition variable.c:3890
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
int len
Length of the buffer.
Definition io.h:8
char * ruby_strdup(const char *str)
This is our own version of strdup(3) that uses ruby_xmalloc() instead of system malloc (benefits our ...
Definition util.c:515
#define PRI_PIDT_PREFIX
A rb_sprintf() format prefix to be used for a pid_t parameter.
Definition pid_t.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:520
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:455
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:502
#define RTEST
This is an old name of RB_TEST.
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:202
Internal header for Namespace.
Definition namespace.h:14
Definition st.h:79
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376