summaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
Diffstat (limited to 'misc')
-rw-r--r--misc/.vscode/settings.json8
-rwxr-xr-xmisc/expand_tabs.rb34
-rw-r--r--[-rwxr-xr-x]misc/lldb_cruby.py24
-rw-r--r--misc/lldb_rb/commands/heap_page_command.py5
-rw-r--r--misc/lldb_rb/commands/print_flags_command.py6
-rw-r--r--misc/lldb_rb/lldb_interface.py11
-rw-r--r--misc/lldb_rb/rb_heap_structs.py19
-rw-r--r--misc/lldb_rb/utils.py36
-rw-r--r--misc/ruby-style.el15
-rw-r--r--misc/tsan_suppressions.txt109
10 files changed, 191 insertions, 76 deletions
diff --git a/misc/.vscode/settings.json b/misc/.vscode/settings.json
index 7b1a38c536..a2e4e1ec69 100644
--- a/misc/.vscode/settings.json
+++ b/misc/.vscode/settings.json
@@ -2,7 +2,9 @@
"rust-analyzer.cargo.features": [
"disasm",
],
- "rust-analyzer.cargo.unsetTest": [
- "yjit",
- ],
+ "rust-analyzer.cfg.setTest": false,
+ // rust-analyzer bundled in the VSCode extension may only support Rust newer than 1.85.0.
+ // To avoid warnings, install rust-analyzer with `rustup component add rust-analyzer` and
+ // use `~/.cargo/bin/rust-analyzer` with the following config.
+ "rust-analyzer.server.path": "rust-analyzer",
}
diff --git a/misc/expand_tabs.rb b/misc/expand_tabs.rb
index a94eea5046..d26568eefc 100755
--- a/misc/expand_tabs.rb
+++ b/misc/expand_tabs.rb
@@ -59,53 +59,31 @@ class Git
end
DEFAULT_GEM_LIBS = %w[
- abbrev
- base64
- benchmark
bundler
- cmath
- csv
- debug
delegate
did_you_mean
- drb
english
erb
+ error_highlight
fileutils
find
forwardable
- getoptlong
ipaddr
- irb
- logger
- mutex_m
net-http
net-protocol
- observer
open3
open-uri
optparse
ostruct
pp
prettyprint
- prime
- pstore
- rdoc
- readline
- reline
+ prism
resolv
- resolv-replace
- rexml
- rinda
- rss
rubygems
- scanf
securerandom
- set
shellwords
singleton
tempfile
- thwait
time
timeout
tmpdir
@@ -117,27 +95,19 @@ DEFAULT_GEM_LIBS = %w[
]
DEFAULT_GEM_EXTS = %w[
- bigdecimal
- cgi
date
digest
etc
fcntl
- fiddle
io-console
io-nonblock
io-wait
json
- nkf
openssl
pathname
psych
- racc
- readline-ext
stringio
strscan
- syslog
- win32ole
zlib
]
diff --git a/misc/lldb_cruby.py b/misc/lldb_cruby.py
index 400ccb45b9..b3d4fb509a 100755..100644
--- a/misc/lldb_cruby.py
+++ b/misc/lldb_cruby.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
#coding: utf-8
#
# Usage: run `command script import -r misc/lldb_cruby.py` on LLDB
@@ -14,6 +13,7 @@ import sys
import shlex
import platform
import glob
+import math
from lldb_rb.constants import *
@@ -67,7 +67,7 @@ class BackTrace:
return self.VM_FRAME_MAGIC_NAME.get(frame_type, "(none)")
def rb_iseq_path_str(self, iseq):
- tRBasic = self.target.FindFirstType("struct RBasic").GetPointerType()
+ tRBasic = self.target.FindFirstType("::RBasic").GetPointerType()
pathobj = iseq.GetValueForExpressionPath("->body->location.pathobj")
pathobj = pathobj.Cast(tRBasic)
@@ -269,8 +269,7 @@ def lldb_inspect(debugger, target, result, val):
elif num & RUBY_IMMEDIATE_MASK:
print('immediate(%x)' % num, file=result)
else:
- tRBasic = target.FindFirstType("struct RBasic").GetPointerType()
- tRValue = target.FindFirstType("struct RVALUE")
+ tRBasic = target.FindFirstType("::RBasic").GetPointerType()
val = val.Cast(tRBasic)
flags = val.GetValueForExpressionPath("->flags").GetValueAsUnsigned()
@@ -524,10 +523,11 @@ def rb_backtrace(debugger, command, result, internal_dict):
bt.print_bt(val)
def dump_bits(target, result, page, object_address, end = "\n"):
- tRValue = target.FindFirstType("struct RVALUE")
+ slot_size = page.GetChildMemberWithName("heap").GetChildMemberWithName("slot_size").unsigned
+ byte_size = 40 ** math.floor(math.log(slot_size, 40))
tUintPtr = target.FindFirstType("uintptr_t") # bits_t
- num_in_page = (object_address & HEAP_PAGE_ALIGN_MASK) // tRValue.GetByteSize();
+ num_in_page = (object_address & HEAP_PAGE_ALIGN_MASK) // byte_size;
bits_bitlength = tUintPtr.GetByteSize() * 8
bitmap_index = num_in_page // bits_bitlength
bitmap_offset = num_in_page & (bits_bitlength - 1)
@@ -547,10 +547,9 @@ class HeapPageIter:
self.target = target
self.start = page.GetChildMemberWithName('start').GetValueAsUnsigned();
self.num_slots = page.GetChildMemberWithName('total_slots').unsigned
- self.slot_size = page.GetChildMemberWithName('size_pool').GetChildMemberWithName('slot_size').unsigned
+ self.slot_size = page.GetChildMemberWithName('heap').GetChildMemberWithName('slot_size').unsigned
self.counter = 0
- self.tRBasic = target.FindFirstType("struct RBasic")
- self.tRValue = target.FindFirstType("struct RVALUE")
+ self.tRBasic = target.FindFirstType("::RBasic")
def is_valid(self):
heap_page_header_size = self.target.FindFirstType("struct heap_page_header").GetByteSize()
@@ -582,14 +581,13 @@ def dump_page_internal(page, target, process, thread, frame, result, debugger, h
freelist = []
fl_start = page.GetChildMemberWithName('freelist').GetValueAsUnsigned()
- tRVALUE = target.FindFirstType("struct RVALUE")
+ free_slot = target.FindFirstType("struct free_slot")
while fl_start > 0:
freelist.append(fl_start)
obj_addr = lldb.SBAddress(fl_start, target)
- obj = target.CreateValueFromAddress("object", obj_addr, tRVALUE)
- fl_start = obj.GetChildMemberWithName("as").GetChildMemberWithName("free").GetChildMemberWithName("next").GetValueAsUnsigned()
-
+ obj = target.CreateValueFromAddress("object", obj_addr, free_slot)
+ fl_start = obj.GetChildMemberWithName("next").GetValueAsUnsigned()
page_iter = HeapPageIter(page, target)
if page_iter.is_valid():
diff --git a/misc/lldb_rb/commands/heap_page_command.py b/misc/lldb_rb/commands/heap_page_command.py
index b56a3eae4e..2eed3c3bee 100644
--- a/misc/lldb_rb/commands/heap_page_command.py
+++ b/misc/lldb_rb/commands/heap_page_command.py
@@ -8,14 +8,15 @@ class HeapPageCommand(RbBaseCommand):
help_string = "prints out 'struct heap_page' for a VALUE pointer in the page"
def call(self, debugger, command, exe_ctx, result):
+ self.result = result
self.t_heap_page_body = self.target.FindFirstType("struct heap_page_body")
self.t_heap_page_ptr = self.target.FindFirstType("struct heap_page").GetPointerType()
page = self._get_page(self.frame.EvaluateExpression(command))
page.Cast(self.t_heap_page_ptr)
- self._append_expression(debugger, "(struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
- self._append_expression(debugger, "*(struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
+ self._append_expression("(struct heap_page *) %0#x" % page.GetValueAsUnsigned())
+ self._append_expression("*(struct heap_page *) %0#x" % page.GetValueAsUnsigned())
def _get_page(self, val):
addr = val.GetValueAsUnsigned()
diff --git a/misc/lldb_rb/commands/print_flags_command.py b/misc/lldb_rb/commands/print_flags_command.py
index 00da4834bf..bc494ae01a 100644
--- a/misc/lldb_rb/commands/print_flags_command.py
+++ b/misc/lldb_rb/commands/print_flags_command.py
@@ -11,13 +11,13 @@ class PrintFlagsCommand(RbBaseCommand):
# call is where our command logic will be implemented
def call(self, debugger, command, exe_ctx, result):
- rclass_t = self.target.FindFirstType("struct RBasic")
+ rclass_t = self.target.FindFirstType("::RBasic")
rcass_ptr = self.target.EvaluateExpression(command).Cast(rclass_t.GetPointerType())
obj_flags = rcass_ptr.GetValueForExpressionPath("->flags").GetValueAsUnsigned()
flags = [
- "RUBY_FL_WB_PROTECTED", "RUBY_FL_PROMOTED0", "RUBY_FL_PROMOTED1", "RUBY_FL_FINALIZE",
- "RUBY_FL_SHAREABLE", "RUBY_FL_EXIVAR", "RUBY_FL_FREEZE",
+ "RUBY_FL_WB_PROTECTED", "RUBY_FL_PROMOTED", "RUBY_FL_FINALIZE",
+ "RUBY_FL_SHAREABLE", "RUBY_FL_FREEZE",
"RUBY_FL_USER0", "RUBY_FL_USER1", "RUBY_FL_USER2", "RUBY_FL_USER3", "RUBY_FL_USER4",
"RUBY_FL_USER5", "RUBY_FL_USER6", "RUBY_FL_USER7", "RUBY_FL_USER8", "RUBY_FL_USER9",
"RUBY_FL_USER10", "RUBY_FL_USER11", "RUBY_FL_USER12", "RUBY_FL_USER13", "RUBY_FL_USER14",
diff --git a/misc/lldb_rb/lldb_interface.py b/misc/lldb_rb/lldb_interface.py
index 785a54b3e3..25930b2e16 100644
--- a/misc/lldb_rb/lldb_interface.py
+++ b/misc/lldb_rb/lldb_interface.py
@@ -5,3 +5,14 @@ class LLDBInterface:
self.process = self.target.GetProcess()
self.thread = self.process.GetSelectedThread()
self.frame = self.thread.GetSelectedFrame()
+
+ def _append_command_output(self, command):
+ output1 = self.result.GetOutput()
+ self.debugger.GetCommandInterpreter().HandleCommand(command, self.result)
+ output2 = self.result.GetOutput()
+ self.result.Clear()
+ self.result.write(output1)
+ self.result.write(output2)
+
+ def _append_expression(self, expression):
+ self._append_command_output("expression " + expression)
diff --git a/misc/lldb_rb/rb_heap_structs.py b/misc/lldb_rb/rb_heap_structs.py
index 86b38dbbbd..798b838080 100644
--- a/misc/lldb_rb/rb_heap_structs.py
+++ b/misc/lldb_rb/rb_heap_structs.py
@@ -1,4 +1,5 @@
import lldb
+import math
from lldb_rb.lldb_interface import LLDBInterface
from lldb_rb.constants import *
@@ -50,8 +51,7 @@ class RbObject(LLDBInterface):
self.flUser9 = self.ruby_globals["RUBY_FL_USER9"]
self.flUshift = self.ruby_globals["RUBY_FL_USHIFT"]
- self.tRBasic = self.target.FindFirstType("struct RBasic").GetPointerType()
- self.tRValue = self.target.FindFirstType("struct RVALUE")
+ self.tRBasic = self.target.FindFirstType("::RBasic").GetPointerType()
self.val = ptr.Cast(self.tRBasic)
self.page = HeapPage(self.debugger, self.val)
@@ -70,10 +70,12 @@ class RbObject(LLDBInterface):
return ' '
def dump_bits(self, result, end = "\n"):
- tRValue = self.target.FindFirstType("struct RVALUE")
tUintPtr = self.target.FindFirstType("uintptr_t") # bits_t
- num_in_page = (self.val.GetValueAsUnsigned() & HEAP_PAGE_ALIGN_MASK) // tRValue.GetByteSize();
+ slot_size = self.page.to_heap_page_struct().GetChildMemberWithName("heap").GetChildMemberWithName("slot_size").unsigned
+ byte_size = 40 ** math.floor(math.log(slot_size, 40))
+
+ num_in_page = (self.val.GetValueAsUnsigned() & HEAP_PAGE_ALIGN_MASK) // byte_size;
bits_bitlength = tUintPtr.GetByteSize() * 8
bitmap_index = num_in_page // bits_bitlength
bitmap_offset = num_in_page & (bits_bitlength - 1)
@@ -109,7 +111,14 @@ class RbObject(LLDBInterface):
return False
def as_type(self, type_name):
- return self.val.Cast(self.tRValue.GetPointerType()).GetValueForExpressionPath("->as."+type_name)
+ if type_name == "array":
+ tRarray = self.target.FindFirstType("struct RArray")
+ return self.val.Cast(tRarray.GetPointerType())
+ elif type_name == "bignum":
+ tRbignum = self.target.FindFirstType("struct RBignum")
+ return self.val.Cast(tRbignum.GetPointerType())
+ else:
+ print("as_type is not implemented for:", type_name)
def ary_ptr(self):
rval = self.as_type("array")
diff --git a/misc/lldb_rb/utils.py b/misc/lldb_rb/utils.py
index a6bbd385cd..1415dd3f33 100644
--- a/misc/lldb_rb/utils.py
+++ b/misc/lldb_rb/utils.py
@@ -8,17 +8,6 @@ class RbInspector(LLDBInterface):
self.result = result
self.ruby_globals = ruby_globals
- def _append_command_output(self, command):
- output1 = self.result.GetOutput()
- self.debugger.GetCommandInterpreter().HandleCommand(command, self.result)
- output2 = self.result.GetOutput()
- self.result.Clear()
- self.result.write(output1)
- self.result.write(output2)
-
- def _append_expression(self, expression):
- self._append_command_output("expression " + expression)
-
def string2cstr(self, rstring):
"""Returns the pointer to the C-string in the given String object"""
if rstring.TypeIsPointerType():
@@ -247,13 +236,26 @@ class RbInspector(LLDBInterface):
elif rval.is_type("RUBY_T_DATA"):
tRTypedData = self.target.FindFirstType("struct RTypedData").GetPointerType()
val = val.Cast(tRTypedData)
- flag = val.GetValueForExpressionPath("->typed_flag")
-
- if flag.GetValueAsUnsigned() == 1:
- print("T_DATA: %s" %
- val.GetValueForExpressionPath("->type->wrap_struct_name"),
+ is_typed_data = self.ruby_globals.get("RUBY_TYPED_FL_IS_TYPED_DATA", None)
+ if is_typed_data:
+ typed = rval.flags & is_typed_data
+ else:
+ typed = val.GetValueForExpressionPath("->typed_flag").GetValueAsUnsigned() == 1
+
+ if typed:
+ type = val.GetValueForExpressionPath("->type").GetValueAsUnsigned()
+ embed = (type & 1)
+ if embed:
+ flaginfo += "[EMBED] "
+ type = self.frame.EvaluateExpression("(rb_data_type_t *)%0#x" % (type & ~1))
+ print("T_DATA: %s%s" %
+ (flaginfo, type.GetValueForExpressionPath("->wrap_struct_name")),
file=self.result)
- self._append_expression("*(struct RTypedData *) %0#x" % val.GetValueAsUnsigned())
+ print("%s", type.Dereference(), file=self.result)
+ ptr = val.GetValueForExpressionPath("->data")
+ if embed:
+ ptr = ptr.AddressOf()
+ self._append_expression("(void *)%0#x" % ptr.GetValueAsUnsigned())
else:
print("T_DATA:", file=self.result)
self._append_expression("*(struct RData *) %0#x" % val.GetValueAsUnsigned())
diff --git a/misc/ruby-style.el b/misc/ruby-style.el
index 13aad77b3d..03d0830d3a 100644
--- a/misc/ruby-style.el
+++ b/misc/ruby-style.el
@@ -56,7 +56,9 @@
(c-basic-offset . 4)
(tab-width . 8)
(indent-tabs-mode . nil)
- (setq show-trailing-whitespace t)
+ (show-trailing-whitespace . t)
+ (c-backslash-column . 1)
+ (c-backslash-max-column . 1)
(c-offsets-alist
(case-label . *)
(label . (ruby-style-label-indent *))
@@ -66,6 +68,17 @@
(access-label /)
)))
+(c-add-style
+ "prism"
+ '("bsd"
+ (c-basic-offset . 4)
+ (tab-width . 8)
+ (indent-tabs-mode . nil)
+ (show-trailing-whitespace . t)
+ (c-offsets-alist
+ (case-label . +)
+ )))
+
;;;###autoload
(defun ruby-style-c-mode ()
(interactive)
diff --git a/misc/tsan_suppressions.txt b/misc/tsan_suppressions.txt
new file mode 100644
index 0000000000..5492500e7f
--- /dev/null
+++ b/misc/tsan_suppressions.txt
@@ -0,0 +1,109 @@
+# TSan: ThreadSanitizer
+# https://github.com/google/sanitizers/wiki/threadsanitizersuppressions
+#
+# This file describes a number of places where TSAN detects problems in CRuby.
+# Many of these indicate bugs. Others are benign (ex. data races that can be
+# replaced with relaxed atomic loads)
+#
+# Usage:
+# Configure with:
+# ./configure cflags='-fsanitize=thread' CC=clang
+# Build and run with:
+# TSAN_OPTIONS="suppressions=$(pwd)/misc/tsan_suppressions.txt:die_after_fork=0"
+#
+# Other useful TSAN_OPTIONS:
+# * halt_on_error=1
+# * strip_path_prefix=$(pwd)/
+
+# Namespaces
+race_top:push_subclass_entry_to_list
+
+# sub_nounderflow includes non-atomic read, possibly other issue
+race:objspace_malloc_increase_body
+
+# Signals and ubf
+race:unregister_ubf_list
+
+# It's already crashing. We're doing our best
+signal:rb_vm_bugreport
+race:check_reserved_signal_
+
+race_top:rb_check_deadlock
+
+# vm->ractor.sched.grq_cnt++
+race_top:ractor_sched_enq
+race_top:ractor_sched_deq
+
+# Race between vm_remove_ractor writing ractor count and
+# native_thread_check_and_create_shared reading it during thread creation.
+# The write happens when a ractor thread exits, the read happens when
+# checking if new shared threads need to be created.
+race:vm_remove_ractor
+
+# th->sched.finished at end of co_start
+race_top:rb_thread_sched_mark_zombies
+
+# Races against timer thread setting th->sched.waiting_reason.flags
+race_top:thread_sched_wait_events
+
+# At thread start
+race_top:rb_ractor_set_current_ec_
+
+# TSan reports a lock-order-inversion between thread_sched_lock_ and this lock.
+# It's unclear if that can cause a deadlock since the lock is on self
+deadlock:ractor_lock_self
+
+# TSan reports a deadlock when reacquiring the this lock after a barrier, but
+# we know the other threads have been stopped
+deadlock:rb_ractor_sched_barrier_start
+
+# RVALUE_AGE_SET manipulates flag bits on objects which may be accessed in Ractors
+race_top:RVALUE_AGE_SET
+
+# Inline caches and call cache updates
+# Multiple threads can race when updating shared call caches during method lookups
+# and argument forwarding. These races involve reading/writing cd->cc fields.
+race_top:vm_cc_call_set
+race_top:vm_cc_class_check
+race_top:vm_search_cc
+race_top:vm_search_method_slowpath0
+race_top:rb_vm_opt_getconstant_path
+race_top:vm_ic_attr_index_set
+race:vm_ic_update
+race:vm_caller_setup_fwd_args
+
+# Race in shape_get_next where multiple threads simultaneously access and modify
+# RCLASS_MAX_IV_COUNT and RCLASS_VARIATION_COUNT fields in class objects.
+# One thread reads the field while another thread calls RCLASS_SET_MAX_IV_COUNT.
+# This happens during instance variable shape transitions in multi-threaded code.
+race:shape_get_next
+
+# Non-atomic reads/writes
+race:gccct_method_search
+
+# Ignore exit for now
+race:rb_ec_finalize
+race:rb_ec_cleanup
+
+# TSan doesn't work well post-fork, this raises errors when creating the new
+# timer thread
+race:after_fork_ruby
+
+# Sets objspace->flags.dont_incremental while writebarrier may be running
+race_top:objspace_each_exec
+race_top:objspace_each_objects_ensure
+
+# Non-atomic lazy initialized static variable
+race_top:rbimpl_intern_const
+
+# Setting def->aliased bitfield non-atomically
+race_top:method_definition_addref
+
+# Switching to setting up tracing. Likely other ractors should be stopped for this.
+race_top:encoded_iseq_trace_instrument
+race:rb_iseq_trace_set_all
+race:rb_tracepoint_enable
+
+# GC enable/disable flag modifications race with object allocation flag reads
+race_top:rb_gc_impl_gc_disable
+race_top:rb_gc_impl_gc_enable