Project

General

Profile

« Previous | Next » 

Revision 689a6a0a

Added by usa (Usaku NAKAMURA) over 4 years ago

merge revision(s) 3f9562015e651735bfc2fdd14e8f6963b673e22a,c06ddfee878524168e4af07443217ed2f8d0954b,3b3b4a44e5: [Backport #15792]

    Get rid of indirect sharing

    * string.c (str_duplicate): share the root shared string if the
      original string is already sharing, so that all shared strings
      refer the root shared string directly.  indirect sharing can
      cause a dangling pointer.

    [Bug #15792]

    str_duplicate: Don't share with a frozen shared string

    This is a follow up for 3f9562015e651735bfc2fdd14e8f6963b673e22a.
    Before this commit, it was possible to create a shared string which
    shares with another shared string by passing a frozen shared string
    to `str_duplicate`.

    Such string looks like:

    ```
     --------                    -----------------
     | root | ------ owns -----> | root's buffer |
     --------                    -----------------
         ^                             ^   ^
     -----------                       |   |
     | shared1 | ------ references -----   |
     -----------                           |
         ^                                 |
     -----------                           |
     | shared2 | ------ references ---------
     -----------
    ```

    This is bad news because `rb_fstring(shared2)` can make `shared1`
    independent, which severs the reference from `shared1` to `root`:

    ```c
    /* from fstr_update_callback() */
    str = str_new_frozen(rb_cString, shared2);  /* can return shared1 */
    if (STR_SHARED_P(str)) { /* shared1 is also a shared string */
        str_make_independent(str);  /* no frozen check */
    }
    ```

    If `shared1` was the only reference to `root`, then `root` can be
    reclaimed by the GC, leaving `shared2` in a corrupted state:

    ```
     -----------                         --------------------
     | shared1 | -------- owns --------> | shared1's buffer |
     -----------                         --------------------
          ^
          |
     -----------                         -------------------------
     | shared2 | ------ references ----> | root's buffer (freed) |
     -----------                         -------------------------
    ```

    Here is a reproduction script for the situation this commit fixes.

    ```ruby
    a = ('a' * 24).strip.freeze.strip
    -a
    p a
    4.times { GC.start }
    p a
    ```

     - string.c (str_duplicate): always share with the root string when
       the original is a shared string.
     - test_rb_str_dup.rb: specifically test `rb_str_dup` to make
       sure it does not try to share with a shared string.

    [Bug #15792]

    Closes: https://github.com/ruby/ruby/pull/2159

    Update dependencies

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_5@67766 b2dd03c8-39d4-4d8f-98ff-823fe69b080e