robinst/taglib-ruby — Issue #8: Exception after adding frame via TagLib::ID3v2::Tag.add_frame
Author: rud1r055
Created: 2012-01-21 00:20:20+00:00
State: open

The following code leads to an `ObjectPreviouslyDeleted` exception:

```ruby
tcom = TagLib::ID3v2::TextIdentificationFrame.new('TCOM', TagLib::String::Latin1)
tcom.text = "Some composer"
@tag.add_frame tcom
# the following leads to an ObjectPreviouslyDeleted error (see Issue #8)
assert_nothing_raised do
@tag.frame_list.find { |fr| 'TCOM' == fr.frame_id }
end
```
When the new frame is created the C++ object is linked to the ruby object and a mapping is added to the tracking table.

When adding the new frame, `SWIG_ConvertPtr` is called with the `SWIG_POINTER_DISOWN` flag set, which means the GC function is set to SWIG_RubyRemoveTracking. Until the GC is called on the ruby object, a mapping of the C++ object onto the ruby object remains in the tracking table. The next step is to call `SWIG_RubyUnlinkObjects` which removes the C++ pointer from the `RTypedData` struct used by ruby to map the ruby object onto the C++ object. This makes sense, since it is possible that the underlying C++ object is deleted while the ruby object still exists.

*I think at this point the mapping should also be removed from the tracking table.* If it remains in there, accessing the newly added frame via `Tag.frame_list` throws `ObjectPreviouslyDeleted`. When accessing the frame list, it is created by `taglib_id3v2_framelist_to_ruby_array` which in turn calls `taglib_id3v2_frame_to_ruby_object` for every frame in the list. The ruby object returned by `taglib_id3v2_frame_to_ruby_object` is created via `SWIG_NewPointerObj`. This function checks the tracking table whether there already exists a mapping. It finds one, as the GC has not been called yet. But the C++ pointer in the `RTypedData` struct is `NULL` because `SWIG_RubyUnlinkObjects` has already been called, so the `ObjectPreviouslyDeleted` exception gets thrown.

I will try to issue a pull request with a suggestion for a fix shortly.