Ruby 3.5.0dev (2025-08-16 revision 11c8bad64b31c125b903547bb3eed0ede8f0f8e2)
namespace.c (11c8bad64b31c125b903547bb3eed0ede8f0f8e2)
1/* indent-tabs-mode: nil */
2
3#include "internal.h"
4#include "internal/class.h"
5#include "internal/eval.h"
6#include "internal/error.h"
7#include "internal/file.h"
8#include "internal/gc.h"
9#include "internal/hash.h"
10#include "internal/load.h"
11#include "internal/namespace.h"
12#include "internal/st.h"
13#include "internal/variable.h"
15#include "ruby/util.h"
16#include "vm_core.h"
17
18#include <stdio.h>
19
21VALUE rb_cNamespaceEntry = 0;
23VALUE rb_mNamespaceLoader = 0;
24
25static rb_namespace_t builtin_namespace_data = {
26 .ns_object = Qnil,
27 .ns_id = 0,
28 .is_builtin = true,
29 .is_user = false,
30 .is_optional = false
31};
32static rb_namespace_t * const root_namespace = 0;
33static rb_namespace_t * const builtin_namespace = &builtin_namespace_data;
34static rb_namespace_t * main_namespace = 0;
35static char *tmp_dir;
36static bool tmp_dir_has_dirsep;
37
38#define NAMESPACE_TMP_PREFIX "_ruby_ns_"
39
40#ifndef MAXPATHLEN
41# define MAXPATHLEN 1024
42#endif
43
44#if defined(_WIN32)
45# define DIRSEP "\\"
46#else
47# define DIRSEP "/"
48#endif
49
50bool ruby_namespace_enabled = false; // extern
51bool ruby_namespace_init_done = false; // extern
52
53VALUE rb_resolve_feature_path(VALUE klass, VALUE fname);
54static VALUE rb_namespace_inspect(VALUE obj);
55static void namespace_push(rb_thread_t *th, VALUE namespace);
56static VALUE namespace_pop(VALUE th_value);
57
58void
59rb_namespace_init_done(void)
60{
61 ruby_namespace_init_done = true;
62}
63
64void
65rb_namespace_enable_builtin(void)
66{
67 VALUE require_stack = GET_VM()->require_stack;
68 if (require_stack) {
69 rb_ary_push(require_stack, Qnil);
70 }
71}
72
73void
74rb_namespace_disable_builtin(void)
75{
76 VALUE require_stack = GET_VM()->require_stack;
77 if (require_stack) {
78 rb_ary_pop(require_stack);
79 }
80}
81
82void
83rb_namespace_push_loading_namespace(const rb_namespace_t *ns)
84{
85 VALUE require_stack = GET_VM()->require_stack;
86 rb_ary_push(require_stack, ns->ns_object);
87}
88
89void
90rb_namespace_pop_loading_namespace(const rb_namespace_t *ns)
91{
92 VALUE require_stack = GET_VM()->require_stack;
93 long size = RARRAY_LEN(require_stack);
94 if (size == 0)
95 rb_bug("popping on the empty require_stack");
96 VALUE latest = RARRAY_AREF(require_stack, size-1);
97 if (latest != ns->ns_object)
98 rb_bug("Inconsistent loading namespace");
99 rb_ary_pop(require_stack);
100}
101
103rb_root_namespace(void)
104{
105 return root_namespace;
106}
107
108const rb_namespace_t *
109rb_builtin_namespace(void)
110{
111 return (const rb_namespace_t *)builtin_namespace;
112}
113
115rb_main_namespace(void)
116{
117 return main_namespace;
118}
119
120static bool
121namespace_ignore_builtin_primitive_methods_p(const rb_namespace_t *ns, rb_method_definition_t *def)
122{
123 if (!NAMESPACE_BUILTIN_P(ns)) {
124 return false;
125 }
126 /* Primitive methods (just to call C methods) covers/hides the effective
127 namespaces, so ignore the methods' namespaces to expose user code's
128 namespace to the implementation.
129 */
130 if (def->type == VM_METHOD_TYPE_ISEQ) {
131 ID mid = def->original_id;
132 const char *path = RSTRING_PTR(pathobj_path(def->body.iseq.iseqptr->body->location.pathobj));
133 if (strcmp(path, "<internal:kernel>") == 0) {
134 if (mid == rb_intern("class") || mid == rb_intern("clone") ||
135 mid == rb_intern("tag") || mid == rb_intern("then") ||
136 mid == rb_intern("yield_self") || mid == rb_intern("loop") ||
137 mid == rb_intern("Float") || mid == rb_intern("Integer")
138 ) {
139 return true;
140 }
141 }
142 else if (strcmp(path, "<internal:warning>") == 0) {
143 if (mid == rb_intern("warn")) {
144 return true;
145 }
146 }
147 else if (strcmp(path, "<internal:marshal>") == 0) {
148 if (mid == rb_intern("load"))
149 return true;
150 }
151 }
152 return false;
153}
154
155static inline const rb_namespace_t *
156block_proc_namespace(const VALUE procval)
157{
158 rb_proc_t *proc;
159
160 if (procval) {
161 GetProcPtr(procval, proc);
162 return proc->ns;
163 }
164 else {
165 return NULL;
166 }
167}
168
169static const rb_namespace_t *
170current_namespace(bool permit_calling_builtin)
171{
172 /*
173 * TODO: move this code to vm.c or somewhere else
174 * when it's fully updated with VM_FRAME_FLAG_*
175 */
177 const rb_namespace_t *ns;
178 rb_execution_context_t *ec = GET_EC();
179 rb_control_frame_t *cfp = ec->cfp;
180 rb_thread_t *th = rb_ec_thread_ptr(ec);
181 int calling = 1;
182
183 if (!rb_namespace_available())
184 return 0;
185
186 if (th->namespaces && RARRAY_LEN(th->namespaces) > 0) {
187 // temp code to detect the context is in require/load
188 // TODO: this doesn't work well in optional namespaces
189 // calling = 0;
190 }
191 while (calling) {
192 const rb_namespace_t *proc_ns = NULL;
193 VALUE bh;
194 if (VM_FRAME_NS_SWITCH_P(cfp)) {
195 bh = rb_vm_frame_block_handler(cfp);
196 if (bh && vm_block_handler_type(bh) == block_handler_type_proc) {
197 proc_ns = block_proc_namespace(VM_BH_TO_PROC(bh));
198 if (permit_calling_builtin || NAMESPACE_USER_P(proc_ns))
199 return proc_ns;
200 }
201 }
202 cme = rb_vm_frame_method_entry(cfp);
203 if (cme && cme->def) {
204 ns = cme->def->ns;
205 if (ns) {
206 // this method is not a built-in class/module's method
207 // or a built-in primitive (Ruby) method
208 if (!namespace_ignore_builtin_primitive_methods_p(ns, cme->def)) {
209 if (permit_calling_builtin || (proc_ns && NAMESPACE_USER_P(proc_ns)))
210 return ns;
211 }
212 }
213 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
214 }
215 else {
216 calling = 0;
217 }
218 }
219 // not in namespace-marked method calls
220 ns = th->ns;
221 if (ns) {
222 return ns;
223 }
224 if (!main_namespace) {
225 // Namespaces are not ready to be created
226 return root_namespace;
227 }
228 return main_namespace;
229}
230
231const rb_namespace_t *
232rb_current_namespace(void)
233{
234 return current_namespace(true);
235}
236
237const rb_namespace_t *
238rb_loading_namespace(void)
239{
240 VALUE namespace;
241 long len;
242 VALUE require_stack = GET_VM()->require_stack;
243
244 if (!rb_namespace_available())
245 return 0;
246
247 if (!require_stack) {
248 return current_namespace(false);
249 }
250 if ((len = RARRAY_LEN(require_stack)) == 0) {
251 return current_namespace(false);
252 }
253
254 if (!RB_TYPE_P(require_stack, T_ARRAY))
255 rb_bug("require_stack is not an array: %s", rb_type_str(BUILTIN_TYPE(require_stack)));
256
257 namespace = RARRAY_AREF(require_stack, len-1);
258 return rb_get_namespace_t(namespace);
259}
260
261const rb_namespace_t *
262rb_definition_namespace(void)
263{
264 const rb_namespace_t *ns = current_namespace(true);
265 if (NAMESPACE_BUILTIN_P(ns)) {
266 return root_namespace;
267 }
268 return ns;
269}
270
271static long namespace_id_counter = 0;
272
273static long
274namespace_generate_id(void)
275{
276 long id;
277 RB_VM_LOCKING() {
278 id = ++namespace_id_counter;
279 }
280 return id;
281}
282
283static void
284namespace_entry_initialize(rb_namespace_t *ns)
285{
286 rb_vm_t *vm = GET_VM();
287
288 // These will be updated immediately
289 ns->ns_object = 0;
290 ns->ns_id = 0;
291
292 ns->top_self = 0;
293 ns->load_path = rb_ary_dup(vm->load_path);
294 ns->expanded_load_path = rb_ary_dup(vm->expanded_load_path);
295 ns->load_path_snapshot = rb_ary_new();
296 ns->load_path_check_cache = 0;
297 ns->loaded_features = rb_ary_dup(vm->loaded_features);
298 ns->loaded_features_snapshot = rb_ary_new();
299 ns->loaded_features_index = st_init_numtable();
300 ns->loaded_features_realpaths = rb_hash_dup(vm->loaded_features_realpaths);
301 ns->loaded_features_realpath_map = rb_hash_dup(vm->loaded_features_realpath_map);
302 ns->loading_table = st_init_strtable();
303 ns->ruby_dln_libmap = rb_hash_new_with_size(0);
304 ns->gvar_tbl = rb_hash_new_with_size(0);
305
306 ns->is_builtin = false;
307 ns->is_user = true;
308 ns->is_optional = true;
309}
310
311void rb_namespace_gc_update_references(void *ptr)
312{
313 rb_namespace_t *ns = (rb_namespace_t *)ptr;
314 if (!NIL_P(ns->ns_object))
315 ns->ns_object = rb_gc_location(ns->ns_object);
316 ns->top_self = rb_gc_location(ns->top_self);
317 ns->load_path = rb_gc_location(ns->load_path);
318 ns->expanded_load_path = rb_gc_location(ns->expanded_load_path);
319 ns->load_path_snapshot = rb_gc_location(ns->load_path_snapshot);
320 if (ns->load_path_check_cache) {
321 ns->load_path_check_cache = rb_gc_location(ns->load_path_check_cache);
322 }
323 ns->loaded_features = rb_gc_location(ns->loaded_features);
324 ns->loaded_features_snapshot = rb_gc_location(ns->loaded_features_snapshot);
325 ns->loaded_features_realpaths = rb_gc_location(ns->loaded_features_realpaths);
326 ns->loaded_features_realpath_map = rb_gc_location(ns->loaded_features_realpath_map);
327 ns->ruby_dln_libmap = rb_gc_location(ns->ruby_dln_libmap);
328 ns->gvar_tbl = rb_gc_location(ns->gvar_tbl);
329}
330
331void
332rb_namespace_entry_mark(void *ptr)
333{
334 const rb_namespace_t *ns = (rb_namespace_t *)ptr;
335 rb_gc_mark(ns->ns_object);
336 rb_gc_mark(ns->top_self);
337 rb_gc_mark(ns->load_path);
338 rb_gc_mark(ns->expanded_load_path);
339 rb_gc_mark(ns->load_path_snapshot);
340 rb_gc_mark(ns->load_path_check_cache);
341 rb_gc_mark(ns->loaded_features);
342 rb_gc_mark(ns->loaded_features_snapshot);
343 rb_gc_mark(ns->loaded_features_realpaths);
344 rb_gc_mark(ns->loaded_features_realpath_map);
345 if (ns->loading_table) {
346 rb_mark_tbl(ns->loading_table);
347 }
348 rb_gc_mark(ns->ruby_dln_libmap);
349 rb_gc_mark(ns->gvar_tbl);
350}
351
352#define namespace_entry_free RUBY_TYPED_DEFAULT_FREE
353
354static size_t
355namespace_entry_memsize(const void *ptr)
356{
357 return sizeof(rb_namespace_t);
358}
359
360const rb_data_type_t rb_namespace_data_type = {
361 "Namespace::Entry",
362 {
363 rb_namespace_entry_mark,
364 namespace_entry_free,
365 namespace_entry_memsize,
366 rb_namespace_gc_update_references,
367 },
368 0, 0, RUBY_TYPED_FREE_IMMEDIATELY // TODO: enable RUBY_TYPED_WB_PROTECTED when inserting write barriers
369};
370
371VALUE
372rb_namespace_entry_alloc(VALUE klass)
373{
374 rb_namespace_t *entry;
375 VALUE obj = TypedData_Make_Struct(klass, rb_namespace_t, &rb_namespace_data_type, entry);
376 namespace_entry_initialize(entry);
377 return obj;
378}
379
380static rb_namespace_t *
381get_namespace_struct_internal(VALUE entry)
382{
383 rb_namespace_t *sval;
384 TypedData_Get_Struct(entry, rb_namespace_t, &rb_namespace_data_type, sval);
385 return sval;
386}
387
389rb_get_namespace_t(VALUE namespace)
390{
391 VALUE entry;
392 ID id_namespace_entry;
393
394 if (!namespace)
395 return root_namespace;
396 if (NIL_P(namespace))
397 return builtin_namespace;
398
399 CONST_ID(id_namespace_entry, "__namespace_entry__");
400 entry = rb_attr_get(namespace, id_namespace_entry);
401 return get_namespace_struct_internal(entry);
402}
403
404VALUE
405rb_get_namespace_object(rb_namespace_t *ns)
406{
407 if (!ns) // root namespace
408 return Qfalse;
409 return ns->ns_object;
410}
411
412static void setup_pushing_loading_namespace(rb_namespace_t *ns);
413
414/*
415 * call-seq:
416 * Namespace.new -> new_namespace
417 *
418 * Returns a new Namespace object.
419 */
420static VALUE
421namespace_initialize(VALUE namespace)
422{
423 rb_namespace_t *ns;
424 rb_classext_t *object_classext;
425 VALUE entry;
426 ID id_namespace_entry;
427 CONST_ID(id_namespace_entry, "__namespace_entry__");
428
429 if (!rb_namespace_available()) {
430 rb_raise(rb_eRuntimeError, "Namespace is disabled. Set RUBY_NAMESPACE=1 environment variable to use Namespace.");
431 }
432
433 entry = rb_class_new_instance_pass_kw(0, NULL, rb_cNamespaceEntry);
434 ns = get_namespace_struct_internal(entry);
435
436 ns->ns_object = namespace;
437 ns->ns_id = namespace_generate_id();
438 ns->load_path = rb_ary_dup(GET_VM()->load_path);
439 ns->is_user = true;
440 rb_define_singleton_method(ns->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
441
442 // Set the Namespace object unique/consistent from any namespaces to have just single
443 // constant table from any view of every (including main) namespace.
444 // If a code in the namespace adds a constant, the constant will be visible even from root/main.
445 RCLASS_SET_PRIME_CLASSEXT_WRITABLE(namespace, true);
446
447 // Get a clean constant table of Object even by writable one
448 // because ns was just created, so it has not touched any constants yet.
449 object_classext = RCLASS_EXT_WRITABLE_IN_NS(rb_cObject, ns);
450 RCLASS_SET_CONST_TBL(namespace, RCLASSEXT_CONST_TBL(object_classext), true);
451
452 rb_ivar_set(namespace, id_namespace_entry, entry);
453
454 setup_pushing_loading_namespace(ns);
455
456 return namespace;
457}
458
459/*
460 * call-seq:
461 * Namespace.enabled? -> true or false
462 *
463 * Returns +true+ if namespace is enabled.
464 */
465static VALUE
466rb_namespace_s_getenabled(VALUE namespace)
467{
468 return RBOOL(rb_namespace_available());
469}
470
471/*
472 * call-seq:
473 * Namespace.current -> namespace, nil or false
474 *
475 * Returns the current namespace.
476 * Returns +nil+ if it is the built-in namespace.
477 * Returns +false+ if namespace is not enabled.
478 */
479static VALUE
480rb_namespace_current(VALUE klass)
481{
482 const rb_namespace_t *ns = rb_current_namespace();
483 if (NAMESPACE_USER_P(ns)) {
484 return ns->ns_object;
485 }
486 if (NAMESPACE_BUILTIN_P(ns)) {
487 return Qnil;
488 }
489 return Qfalse;
490}
491
492/*
493 * call-seq:
494 * Namespace.is_builtin?(klass) -> true or false
495 *
496 * Returns +true+ if +klass+ is only in a user namespace.
497 */
498static VALUE
499rb_namespace_s_is_builtin_p(VALUE namespace, VALUE klass)
500{
501 if (RCLASS_PRIME_CLASSEXT_READABLE_P(klass) && !RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass))
502 return Qtrue;
503 return Qfalse;
504}
505
506/*
507 * call-seq:
508 * load_path -> array
509 *
510 * Returns namespace local load path.
511 */
512static VALUE
513rb_namespace_load_path(VALUE namespace)
514{
515 return rb_get_namespace_t(namespace)->load_path;
516}
517
518#ifdef _WIN32
519UINT rb_w32_system_tmpdir(WCHAR *path, UINT len);
520#endif
521
522/* Copied from mjit.c Ruby 3.0.3 */
523static char *
524system_default_tmpdir(void)
525{
526 // c.f. ext/etc/etc.c:etc_systmpdir()
527#ifdef _WIN32
528 WCHAR tmppath[_MAX_PATH];
529 UINT len = rb_w32_system_tmpdir(tmppath, numberof(tmppath));
530 if (len) {
531 int blen = WideCharToMultiByte(CP_UTF8, 0, tmppath, len, NULL, 0, NULL, NULL);
532 char *tmpdir = xmalloc(blen + 1);
533 WideCharToMultiByte(CP_UTF8, 0, tmppath, len, tmpdir, blen, NULL, NULL);
534 tmpdir[blen] = '\0';
535 return tmpdir;
536 }
537#elif defined _CS_DARWIN_USER_TEMP_DIR
538 char path[MAXPATHLEN];
539 size_t len = confstr(_CS_DARWIN_USER_TEMP_DIR, path, sizeof(path));
540 if (len > 0) {
541 char *tmpdir = xmalloc(len);
542 if (len > sizeof(path)) {
543 confstr(_CS_DARWIN_USER_TEMP_DIR, tmpdir, len);
544 }
545 else {
546 memcpy(tmpdir, path, len);
547 }
548 return tmpdir;
549 }
550#endif
551 return 0;
552}
553
554static int
555check_tmpdir(const char *dir)
556{
557 struct stat st;
558
559 if (!dir) return FALSE;
560 if (stat(dir, &st)) return FALSE;
561#ifndef S_ISDIR
562# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
563#endif
564 if (!S_ISDIR(st.st_mode)) return FALSE;
565#ifndef _WIN32
566# ifndef S_IWOTH
567# define S_IWOTH 002
568# endif
569 if (st.st_mode & S_IWOTH) {
570# ifdef S_ISVTX
571 if (!(st.st_mode & S_ISVTX)) return FALSE;
572# else
573 return FALSE;
574# endif
575 }
576 if (access(dir, W_OK)) return FALSE;
577#endif
578 return TRUE;
579}
580
581static char *
582system_tmpdir(void)
583{
584 char *tmpdir;
585# define RETURN_ENV(name) \
586 if (check_tmpdir(tmpdir = getenv(name))) return ruby_strdup(tmpdir)
587 RETURN_ENV("TMPDIR");
588 RETURN_ENV("TMP");
589 tmpdir = system_default_tmpdir();
590 if (check_tmpdir(tmpdir)) return tmpdir;
591 return ruby_strdup("/tmp");
592# undef RETURN_ENV
593}
594
595/* end of copy */
596
597static int
598sprint_ext_filename(char *str, size_t size, long namespace_id, const char *prefix, const char *basename)
599{
600 if (tmp_dir_has_dirsep) {
601 return snprintf(str, size, "%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, prefix, getpid(), namespace_id, basename);
602 }
603 return snprintf(str, size, "%s%s%sp%"PRI_PIDT_PREFIX"u_%ld_%s", tmp_dir, DIRSEP, prefix, getpid(), namespace_id, basename);
604}
605
606#ifdef _WIN32
607static const char *
608copy_ext_file_error(char *message, size_t size)
609{
610 int error = GetLastError();
611 char *p = message;
612 size_t len = snprintf(message, size, "%d: ", error);
613
614#define format_message(sublang) FormatMessage(\
615 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
616 NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
617 message + len, size - len, NULL)
618 if (format_message(SUBLANG_ENGLISH_US) == 0)
619 format_message(SUBLANG_DEFAULT);
620 for (p = message + len; *p; p++) {
621 if (*p == '\n' || *p == '\r')
622 *p = ' ';
623 }
624 return message;
625}
626#else
627static const char *
628copy_ext_file_error(char *message, size_t size, int copy_retvalue, char *src_path, char *dst_path)
629{
630 switch (copy_retvalue) {
631 case 1:
632 snprintf(message, size, "can't open the extension path: %s", src_path);
633 case 2:
634 snprintf(message, size, "can't open the file to write: %s", dst_path);
635 case 3:
636 snprintf(message, size, "failed to read the extension path: %s", src_path);
637 case 4:
638 snprintf(message, size, "failed to write the extension path: %s", dst_path);
639 default:
640 rb_bug("unknown return value of copy_ext_file: %d", copy_retvalue);
641 }
642 return message;
643}
644#endif
645
646static int
647copy_ext_file(char *src_path, char *dst_path)
648{
649#if defined(_WIN32)
650 int rvalue;
651
652 WCHAR *w_src = rb_w32_mbstr_to_wstr(CP_UTF8, src_path, -1, NULL);
653 WCHAR *w_dst = rb_w32_mbstr_to_wstr(CP_UTF8, dst_path, -1, NULL);
654 if (!w_src || !w_dst) {
655 rb_memerror();
656 }
657
658 rvalue = CopyFileW(w_src, w_dst, FALSE) ? 0 : 1;
659 free(w_src);
660 free(w_dst);
661 return rvalue;
662#else
663 FILE *src, *dst;
664 char buffer[1024];
665 size_t read = 0, wrote, written = 0;
666 size_t maxread = sizeof(buffer);
667 int eof = 0;
668 int clean_read = 1;
669 int retvalue = 0;
670
671 src = fopen(src_path, "rb");
672 if (!src) {
673 return 1;
674 }
675 dst = fopen(dst_path, "wb");
676 if (!dst) {
677 return 2;
678 }
679 while (!eof) {
680 if (clean_read) {
681 read = fread(buffer, 1, sizeof(buffer), src);
682 written = 0;
683 }
684 if (read > 0) {
685 wrote = fwrite(buffer+written, 1, read-written, dst);
686 if (wrote < read-written) {
687 if (ferror(dst)) {
688 retvalue = 4;
689 break;
690 }
691 else { // partial write
692 clean_read = 0;
693 written += wrote;
694 }
695 }
696 else { // Wrote the entire buffer to dst, next read is clean one
697 clean_read = 1;
698 }
699 }
700 if (read < maxread) {
701 if (clean_read && feof(src)) {
702 // If it's not clean, buffer should have bytes not written yet.
703 eof = 1;
704 }
705 else if (ferror(src)) {
706 retvalue = 3;
707 // Writes could be partial/dirty, but this load is failure anyway
708 break;
709 }
710 }
711 }
712 fclose(src);
713 fclose(dst);
714 return retvalue;
715#endif
716}
717
718#if defined __CYGWIN__ || defined DOSISH
719#define isdirsep(x) ((x) == '/' || (x) == '\\')
720#else
721#define isdirsep(x) ((x) == '/')
722#endif
723
724#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
725#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
726
727static void
728fname_without_suffix(char *fname, char *rvalue)
729{
730 char *pos;
731 strcpy(rvalue, fname);
732 for (pos = rvalue + strlen(fname); pos > rvalue; pos--) {
733 if (IS_SOEXT(pos) || IS_DLEXT(pos)) {
734 *pos = '\0';
735 return;
736 }
737 }
738}
739
740static void
741escaped_basename(char *path, char *fname, char *rvalue)
742{
743 char *pos, *leaf, *found;
744 leaf = path;
745 // `leaf + 1` looks uncomfortable (when leaf == path), but fname must not be the top-dir itself
746 while ((found = strstr(leaf + 1, fname)) != NULL) {
747 leaf = found; // find the last occurrence for the path like /etc/my-crazy-lib-dir/etc.so
748 }
749 strcpy(rvalue, leaf);
750 for (pos = rvalue; *pos; pos++) {
751 if (isdirsep(*pos)) {
752 *pos = '+';
753 }
754 }
755}
756
757VALUE
758rb_namespace_local_extension(VALUE namespace, VALUE fname, VALUE path)
759{
760 char ext_path[MAXPATHLEN], fname2[MAXPATHLEN], basename[MAXPATHLEN];
761 int copy_error, wrote;
762 char *src_path = RSTRING_PTR(path), *fname_ptr = RSTRING_PTR(fname);
763 rb_namespace_t *ns = rb_get_namespace_t(namespace);
764
765 fname_without_suffix(fname_ptr, fname2);
766 escaped_basename(src_path, fname2, basename);
767
768 wrote = sprint_ext_filename(ext_path, sizeof(ext_path), ns->ns_id, NAMESPACE_TMP_PREFIX, basename);
769 if (wrote >= (int)sizeof(ext_path)) {
770 rb_bug("Extension file path in namespace was too long");
771 }
772 copy_error = copy_ext_file(src_path, ext_path);
773 if (copy_error) {
774 char message[1024];
775#if defined(_WIN32)
776 copy_ext_file_error(message, sizeof(message));
777#else
778 copy_ext_file_error(message, sizeof(message), copy_error, src_path, ext_path);
779#endif
780 rb_raise(rb_eLoadError, "can't prepare the extension file for namespaces (%s from %s): %s", ext_path, src_path, message);
781 }
782 // TODO: register the path to be clean-uped
783 return rb_str_new_cstr(ext_path);
784}
785
786// TODO: delete it just after dln_load? or delay it?
787// At least for _WIN32, deleting extension files should be delayed until the namespace's destructor.
788// And it requires calling dlclose before deleting it.
789
790static void
791namespace_push(rb_thread_t *th, VALUE namespace)
792{
793 if (RTEST(th->namespaces)) {
794 rb_ary_push(th->namespaces, namespace);
795 }
796 else {
797 th->namespaces = rb_ary_new_from_args(1, namespace);
798 }
799 th->ns = rb_get_namespace_t(namespace);
800}
801
802static VALUE
803namespace_pop(VALUE th_value)
804{
805 VALUE upper_ns;
806 long stack_len;
807 rb_thread_t *th = (rb_thread_t *)th_value;
808 VALUE namespaces = th->namespaces;
809 if (!namespaces) {
810 rb_bug("Too many namespace pops");
811 }
812 rb_ary_pop(namespaces);
813 stack_len = RARRAY_LEN(namespaces);
814 if (stack_len == 0) {
815 th->namespaces = 0;
816 th->ns = main_namespace;
817 }
818 else {
819 upper_ns = RARRAY_AREF(namespaces, stack_len-1);
820 th->ns = rb_get_namespace_t(upper_ns);
821 }
822 return Qnil;
823}
824
825VALUE
826rb_namespace_exec(const rb_namespace_t *ns, namespace_exec_func *func, VALUE arg)
827{
828 rb_thread_t *th = GET_THREAD();
829 namespace_push(th, ns ? ns->ns_object : Qnil);
830 return rb_ensure(func, arg, namespace_pop, (VALUE)th);
831}
832
834 rb_thread_t *th;
835 rb_namespace_t *ns;
836};
837
838static VALUE
839namespace_both_pop(VALUE arg)
840{
841 struct namespace_pop2_arg *data = (struct namespace_pop2_arg *)arg;
842 namespace_pop((VALUE) data->th);
843 rb_namespace_pop_loading_namespace(data->ns);
844 return Qnil;
845}
846
847static VALUE
848rb_namespace_load(int argc, VALUE *argv, VALUE namespace)
849{
850 VALUE fname, wrap;
851 rb_thread_t *th = GET_THREAD();
852 rb_namespace_t *ns = rb_get_namespace_t(namespace);
853
854 rb_scan_args(argc, argv, "11", &fname, &wrap);
855
856 VALUE args = rb_ary_new_from_args(2, fname, wrap);
857 namespace_push(th, namespace);
858 rb_namespace_push_loading_namespace(ns);
859 struct namespace_pop2_arg arg = {
860 .th = th,
861 .ns = ns
862 };
863 return rb_ensure(rb_load_entrypoint, args, namespace_both_pop, (VALUE)&arg);
864}
865
866static VALUE
867rb_namespace_require(VALUE namespace, VALUE fname)
868{
869 rb_thread_t *th = GET_THREAD();
870 rb_namespace_t *ns = rb_get_namespace_t(namespace);
871 namespace_push(th, namespace);
872 rb_namespace_push_loading_namespace(ns);
873 struct namespace_pop2_arg arg = {
874 .th = th,
875 .ns = ns
876 };
877 return rb_ensure(rb_require_string, fname, namespace_both_pop, (VALUE)&arg);
878}
879
880static VALUE
881rb_namespace_require_relative(VALUE namespace, VALUE fname)
882{
883 rb_thread_t *th = GET_THREAD();
884 rb_namespace_t *ns = rb_get_namespace_t(namespace);
885 namespace_push(th, namespace);
886 rb_namespace_push_loading_namespace(ns);
887 struct namespace_pop2_arg arg = {
888 .th = th,
889 .ns = ns
890 };
891 return rb_ensure(rb_require_relative_entrypoint, fname, namespace_both_pop, (VALUE)&arg);
892}
893
894static VALUE
895rb_namespace_eval_string(VALUE str)
896{
897 return rb_eval_string(RSTRING_PTR(str));
898}
899
900static VALUE
901rb_namespace_eval(VALUE namespace, VALUE str)
902{
903 rb_thread_t *th = GET_THREAD();
904
905 StringValue(str);
906
907 namespace_push(th, namespace);
908 return rb_ensure(rb_namespace_eval_string, str, namespace_pop, (VALUE)th);
909}
910
911static int namespace_experimental_warned = 0;
912
913void
914rb_initialize_main_namespace(void)
915{
916 rb_namespace_t *ns;
917 rb_vm_t *vm = GET_VM();
918 rb_thread_t *th = GET_THREAD();
919 VALUE main_ns;
920
921 if (!namespace_experimental_warned) {
923 "Namespace is experimental, and the behavior may change in the future!\n"
924 "See doc/namespace.md for known issues, etc.");
925 namespace_experimental_warned = 1;
926 }
927
929 ns = rb_get_namespace_t(main_ns);
930 ns->ns_object = main_ns;
931 ns->ns_id = namespace_generate_id();
932 ns->is_builtin = false;
933 ns->is_user = true;
934 ns->is_optional = false;
935
936 rb_const_set(rb_cNamespace, rb_intern("MAIN"), main_ns);
937
938 vm->main_namespace = th->ns = main_namespace = ns;
939}
940
941static VALUE
942rb_namespace_inspect(VALUE obj)
943{
944 rb_namespace_t *ns;
945 VALUE r;
946 if (obj == Qfalse) {
947 r = rb_str_new_cstr("#<Namespace:root>");
948 return r;
949 }
950 ns = rb_get_namespace_t(obj);
951 r = rb_str_new_cstr("#<Namespace:");
952 rb_str_concat(r, rb_funcall(LONG2NUM(ns->ns_id), rb_intern("to_s"), 0));
953 if (NAMESPACE_BUILTIN_P(ns)) {
954 rb_str_cat_cstr(r, ",builtin");
955 }
956 if (NAMESPACE_USER_P(ns)) {
957 rb_str_cat_cstr(r, ",user");
958 }
959 if (NAMESPACE_MAIN_P(ns)) {
960 rb_str_cat_cstr(r, ",main");
961 }
962 else if (NAMESPACE_OPTIONAL_P(ns)) {
963 rb_str_cat_cstr(r, ",optional");
964 }
965 rb_str_cat_cstr(r, ">");
966 return r;
967}
968
970 int argc;
971 VALUE *argv;
972};
973
974static VALUE
975namespace_builtin_refiner_calling_super(VALUE arg)
976{
977 struct refiner_calling_super_data *data = (struct refiner_calling_super_data *)arg;
978 return rb_call_super(data->argc, data->argv);
979}
980
981static VALUE
982namespace_builtin_refiner_loading_func_ensure(VALUE _)
983{
984 rb_vm_t *vm = GET_VM();
985 if (!vm->require_stack)
986 rb_bug("require_stack is not ready but the namespace refiner is called");
987 rb_namespace_disable_builtin();
988 return Qnil;
989}
990
991static VALUE
992rb_namespace_builtin_refiner_loading_func(int argc, VALUE *argv, VALUE _self)
993{
994 rb_vm_t *vm = GET_VM();
995 if (!vm->require_stack)
996 rb_bug("require_stack is not ready but the namespace refiner is called");
997 rb_namespace_enable_builtin();
998 // const rb_namespace_t *ns = rb_loading_namespace();
999 // printf("N:current loading ns: %ld\n", ns->ns_id);
1000 struct refiner_calling_super_data data = {
1001 .argc = argc,
1002 .argv = argv
1003 };
1004 return rb_ensure(namespace_builtin_refiner_calling_super, (VALUE)&data,
1005 namespace_builtin_refiner_loading_func_ensure, Qnil);
1006}
1007
1008static void
1009setup_builtin_refinement(VALUE mod)
1010{
1011 struct rb_refinements_data data;
1012 rb_refinement_setup(&data, mod, rb_mKernel);
1013 rb_define_method(data.refinement, "require", rb_namespace_builtin_refiner_loading_func, -1);
1014 rb_define_method(data.refinement, "require_relative", rb_namespace_builtin_refiner_loading_func, -1);
1015 rb_define_method(data.refinement, "load", rb_namespace_builtin_refiner_loading_func, -1);
1016}
1017
1018static VALUE
1019namespace_user_loading_func_calling_super(VALUE arg)
1020{
1021 struct refiner_calling_super_data *data = (struct refiner_calling_super_data *)arg;
1022 return rb_call_super(data->argc, data->argv);
1023}
1024
1025static VALUE
1026namespace_user_loading_func_ensure(VALUE arg)
1027{
1028 rb_namespace_t *ns = (rb_namespace_t *)arg;
1029 rb_namespace_pop_loading_namespace(ns);
1030 return Qnil;
1031}
1032
1033static VALUE
1034rb_namespace_user_loading_func(int argc, VALUE *argv, VALUE _self)
1035{
1036 const rb_namespace_t *ns;
1037 rb_vm_t *vm = GET_VM();
1038 if (!vm->require_stack)
1039 rb_bug("require_stack is not ready but require/load is called in user namespaces");
1040 ns = rb_current_namespace();
1041 VM_ASSERT(rb_namespace_available() || !ns);
1042 rb_namespace_push_loading_namespace(ns);
1043 struct refiner_calling_super_data data = {
1044 .argc = argc,
1045 .argv = argv
1046 };
1047 return rb_ensure(namespace_user_loading_func_calling_super, (VALUE)&data,
1048 namespace_user_loading_func_ensure, (VALUE)ns);
1049}
1050
1051static VALUE
1052setup_pushing_loading_namespace_include(VALUE mod)
1053{
1054 rb_include_module(rb_cObject, mod);
1055 return Qnil;
1056}
1057
1058static void
1059setup_pushing_loading_namespace(rb_namespace_t *ns)
1060{
1061 rb_namespace_exec(ns, setup_pushing_loading_namespace_include, rb_mNamespaceLoader);
1062}
1063
1064static void
1065namespace_define_loader_method(const char *name)
1066{
1067 rb_define_private_method(rb_mNamespaceLoader, name, rb_namespace_user_loading_func, -1);
1068 rb_define_singleton_method(rb_mNamespaceLoader, name, rb_namespace_user_loading_func, -1);
1069}
1070
1071void
1072Init_enable_namespace(void)
1073{
1074 const char *env = getenv("RUBY_NAMESPACE");
1075 if (env && strlen(env) == 1 && env[0] == '1') {
1076 ruby_namespace_enabled = true;
1077 }
1078 else {
1079 ruby_namespace_init_done = true;
1080 }
1081}
1082
1083/*
1084 * Document-class: Namespace
1085 *
1086 * Namespace is designed to provide separated spaces in a Ruby
1087 * process, to isolate applications and libraries.
1088 * See {Namespace}[rdoc-ref:namespace.md].
1089 */
1090void
1091Init_Namespace(void)
1092{
1093 tmp_dir = system_tmpdir();
1094 tmp_dir_has_dirsep = (strcmp(tmp_dir + (strlen(tmp_dir) - strlen(DIRSEP)), DIRSEP) == 0);
1095
1097 rb_define_method(rb_cNamespace, "initialize", namespace_initialize, 0);
1098
1099 /* :nodoc: */
1100 rb_cNamespaceEntry = rb_define_class_under(rb_cNamespace, "Entry", rb_cObject);
1101 rb_define_alloc_func(rb_cNamespaceEntry, rb_namespace_entry_alloc);
1102
1103 /* :nodoc: */
1105 if (rb_namespace_available()) {
1106 setup_builtin_refinement(rb_mNamespaceRefiner);
1107 }
1108
1109 /* :nodoc: */
1110 rb_mNamespaceLoader = rb_define_module_under(rb_cNamespace, "Loader");
1111 namespace_define_loader_method("require");
1112 namespace_define_loader_method("require_relative");
1113 namespace_define_loader_method("load");
1114
1115 rb_define_singleton_method(rb_cNamespace, "enabled?", rb_namespace_s_getenabled, 0);
1116 rb_define_singleton_method(rb_cNamespace, "current", rb_namespace_current, 0);
1117 rb_define_singleton_method(rb_cNamespace, "is_builtin?", rb_namespace_s_is_builtin_p, 1);
1118
1119 rb_define_method(rb_cNamespace, "load_path", rb_namespace_load_path, 0);
1120 rb_define_method(rb_cNamespace, "load", rb_namespace_load, -1);
1121 rb_define_method(rb_cNamespace, "require", rb_namespace_require, 1);
1122 rb_define_method(rb_cNamespace, "require_relative", rb_namespace_require_relative, 1);
1123 rb_define_method(rb_cNamespace, "eval", rb_namespace_eval, 1);
1124
1125 rb_define_method(rb_cNamespace, "inspect", rb_namespace_inspect, 0);
1126
1127 rb_vm_t *vm = GET_VM();
1128 vm->require_stack = rb_ary_new();
1129}
#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.
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:1691
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1474
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1510
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1620
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:3133
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define Qtrue
Old name of RUBY_Qtrue.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#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_mKernel
Kernel module.
Definition object.c:61
VALUE rb_cNamespace
Namespace class.
Definition namespace.c:20
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:2141
VALUE rb_cModule
Module class.
Definition object.c:63
VALUE rb_mNamespaceRefiner
Namespace::Refiner module.
Definition namespace.c:22
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
VALUE rb_eval_string(const char *str)
Evaluates the given string.
Definition vm_eval.c:2083
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_pop(VALUE ary)
Destructively deletes an element from the end of the passed array and returns what was deleted.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
Definition load.c:1555
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:3994
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1656
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
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:2126
void rb_const_set(VALUE space, ID name, VALUE val)
Names a constant.
Definition variable.c:4062
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
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#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 RARRAY_AREF(a, i)
Definition rarray.h:403
#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:523
#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:505
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition method.h:63
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:204
const rb_iseq_t * iseqptr
iseq pointer, should be separated from iseqval
Definition method.h:136
Internal header for Namespace.
Definition namespace.h:14
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