Skip to content

Commit 126b657

Browse files
committed
Use rb_ensure instead of guard objects for Dir.pwd
This replaces GC-based buffer guards (rb_imemo_tmpbuf, TypedData_Wrap_Struct) with rb_ensure to clean up malloc/xmalloc memory when an exception occurs.
1 parent 06c8b1a commit 126b657

2 files changed

Lines changed: 36 additions & 32 deletions

File tree

dir.c

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,23 +1586,29 @@ dir_chdir(VALUE dir)
15861586
}
15871587

15881588
#ifndef _WIN32
1589-
VALUE
1590-
rb_dir_getwd_ospath(void)
1589+
static VALUE
1590+
getcwd_to_str(VALUE arg)
15911591
{
1592-
char *path;
1593-
VALUE cwd;
1594-
VALUE path_guard;
1595-
1596-
path_guard = rb_imemo_tmpbuf_new();
1597-
path = ruby_getcwd();
1598-
rb_imemo_tmpbuf_set_ptr(path_guard, path);
1592+
const char *path = (const char *)arg;
15991593
#ifdef __APPLE__
1600-
cwd = rb_str_normalize_ospath(path, strlen(path));
1594+
return rb_str_normalize_ospath(path, strlen(path));
16011595
#else
1602-
cwd = rb_str_new2(path);
1596+
return rb_str_new2(path);
16031597
#endif
1604-
rb_free_tmp_buffer(&path_guard);
1605-
return cwd;
1598+
}
1599+
1600+
static VALUE
1601+
getcwd_xfree(VALUE arg)
1602+
{
1603+
xfree((void *)arg);
1604+
return Qnil;
1605+
}
1606+
1607+
VALUE
1608+
rb_dir_getwd_ospath(void)
1609+
{
1610+
char *path = ruby_getcwd();
1611+
return rb_ensure(getcwd_to_str, (VALUE)path, getcwd_xfree, (VALUE)path);
16061612
}
16071613
#endif
16081614

util.c

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -529,45 +529,43 @@ ruby_strdup(const char *str)
529529
char *
530530
ruby_getcwd(void)
531531
{
532-
VALUE guard = rb_imemo_tmpbuf_new();
533532
int size = 200;
534533
char *buf = xmalloc(size);
535534

536535
while (!getcwd(buf, size)) {
537536
int e = errno;
538537
if (e != ERANGE) {
539-
rb_free_tmp_buffer(&guard);
538+
xfree(buf);
540539
rb_syserr_fail(e, "getcwd");
541540
}
542541
size *= 2;
543-
rb_imemo_tmpbuf_set_ptr(guard, buf);
544-
buf = xrealloc(buf, size);
542+
xfree(buf);
543+
buf = xmalloc(size);
545544
}
546-
rb_imemo_tmpbuf_set_ptr(guard, NULL);
547545
return buf;
548546
}
549547

550548
# else
551549

552-
static const rb_data_type_t getcwd_buffer_guard_type = {
553-
.wrap_struct_name = "ruby_getcwd_guard",
554-
.function = {
555-
.dfree = free // not xfree.
556-
},
557-
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
558-
};
550+
static VALUE
551+
getcwd_strdup(VALUE arg)
552+
{
553+
return (VALUE)ruby_strdup((const char *)arg);
554+
}
555+
556+
static VALUE
557+
getcwd_free(VALUE arg)
558+
{
559+
free((void *)arg);
560+
return Qnil;
561+
}
559562

560563
char *
561564
ruby_getcwd(void)
562565
{
563-
VALUE guard = TypedData_Wrap_Struct((VALUE)0, &getcwd_buffer_guard_type, NULL);
564-
char *buf, *cwd = getcwd(NULL, 0);
565-
RTYPEDDATA_DATA(guard) = cwd;
566+
char *cwd = getcwd(NULL, 0);
566567
if (!cwd) rb_sys_fail("getcwd");
567-
buf = ruby_strdup(cwd); /* allocate by xmalloc */
568-
free(cwd);
569-
RTYPEDDATA_DATA(RB_GC_GUARD(guard)) = NULL;
570-
return buf;
568+
return (char *)rb_ensure(getcwd_strdup, (VALUE)cwd, getcwd_free, (VALUE)cwd);
571569
}
572570

573571
# endif

0 commit comments

Comments
 (0)