NOTE: I didn't attach a patch or proof of concept fix because I don't know how you want to handle this edge case. The easiest thing would just be to return the original string in rb_str_init and not honor the capacity change here.
I no longer get the segfault if in rb_str_init, return str is added right after existing check of (orig == str), but then capacity of string won't change.
EDIT: I think I figured out what was going on. If str is a shared string, it must be made independent before realloc in rb_str_init.