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