rice 4.11.3 → 4.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b52ff5ddc64209e1c252d529111695d833a57d1362e15b6d223777194dc6750
4
- data.tar.gz: 214c2b675683e68d026440cc83499a7de0faa6282563c0bfa028c925e677f195
3
+ metadata.gz: '07196451c8152b8110d5a2aa17d9d1073c846139a8e08d3fe71217095c3386d6'
4
+ data.tar.gz: d0a84860a008461a29396679953abe8377f24b92ee9085ed84820dd946065390
5
5
  SHA512:
6
- metadata.gz: fdee833532115137ec7e375e83e377c5e21a634b44e0b67bb5954ea3ad04a2983ef3c6ffc5d5deb804b1d94c7b76f04d2cc94b73b054aaa0722f01fd39f58c37
7
- data.tar.gz: 23e9990bbf398a067608c29028018840506254f3a8a00a7f6cc56840ec88e70007d0309656b297b20ab31776805b3deccb14e16fface820b0ec7d3340aafc0f3
6
+ metadata.gz: 1d560e79db1a4645bd6d1084e0df00a44d79795b14d963292e731912c1bcabf29578846ff18a2bf8f8cdb171419c1b13be66b358582328ff5e4d18c61aee8731
7
+ data.tar.gz: bfa6478914622bf559db804f3ccb10fd51c39973ff7032a07d2ced37c7d5fbbacd3b9417ed4399499f97f209ec115daecabd7e9ab75a145dfaba9c6c2d94478e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.11.4 (2026-03-13)
4
+
5
+ ### Bug Fixes
6
+
7
+ * Fix memory leak (#397)
8
+
3
9
  ## 4.11.3 (2026-03-11)
4
10
 
5
11
  ### Bug Fixes
@@ -10283,8 +10283,9 @@ namespace Rice::detail
10283
10283
  if constexpr (is_complete_v<T>)
10284
10284
  {
10285
10285
  // is_abstract_v requires a complete type, so nest inside is_complete_v.
10286
- // Deleting an abstract class through a non-virtual destructor is UB.
10287
- if constexpr (std::is_destructible_v<T> && !std::is_abstract_v<T>)
10286
+ // Deleting an abstract class through a non-virtual destructor is UB,
10287
+ // but it is safe if the destructor is virtual.
10288
+ if constexpr (std::is_destructible_v<T> && (!std::is_abstract_v<T> || std::has_virtual_destructor_v<T>))
10288
10289
  {
10289
10290
  if (this->isOwner_)
10290
10291
  {
data/lib/rice/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rice
2
- VERSION = "4.11.3"
2
+ VERSION = "4.11.4"
3
3
  end
@@ -122,8 +122,9 @@ namespace Rice::detail
122
122
  if constexpr (is_complete_v<T>)
123
123
  {
124
124
  // is_abstract_v requires a complete type, so nest inside is_complete_v.
125
- // Deleting an abstract class through a non-virtual destructor is UB.
126
- if constexpr (std::is_destructible_v<T> && !std::is_abstract_v<T>)
125
+ // Deleting an abstract class through a non-virtual destructor is UB,
126
+ // but it is safe if the destructor is virtual.
127
+ if constexpr (std::is_destructible_v<T> && (!std::is_abstract_v<T> || std::has_virtual_destructor_v<T>))
127
128
  {
128
129
  if (this->isOwner_)
129
130
  {
@@ -188,6 +188,36 @@ namespace
188
188
  static inline MyCopyableClass* instance_ = nullptr;
189
189
  };
190
190
 
191
+ // Abstract class with virtual destructor - deletion through base pointer is safe
192
+ class AbstractVirtualDtor
193
+ {
194
+ public:
195
+ static inline int destructorCalls = 0;
196
+
197
+ static void reset()
198
+ {
199
+ destructorCalls = 0;
200
+ }
201
+
202
+ virtual ~AbstractVirtualDtor()
203
+ {
204
+ destructorCalls++;
205
+ }
206
+
207
+ virtual int compute() const = 0;
208
+ };
209
+
210
+ class ConcreteChild : public AbstractVirtualDtor
211
+ {
212
+ public:
213
+ int compute() const override { return 42; }
214
+ };
215
+
216
+ AbstractVirtualDtor* createChild()
217
+ {
218
+ return new ConcreteChild();
219
+ }
220
+
191
221
  class OwnerBox;
192
222
 
193
223
  class AliasBox
@@ -327,6 +357,14 @@ SETUP(Ownership)
327
357
  .define_constructor(Constructor<SharedFactory>())
328
358
  .define_method("create_owned", &SharedFactory::createOwned, Return().takeOwnership())
329
359
  .define_method("get_borrowed", &SharedFactory::getBorrowed);
360
+
361
+ define_class<AbstractVirtualDtor>("AbstractVirtualDtor")
362
+ .define_method("compute", &AbstractVirtualDtor::compute);
363
+
364
+ define_class<ConcreteChild, AbstractVirtualDtor>("ConcreteChild");
365
+
366
+ define_module("AbstractVirtualDtorTest")
367
+ .define_module_function("create_child", &createChild, Return().takeOwnership());
330
368
  }
331
369
 
332
370
  TEARDOWN(Ownership)
@@ -541,3 +579,23 @@ TESTCASE(MultipleOwnerReferences)
541
579
  result = m.module_eval(code);
542
580
  ASSERT_EQUAL(Qfalse, result.value());
543
581
  }
582
+
583
+ TESTCASE(AbstractVirtualDestructor)
584
+ {
585
+ AbstractVirtualDtor::reset();
586
+
587
+ Module m = define_module("TestingModule");
588
+
589
+ std::string code = R"(child = AbstractVirtualDtorTest.create_child
590
+ child.compute)";
591
+
592
+ Object result = m.module_eval(code);
593
+ ASSERT_EQUAL(detail::To_Ruby<int>().convert(42), result.value());
594
+
595
+ // Force GC to clean up the object - destructor should be called
596
+ // since AbstractVirtualDtor has a virtual destructor
597
+ rb_gc_start();
598
+ rb_gc_start();
599
+
600
+ ASSERT_EQUAL(1, AbstractVirtualDtor::destructorCalls);
601
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rice
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.11.3
4
+ version: 4.11.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Brannan