Skip to content

Conversation

byroot
Copy link
Owner

@byroot byroot commented Aug 16, 2024

Opening here for now because I'm not able to reduce it. But with this Rails branch, I get Ruby to crash most of the time while running Active Record test suite.

It impact Ruby 3.3.4 and ruby-head.

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x8520b92f0000)
    frame #0: 0x00000001000dbfe0 ruby`gc_marks_finish [inlined] RVALUE_MARKED(objspace=<unavailable>, obj=146375592318752) at default.c:1233:12
   1230	RVALUE_MARKED(rb_objspace_t *objspace, VALUE obj)
   1231	{
   1232	    check_rvalue_consistency(objspace, obj);
-> 1233	    return RVALUE_MARKED_BITMAP(obj) != 0;
   1234	}
   1235	
   1236	static inline int
Target 0: (ruby) stopped.
(lldb) r
There is a running process, kill it and restart?: [Y/n] n
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x8520b92f0000)
  * frame #0: 0x00000001000dbfe0 ruby`gc_marks_finish [inlined] RVALUE_MARKED(objspace=<unavailable>, obj=146375592318752) at default.c:1233:12
    frame #1: 0x00000001000dbfdc ruby`gc_marks_finish at default.c:5599:14
    frame #2: 0x00000001000dbf80 ruby`gc_marks_finish(objspace=0x000000012a009200) at default.c:5643:5
    frame #3: 0x00000001000da470 ruby`gc_continue [inlined] gc_marks_step(objspace=0x000000012a009200, slots=<unavailable>) at default.c:5964:9
    frame #4: 0x00000001000da454 ruby`gc_continue [inlined] gc_marks_continue(objspace=0x000000012a009200, size_pool=0x000000012a0093e8, heap=0x000000012a009438) at default.c:5983:28
    frame #5: 0x00000001000da408 ruby`gc_continue(objspace=0x000000012a009200, size_pool=0x000000012a0093e8, heap=0x000000012a009438) at default.c:2255:13
    frame #6: 0x00000001000da100 ruby`newobj_cache_miss(objspace=0x000000012a009200, cache=0x00006000013601e0, size_pool_idx=2, vm_locked=<unavailable>) at default.c:2589:13
    frame #7: 0x00000001000ca938 ruby`rb_gc_impl_new_obj [inlined] newobj_alloc(objspace=0x000000012a009200, cache=<unavailable>, size_pool_idx=<unavailable>, vm_locked=false) at default.c:2622:15
    frame #8: 0x00000001000ca914 ruby`rb_gc_impl_new_obj(objspace_ptr=0x000000012a009200, cache_ptr=<unavailable>, klass=4302109680, flags=28, v1=0, v2=0, v3=0, wb_protected=<unavailable>, alloc_size=160) at default.c:2701:15
    frame #9: 0x00000001000d4410 ruby`rb_wb_protected_newobj_of [inlined] newobj_of(cr=0x0000000129e05370, klass=<unavailable>, flags=<unavailable>, v1=0, v2=0, v3=0, wb_protected=true, size=<unavailable>) at gc.c:890:17
    frame #10: 0x00000001000d43e0 ruby`rb_wb_protected_newobj_of(ec=<unavailable>, klass=<unavailable>, flags=<unavailable>, size=<unavailable>) at gc.c:917:12
    frame #11: 0x000000010002ecc8 ruby`rb_include_class_new [inlined] class_alloc(flags=60, klass=4302109680) at class.c:245:5
    frame #12: 0x000000010002ecb4 ruby`rb_include_class_new(module=4798410120, super=4800121680) at class.c:1153:19
    frame #13: 0x000000010002f360 ruby`do_include_modules_at(klass=4966256560, c=4966256560, module=4798410120, search_super=1, check_cyclic=<unavailable>) at class.c:1336:18
    frame #14: 0x000000010002ee1c ruby`rb_include_module [inlined] include_modules_at(klass=4966256560, c=<unavailable>, module=4798410120, search_super=1) at class.c:1380:12
    frame #15: 0x000000010002ee08 ruby`rb_include_module(klass=4966256560, module=4798410120) at class.c:1195:15
    frame #16: 0x00000001000bb1f8 ruby`rb_mod_extend_object [inlined] rb_extend_object(obj=4966256880, module=<unavailable>) at eval.c:1752:5
    frame #17: 0x00000001000bb1e8 ruby`rb_mod_extend_object(mod=<unavailable>, obj=4966256880) at eval.c:1785:5
    frame #18: 0x000000010026a6f0 ruby`vm_call0_body at vm_eval.c:164:15
    frame #19: 0x000000010026a650 ruby`vm_call0_body [inlined] vm_call0_cfunc(ec=0x0000000129e05600, calling=<unavailable>, argv=0x000000016fdfcf50) at vm_eval.c:178:12
    frame #20: 0x000000010026a650 ruby`vm_call0_body(ec=0x0000000129e05600, calling=<unavailable>, argv=0x000000016fdfcf50) at vm_eval.c:229:15
    frame #21: 0x0000000100254710 ruby`rb_funcallv_scope [inlined] vm_call0_cc(ec=0x0000000129e05600, recv=4798410120, id=5057, argc=1, argv=<unavailable>, cc=<unavailable>, kw_splat=0) at vm_eval.c:101:12
    frame #22: 0x00000001002546b0 ruby`rb_funcallv_scope(recv=4798410120, mid=5057, argc=<unavailable>, argv=<unavailable>, scope=CALL_FCALL) at vm_eval.c:1047:16
    frame #23: 0x0000000100254ad0 ruby`rb_funcall [inlined] rb_funcallv(recv=<unavailable>, mid=<unavailable>, argc=<unavailable>, argv=<unavailable>) at vm_eval.c:1062:12
    frame #24: 0x0000000100254ac8 ruby`rb_funcall(recv=<unavailable>, mid=<unavailable>, n=<unavailable>) at vm_eval.c:1119:12
    frame #25: 0x00000001000bc090 ruby`rb_obj_extend(argc=0, argv=0x0000000130028710, obj=4966256880) at eval.c:1831:9
    frame #26: 0x0000000100265060 ruby`vm_call_cfunc_with_frame_(ec=0x0000000129e05600, reg_cfp=0x0000000130127698, calling=<unavailable>, argc=1, argv=0x0000000130028710, stack_bottom=0x0000000130028708) at vm_insnhelper.c:3788:11
    frame #27: 0x00000001002492e0 ruby`vm_exec_core [inlined] vm_sendish(ec=0x0000000129e05600, reg_cfp=0x0000000130127698, cd=0x0000600000064e40, block_handler=0, method_explorer=mexp_search_method) at vm_insnhelper.c:5955:15
    frame #28: 0x0000000100249214 ruby`vm_exec_core(ec=<unavailable>) at insns.def:898:11
    frame #29: 0x0000000100245b10 ruby`rb_vm_exec(ec=0x0000000129e05600) at vm.c:2564:22
    frame #30: 0x0000000100254710 ruby`rb_funcallv_scope [inlined] vm_call0_cc(ec=0x0000000129e05600, recv=4798411240, id=5073, argc=1, argv=<unavailable>, cc=<unavailable>, kw_splat=0) at vm_eval.c:101:12
    frame #31: 0x00000001002546b0 ruby`rb_funcallv_scope(recv=4798411240, mid=5073, argc=<unavailable>, argv=<unavailable>, scope=CALL_FCALL) at vm_eval.c:1047:16
    frame #32: 0x0000000100254ad0 ruby`rb_funcall [inlined] rb_funcallv(recv=<unavailable>, mid=<unavailable>, argc=<unavailable>, argv=<unavailable>) at vm_eval.c:1062:12
    frame #33: 0x0000000100254ac8 ruby`rb_funcall(recv=<unavailable>, mid=<unavailable>, n=<unavailable>) at vm_eval.c:1119:12
    frame #34: 0x00000001000baf54 ruby`rb_mod_include(argc=0, argv=0x00000001300286c0, module=4966256880) at eval.c:1202:9
    frame #35: 0x0000000100265060 ruby`vm_call_cfunc_with_frame_(ec=0x0000000129e05600, reg_cfp=0x0000000130127708, calling=<unavailable>, argc=1, argv=0x00000001300286c0, stack_bottom=0x00000001300286b8) at vm_insnhelper.c:3788:11
    frame #36: 0x00000001002492e0 ruby`vm_exec_core [inlined] vm_sendish(ec=0x0000000129e05600, reg_cfp=0x0000000130127708, cd=0x00006000035df690, block_handler=0, method_explorer=mexp_search_method) at vm_insnhelper.c:5955:15
    frame #37: 0x0000000100249214 ruby`vm_exec_core(ec=<unavailable>) at insns.def:898:11
    frame #38: 0x0000000100245b10 ruby`rb_vm_exec(ec=0x0000000129e05600) at vm.c:2564:22
    frame #39: 0x000000010026cf84 ruby`invoke_block_from_c_bh [inlined] invoke_iseq_block_from_c(ec=0x0000000129e05600, captured=<unavailable>, self=4966256880, argc=<unavailable>, argv=<unavailable>, kw_splat=<unavailable>, passed_block_handler=<unavailable>, cref=0x0000000128ab56e8, is_lambda=0, me=0x0000000000000000) at vm.c:1595:12
    frame #40: 0x000000010026ce08 ruby`invoke_block_from_c_bh(ec=0x0000000129e05600, block_handler=<unavailable>, argc=<unavailable>, argv=<unavailable>, kw_splat=<unavailable>, passed_block_handler=<unavailable>, cref=<unavailable>, is_lambda=<unavailable>, force_blockarg=0) at vm.c:1609:20
    frame #41: 0x0000000100256e58 ruby`yield_under [inlined] vm_yield_with_cref(ec=0x0000000129e05600, argc=1, argv=0x000000016fdfd9e0, kw_splat=0, cref=<unavailable>, is_lambda=0) at vm.c:1646:12
    frame #42: 0x0000000100256e10 ruby`yield_under(self=4966256880, singleton=0, argc=1, argv=0x000000016fdfd9e0, kw_splat=0) at vm_eval.c:2097:12
    frame #43: 0x00000001001488f0 ruby`rb_class_initialize [inlined] rb_mod_initialize_exec(module=4966256880) at object.c:1992:9
    frame #44: 0x00000001001488d8 ruby`rb_class_initialize(argc=<unavailable>, argv=<unavailable>, klass=4966256880) at object.c:2060:5
    frame #45: 0x000000010026a6f0 ruby`vm_call0_body at vm_eval.c:164:15
    frame #46: 0x000000010026a650 ruby`vm_call0_body [inlined] vm_call0_cfunc(ec=0x0000000129e05600, calling=<unavailable>, argv=0x0000000130028668) at vm_eval.c:178:12
    frame #47: 0x000000010026a650 ruby`vm_call0_body(ec=0x0000000129e05600, calling=<unavailable>, argv=0x0000000130028668) at vm_eval.c:229:15
    frame #48: 0x000000010026b9c0 ruby`rb_call0 [inlined] vm_call0_cc(ec=0x0000000129e05600, recv=4966256880, id=3137, argc=1, argv=<unavailable>, cc=0x000000011b7a9038, kw_splat=0) at vm_eval.c:101:12
    frame #49: 0x000000010026b94c ruby`rb_call0(ec=0x0000000129e05600, recv=4966256880, mid=3137, argc=<unavailable>, argv=<unavailable>, call_scope=<unavailable>, self=<unavailable>) at vm_eval.c:554:12
    frame #50: 0x00000001001432e8 ruby`rb_class_new_instance_pass_kw(argc=<unavailable>, argv=<unavailable>, klass=<unavailable>) at object.c:2173:5
    frame #51: 0x0000000100265060 ruby`vm_call_cfunc_with_frame_(ec=0x0000000129e05600, reg_cfp=0x00000001301277b0, calling=<unavailable>, argc=1, argv=0x0000000130028668, stack_bottom=0x0000000130028660) at vm_insnhelper.c:3788:11
    frame #52: 0x0000000100248d70 ruby`vm_exec_core [inlined] vm_sendish(ec=0x0000000129e05600, reg_cfp=0x00000001301277b0, cd=0x0000600001c29420, block_handler=<unavailable>, method_explorer=mexp_search_method) at vm_insnhelper.c:5955:15
    frame #53: 0x0000000100248c78 ruby`vm_exec_core(ec=<unavailable>) at insns.def:851:11
    frame #54: 0x0000000100245b10 ruby`rb_vm_exec(ec=0x0000000129e05600) at vm.c:2564:22
    frame #55: 0x0000000100254710 ruby`rb_funcallv_scope [inlined] vm_call0_cc(ec=0x0000000129e05600, recv=4797102760, id=4097, argc=1, argv=<unavailable>, cc=<unavailable>, kw_splat=0) at vm_eval.c:101:12
    frame #56: 0x00000001002546b0 ruby`rb_funcallv_scope(recv=4797102760, mid=4097, argc=<unavailable>, argv=<unavailable>, scope=CALL_FCALL) at vm_eval.c:1047:16
    frame #57: 0x0000000100254ad0 ruby`rb_funcall [inlined] rb_funcallv(recv=<unavailable>, mid=<unavailable>, argc=<unavailable>, argv=<unavailable>) at vm_eval.c:1062:12
    frame #58: 0x0000000100254ac8 ruby`rb_funcall(recv=<unavailable>, mid=<unavailable>, n=<unavailable>) at vm_eval.c:1119:12
    frame #59: 0x000000010002e40c ruby`rb_class_inherited(super=<unavailable>, klass=4966262000) at class.c:978:12
    frame #60: 0x00000001001488d4 ruby`rb_class_initialize(argc=<unavailable>, argv=<unavailable>, klass=4966262000) at object.c:2059:5
    frame #61: 0x000000010026a6f0 ruby`vm_call0_body at vm_eval.c:164:15
    frame #62: 0x000000010026a650 ruby`vm_call0_body [inlined] vm_call0_cfunc(ec=0x0000000129e05600, calling=<unavailable>, argv=0x0000000130028408) at vm_eval.c:178:12
    frame #63: 0x000000010026a650 ruby`vm_call0_body(ec=0x0000000129e05600, calling=<unavailable>, argv=0x0000000130028408) at vm_eval.c:229:15
    frame #64: 0x000000010026b9c0 ruby`rb_call0 [inlined] vm_call0_cc(ec=0x0000000129e05600, recv=4966262000, id=3137, argc=1, argv=<unavailable>, cc=0x000000011b7a9038, kw_splat=0) at vm_eval.c:101:12
    frame #65: 0x000000010026b94c ruby`rb_call0(ec=0x0000000129e05600, recv=4966262000, mid=3137, argc=<unavailable>, argv=<unavailable>, call_scope=<unavailable>, self=<unavailable>) at vm_eval.c:554:12
    frame #66: 0x00000001001432e8 ruby`rb_class_new_instance_pass_kw(argc=<unavailable>, argv=<unavailable>, klass=<unavailable>) at object.c:2173:5
    frame #67: 0x0000000100265060 ruby`vm_call_cfunc_with_frame_(ec=0x0000000129e05600, reg_cfp=0x0000000130127af8, calling=<unavailable>, argc=1, argv=0x0000000130028408, stack_bottom=0x0000000130028400) at vm_insnhelper.c:3788:11
    frame #68: 0x00000001002492e0 ruby`vm_exec_core [inlined] vm_sendish(ec=0x0000000129e05600, reg_cfp=0x0000000130127af8, cd=0x0000600002210e20, block_handler=0, method_explorer=mexp_search_method) at vm_insnhelper.c:5955:15
    frame #69: 0x0000000100249214 ruby`vm_exec_core(ec=<unavailable>) at insns.def:898:11
    frame #70: 0x0000000100245cfc ruby`rb_vm_exec [inlined] vm_exec_loop(ec=0x0000000129e05600, state=<unavailable>, tag=0x000000016fdfe638, result=<unavailable>) at vm.c:2591:22
    frame #71: 0x0000000100245c44 ruby`rb_vm_exec(ec=0x0000000129e05600) at vm.c:2570:18
    frame #72: 0x000000010026cf84 ruby`invoke_block_from_c_bh [inlined] invoke_iseq_block_from_c(ec=0x0000000129e05600, captured=<unavailable>, self=4760314840, argc=<unavailable>, argv=<unavailable>, kw_splat=<unavailable>, passed_block_handler=<unavailable>, cref=0x0000000000000000, is_lambda=0, me=0x0000000000000000) at vm.c:1595:12
    frame #73: 0x000000010026ce08 ruby`invoke_block_from_c_bh(ec=0x0000000129e05600, block_handler=<unavailable>, argc=<unavailable>, argv=<unavailable>, kw_splat=<unavailable>, passed_block_handler=<unavailable>, cref=<unavailable>, is_lambda=<unavailable>, force_blockarg=0) at vm.c:1609:20
    frame #74: 0x0000000100255048 ruby`rb_yield(val=<unavailable>) at vm_eval.c:0
    frame #75: 0x000000010000b448 ruby`rb_ary_collect(ary=4969580440) at array.c:3694:30
    frame #76: 0x0000000100265060 ruby`vm_call_cfunc_with_frame_(ec=0x0000000129e05600, reg_cfp=0x0000000130127f20, calling=<unavailable>, argc=0, argv=0x00000001300280d0, stack_bottom=0x00000001300280c8) at vm_insnhelper.c:3788:11
    frame #77: 0x0000000100248d70 ruby`vm_exec_core [inlined] vm_sendish(ec=0x0000000129e05600, reg_cfp=0x0000000130127f20, cd=0x000060000133ce70, block_handler=<unavailable>, method_explorer=mexp_search_method) at vm_insnhelper.c:5955:15
    frame #78: 0x0000000100248c78 ruby`vm_exec_core(ec=<unavailable>) at insns.def:851:11
    frame #79: 0x0000000100245b10 ruby`rb_vm_exec(ec=0x0000000129e05600) at vm.c:2564:22
    frame #80: 0x0000000100259e48 ruby`vm_invoke_proc [inlined] invoke_iseq_block_from_c(ec=0x0000000129e05600, captured=<unavailable>, self=4760314840, argc=<unavailable>, argv=<unavailable>, kw_splat=<unavailable>, passed_block_handler=<unavailable>, cref=0x0000000000000000, is_lambda=0, me=0x0000000000000000) at vm.c:1595:12
    frame #81: 0x0000000100259cd0 ruby`vm_invoke_proc [inlined] invoke_block_from_c_proc(ec=<unavailable>, proc=<unavailable>, self=<unavailable>, argc=<unavailable>, argv=<unavailable>, kw_splat=<unavailable>, passed_block_handler=<unavailable>, is_lambda=0, me=0x0000000000000000) at vm.c:1689:16
    frame #82: 0x0000000100259bd4 ruby`vm_invoke_proc(ec=0x0000000129e05600, proc=<unavailable>, self=4760314840, argc=<unavailable>, argv=<unavailable>, kw_splat=<unavailable>, passed_block_handler=<unavailable>) at vm.c:1719:12
    frame #83: 0x0000000100172efc ruby`rb_proc_call [inlined] rb_proc_call_kw(self=<unavailable>, args=<unavailable>, kw_splat=0) at proc.c:962:12
    frame #84: 0x0000000100172eb8 ruby`rb_proc_call(self=<unavailable>, args=<unavailable>) at proc.c:972:12
    frame #85: 0x00000001000bc6ac ruby`rb_ec_exec_end_proc [inlined] exec_end_procs_chain(procs=<unavailable>, errp=0x0000000129e05670) at eval_jump.c:105:9
    frame #86: 0x00000001000bc670 ruby`rb_ec_exec_end_proc(ec=0x0000000129e05600) at eval_jump.c:121:13
    frame #87: 0x00000001000b8f44 ruby`rb_ec_teardown(ec=0x0000000129e05600) at eval.c:155:5
    frame #88: 0x00000001000b90ac ruby`rb_ec_cleanup(ec=0x0000000129e05600, ex=RUBY_TAG_NONE) at eval.c:207:9
    frame #89: 0x00000001000023b0 ruby`main [inlined] rb_main(argc=3, argv=0x000000016fdff418) at main.c:43:12
    frame #90: 0x0000000100002394 ruby`main(argc=3, argv=0x000000016fdff418) at main.c:62:12
    frame #91: 0x0000000193cca0e0 dyld`start + 2360
