summaryrefslogtreecommitdiff
path: root/ext/objspace
diff options
context:
space:
mode:
authorPeter Zhu <peter@peterzhu.ca>2023-01-03 10:59:47 -0500
committerPeter Zhu <peter@peterzhu.ca>2023-01-04 09:10:58 -0500
commitb8a3f1bd456f92866c4a7bd83235f78c574784a8 (patch)
tree843a013bce52ba539df4056462e7be51e01b65a0 /ext/objspace
parent3bcf92d8afb62a10dd4c700a4925d2ccac43f5a2 (diff)
downloadruby-b8a3f1bd456f92866c4a7bd83235f78c574784a8.tar.gz
Fix crash in tracing object allocations
ObjectSpace.trace_object_allocations_start could crash since it adds a TracePoint for when objects are freed. However, TracePoint could crash since it modifies st tables while inside the GC that is trying to free the object. This could cause a memory allocation to happen which would crash if it triggers another GC. See a crash log: http://ci.rvm.jp/results/trunk@ruby-sp1/4373707
Diffstat (limited to 'ext/objspace')
-rw-r--r--ext/objspace/depend1
-rw-r--r--ext/objspace/object_tracing.c7
2 files changed, 8 insertions, 0 deletions
diff --git a/ext/objspace/depend b/ext/objspace/depend
index de5fa6c6a3..435ed294b9 100644
--- a/ext/objspace/depend
+++ b/ext/objspace/depend
@@ -158,6 +158,7 @@ object_tracing.o: $(hdrdir)/ruby/missing.h
object_tracing.o: $(hdrdir)/ruby/ruby.h
object_tracing.o: $(hdrdir)/ruby/st.h
object_tracing.o: $(hdrdir)/ruby/subst.h
+object_tracing.o: $(top_srcdir)/gc.h
object_tracing.o: $(top_srcdir)/internal.h
object_tracing.o: object_tracing.c
object_tracing.o: objspace.h
diff --git a/ext/objspace/object_tracing.c b/ext/objspace/object_tracing.c
index 0bf866a8f1..8c54d51eab 100644
--- a/ext/objspace/object_tracing.c
+++ b/ext/objspace/object_tracing.c
@@ -13,6 +13,7 @@
**********************************************************************/
+#include "gc.h"
#include "internal.h"
#include "ruby/debug.h"
#include "objspace.h"
@@ -121,6 +122,10 @@ freeobj_i(VALUE tpval, void *data)
st_data_t v;
struct allocation_info *info;
+ /* Modifying the st table can cause allocations, which can trigger GC.
+ * Since freeobj_i is called during GC, it must not trigger another GC. */
+ VALUE gc_disabled = rb_gc_disable_no_rest();
+
if (arg->keep_remains) {
if (st_lookup(arg->object_table, obj, &v)) {
info = (struct allocation_info *)v;
@@ -135,6 +140,8 @@ freeobj_i(VALUE tpval, void *data)
ruby_xfree(info);
}
}
+
+ if (gc_disabled == Qfalse) rb_gc_enable();
}
static int