You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,11 @@
1
1
# Changelog
2
2
3
+
## Unreleased
4
+
5
+
Incompatible Changes:
6
+
*`InstanceRegistry.isEnabled` (boolean) has been replaced by an `InstanceRegistry.isEnabled` which is an enum (`Off`, `Owned`, `All`).
7
+
*`InstanceRegistry` now defaults to `Owned` - previously it was disabled. The goal of this change is to ensure C++ objects owned by Ruby are only wrapped once to avoid double free errors.
Copy file name to clipboardExpand all lines: docs/bindings/constructors.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -83,6 +83,10 @@ class Mat
83
83
end
84
84
```
85
85
86
+
### KeepAlive
87
+
88
+
When an object is cloned or duped, Rice automatically copies its [keepAlive](keep_alive.md) references to the new object. This ensures that the clone directly protects the same Ruby objects as the original. For example, if a `std::vector<MyClass*>` holds pointers to Ruby-wrapped objects, cloning the vector will ensure those objects are kept alive by both the original and the clone independently.
89
+
86
90
## Move Constructors
87
91
88
92
Rice does not support move constructors because there is no clean mapping of them to Ruby.
Copy file name to clipboardExpand all lines: docs/bindings/instance_registry.md
+15-4Lines changed: 15 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,17 +4,20 @@ Rice 4.1 added an instance registry which tracks which C++ objects have been wra
4
4
5
5
## Enabled
6
6
7
-
When the instance registry is enabled, Rice will check if a C++ instance has been wrapped by a Ruby instance. If it has, then the existing Ruby instance is returned.
7
+
When instance tracking is enabled (that is, mode is not `Off`), Rice will check if a C++ instance has already been wrapped by Ruby. If it has, then the existing Ruby instance is returned.
8
8
9
-
By default, instance tracking is disabled. To turn it on:
// Owned -> track only Ruby-owned wrapped instances
15
+
// All -> track both Ruby-owned and borrowed instances
13
16
```
14
17
15
18
## Disabled
16
19
17
-
When the instance registry is disabled, Rice will wrap a C++ instance in a new Ruby instance regardless of whether it is already wrapped by a Ruby instance. Therefore if you make multiple calls to a C++ method that returns the same C++ object each time via a reference or pointer, multiple wrapping Ruby objects will be created. By default having multiple Ruby objects wrap a C++ object is fine since the Ruby objects do not own the C++ object. For more information please carefully read the [C++ to Ruby](memory_management.md#c-to-ruby) topic.
20
+
When mode is `Off`, Rice will wrap a C++ instance in a new Ruby instance regardless of whether it is already wrapped by a Ruby instance. Therefore if you make multiple calls to a C++ method that returns the same C++ object each time via a reference or pointer, multiple wrapping Ruby objects will be created. By default having multiple Ruby objects wrap a C++ object is fine since the Ruby objects do not own the C++ object. For more information please carefully read the [C++ to Ruby](memory_management.md#c-to-ruby) topic.
18
21
19
22
There is one exception to this rule, which happens when a C++ method returns back itself. Rice recognizes that the C++ object is wrapped by the Ruby object making the call, and thus it is returning self (see [return self](methods.md#return-self)).
20
23
@@ -29,3 +32,11 @@ First, the implementation is not thread-safe. Due to Ruby's GIL, this is not con
29
32
Second, pairs in the global map are removed when a Ruby object is freed by the garbage collector. There could be a window where a Ruby object is marked for deletion but the underlying C++ object is returned back to Ruby. Then the Ruby object would be freed resulting in a crash. It is unknown if this really happens, it has never been observed.
30
33
31
34
Third, a C++ instance wrapped by Ruby instance may be freed on the C++ side. As long as ownership rules have been correctly setup, this is fine. However, if a new C++ instance is created that has the same address as the deleted C++ object and then is passed to Ruby the instance tracker will return the old deleted object. This has been observed in the Rice tests. It is unknown if this is due to how the tests are written or is a more general problem.
35
+
36
+
## Rule for Ruby-Owned Objects
37
+
38
+
A useful practical rule is: if Ruby owns a C++ object, there should be only one Ruby object wrapping that C++ instance. Multiple Ruby wrappers for the same Ruby-owned C++ object can create lifetime bugs where one wrapper frees the underlying C++ object while another wrapper still exists and later dereferences a dangling pointer.
39
+
40
+
The instance registry addresses this by mapping C++ instance addresses to existing Ruby wrappers and reusing the same Ruby object instead of creating duplicates. In other words, when ownership is on the Ruby side, enabling instance tracking helps enforce a single-wrapper identity and avoids this class of aliasing/lifetime errors.
41
+
42
+
Value-return wrappers do not participate in instance tracking. When C++ returns values, Rice copies or moves them into wrapper-owned storage, so there is no stable shared native address identity to reuse. Instance tracking is therefore only meaningful for pointer/reference-style aliasing cases, not value copies.
0 commit comments