frame #1: 0x00000001000dbfdc ruby`gc_marks_finish at default.c:5599:14
   5596	
   5597	        if (RB_SPECIAL_CONST_P(obj)) continue;
   5598	
-> 5599	        if (!RVALUE_MARKED(objspace, obj)) {
   5600	            **ptr_ptr = Qundef;
   5601	        }
   5602	        else {

The pointer seem to be garbage, so I wonder if perhaps it's because the hash was GCed prior to the key or something?

(lldb) p *(RBasic *)146375592318752
error: Couldn't apply expression side effects : Couldn't dematerialize a result variable: couldn't read its memory

cc @peterzhu2118

I'll try to see if I can reduce it, but if you wish to have a look yourself, right now the repro is:

cd activerecord
bundle
bin/test test/cases/attribute_methods_test.rb

It crashes almost every time, if you run this a handful of time you should see the crash.

dhh and others added 30 commits July 28, 2024 15:44
Fix: rails#52429

The previous implementation assumed `NoMethodError` would be raised
when calling `super`, but that's not always true.

If the receiver is an implicit self, the raised error will be
`NameError`.

It's better not to rely on exceptions for this anyways.
Fix `delegate_missing_to allow_nil: true` when called with implict self
Adapters have very inconsistent internal APIs to perform queries.

This refactoring tries to improve consistency with a common provite
API for all of them.

Abstract methods:

- `raw_execute`: the only method where an adapter should perform
  a query. It returns a native, adapter specific result object.
  Does not apply query transformations. Does not check for writes.

- `cast_result`: receives the native result object and returns
  a generic `ActiveRecord::Result`.

- `affected_rows`: receives the native result object and returns
  the number of affected rows.

By just implementing these 3 methods all adapters automatically get:

- `raw_exec_query`: same as `raw_execute` but returns an `ActiveRecord::Result`.

- `internal_exec_query`: same as `raw_exec_query` but check for writes and
  apply query transformations.

- `internal_execute`: same as `internal_exec_query` but retuns the native,
  adapter specific, result object.

With this increased conisistency, we can now reduce the ammount of
duplicated code in every adapter. There's some room for futher
improvments but I tried to not go too far all at once.

Also previously some adapters had a block based query interface that
allowed to eagerly clear the native result object.

It may make sense to bring that capability back in a consistent
way, but short term I opted for consistency.
The postgres adapter used to be more complex than the others to
be able to pass the prepared statement key to the `log` method.

If we instead add it to the payload later, we can simplify the method
further and it opens the door to refactor `log` and `with_raw_connection`
out of `raw_execute`.
A `raw_execute` implementation is now provided, instead adapters
have to implement `perform_query`.

It's a much simpler method that no longer need to concern itself
with Active Support notifications nor calling `with_raw_connection`.
Inline simple operations like reseting the timezone.
Normalizes email_address before saving it to the DB.
and the sessions view template has been moved into an erb generator so
that gems like tailwindcss-rails can provide a specialized template.
Not worth the complication. Let them login again. It doesn't matter.
It's slower than it needs to because it contains a workaround for
a bug affecting early Ruby 3.2 releases.

It also matches against a regexp which isn't necessary given
that starting in Ruby 3.2, `Time.new(str)` is strict enough
for this purpose.

```
ruby 3.3.3 (2024-06-12 revision f1c7b6f435) +YJIT [arm64-darwin23]
Warming up --------------------------------------
              bugged   265.827k i/100ms
                good   394.774k i/100ms
Calculating -------------------------------------
              bugged      2.759M (± 5.8%) i/s -     13.823M in   5.031296s
                good      4.128M (± 7.8%) i/s -     20.528M in   5.010538s

Comparison:
              bugged:  2758945.6 i/s
                good:  4128323.9 i/s - 1.50x  faster
```

```ruby
require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  gem "benchmark-ips"
end

require 'benchmark/ips'

ISO_DATETIME = /
  \A
  (\d{4})-(\d\d)-(\d\d)(?:T|\s)            # 2020-06-20T
  (\d\d):(\d\d):(\d\d)(?:\.(\d{1,6})\d*)?  # 10:20:30.123456
  (?:(Z(?=\z)|[+-]\d\d)(?::?(\d\d))?)?     # +09:00
  \z
/x

def old(string)
  return unless ISO_DATETIME.match?(string)

  ::Time.at(::Time.new(string, in: "UTC"))
end

def fast(string)
  return unless string.include?("-") #  Time.new("1234") # => 1234-01-01 00:00:00

  ::Time.new(string, in: "UTC")
end

str = "2024-01-01T12:43:13"
Benchmark.ips do |x|
  x.report("bugged") { old(str) }
  x.report("good") { fast(str) }
  x.compare!(order: :baseline)
end
```
* Add bin/dev by default

Then we have a uniform way of starting dev mode whether someone is using
jsbundling or importmaps.

* Also generated here
The docs usage should align with the method. 

Here are the examples:
```
[29] pry(main)> ActiveSupport::JSON::Encoding.use_standard_json_time_format = true
=> true
[30] pry(main)> Time.utc(2005,2,1,15,15,10).in_time_zone("Hawaii").to_json
=> "\"2005-02-01T05:15:10.000-10:00\""
[31] pry(main)> Time.utc(2005,2,1,15,15,10).in_time_zone("Hawaii").as_json
=> "2005-02-01T05:15:10.000-10:00"
[32] pry(main)> ActiveSupport::JSON::Encoding.use_standard_json_time_format = false
=> false
[33] pry(main)> Time.utc(2005,2,1,15,15,10).in_time_zone("Hawaii").as_json
=> "2005/02/01 05:15:10 -1000"
[34] pry(main)> Time.utc(2005,2,1,15,15,10).in_time_zone("Hawaii").to_json
=> "\"2005/02/01 05:15:10 -1000\""
```
The payload construction was moved here in a previous commit, but log
wasn't removed or deprecated.

We've been using this as a hook we can override to add some adapter
specific-keys. If we want to remove or bypass this at a later date we
should probably introduce something that can be overridden like we did
for cache_notification_info.

Co-authored-by: Daniel Colson <danieljamescolson@gmail.com>
When config.i18n.raise_on_missing_translations = true, controllers and
views raise an error on missing translations. However, models won't.
This commit changes models to raise an error when
raise_on_missing_translations is true

Co-authored-by: Alex Ghiculescu <alex@tanda.co>
Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
[ci skip] docs: use `as_json` per method instead of `to_json`
…tions

Change ActiveModel human_attribute_name to raise an error
We special case singleton methods being added to ActiveRecord::Base
subclasses whose names match methods on Kernel so that we can eagerly
define them on the ClassSpecificRelation as otherwise we'd never hit
method_missing.

Previously, this would also eagerly define methods which were on the
Kernel Module's singleton class rather than being defined as instance
methods inside the module.

Most notably this hit "name" which is defined on the anonymous HABTM
classes.
If name is called on Relation it should be delegated to the model and
doesn't require scoping.
…-structure-parsing

Fix SQLite table definition parsing bug to handle commas in default function definitions
…message

Mention which blob can't be transformed/previewed and what content_type
it has.

Co-authored-by: zzak <zzakscott@gmail.com>
Improve ActiveStorage::InvariableError message
…ails#52447)

* lib/assets is too rare of a use case to warrant a default directory

Either these assets are part of your app, and should be in app/assets,
or you're getting them from a vendor, and they should be in
vendor/assets.

* Fix test
Edits to the scripts entry in CHANGELOG
rafaelfranca and others added 23 commits August 14, 2024 15:26
Avoid calling Headers#env_name when static header
Split AR::Migration.load_schema_if_pending! into two methods
Minitest 5.25+ has a new API for `with_info_handler` that accepts an
additional argument.

The code now support all versions of minitest 5.

See minitest/minitest@8cd3b1c
…-extension

Update PostgreSQLAdapter#extensions to include schema name
Converts hashes to keywords in ActionDispatch::Resources::Resource and
in ActionDispatch::Scope to match syntax of other mapping methods and
allocate less.
Removes racc dependency, and writes our own parser for routing instead.
Fix: rails#52601

Now that Active Record connections are fully lazy, just calling
`.lease_connection` isn't actually enough to estalish a connection.

We might as well suggest to use a method with the actual intent.
…ssage

Fix ActiveRecord::Base.inspect to correctly indicate how to load schema
Fix: rails#52615
Ref: rails#50796

The code assumed the application follow the standard `Name::Application`
naming, but it's possible to rename it however you like.
rails console: Handle non standard application names
Use keywords with scopes and resources
…ions

Allow to eager load nested nil associations
…nore

Fix swallowing ignore order warning when batching using `BatchEnumerator`
Fix: rails#52617
Closes: rails#52618

It isn't per say a leak because the connection reaper eventually prune these, and also it's not expected
that new Threads are constantly making entries into that cache.
But it's true that with Fiber it's probably a bit more common, and the default reaper frequency
isn't adapted to clear this fast enough.

So we should instead eagerly prune it, or use a WeakMap.

On 3.3+ we can use ObjectSpace::WeakKeyMap, but on older Ruby versions
we have to resort to eager clearing.
@byroot
Copy link
Owner Author

byroot commented Aug 16, 2024

One possibly related things, the keys in that weak map are either Thread or Fiber and I see the GC treat them distinctly:

bool
rb_gc_shutdown_call_finalizer_p(VALUE obj)
{
    switch (BUILTIN_TYPE(obj)) {
      case T_DATA:
        if (!ruby_free_at_exit_p() && (!DATA_PTR(obj) || !RDATA(obj)->dfree)) return false;
        if (rb_obj_is_thread(obj)) return false;
        if (rb_obj_is_mutex(obj)) return false;
        if (rb_obj_is_fiber(obj)) return false;
        if (rb_obj_is_main_ractor(obj)) return false;

So perhaps that why, but I still haven't managed to reduce it.

byroot added a commit that referenced this pull request Aug 16, 2024
Being investigated at #3

It seems that it's caused by using Thread or Fiber as keys.
@byroot
Copy link
Owner Author

byroot commented Aug 22, 2024

Investigated with @peterzhu2118, and filed at https://bugs.ruby-lang.org/issues/20691 with a patch.

@byroot byroot closed this Aug 22, 2024
@byroot byroot deleted the weak-key-map-crash branch August 22, 2024 16:08
DanielaVelasquez pushed a commit to DanielaVelasquez/rails that referenced this pull request Oct 3, 2024
Being investigated at byroot#3

It seems that it's caused by using Thread or Fiber as keys.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.