Object reference lifetimes and use-after-destroy

1 view
Skip to first unread message

Bill Cox

unread,
May 1, 2023, 7:10:53 PM5/1/23
to Rune language discussion
Consider this code:

class Foo(self) {
}
class Bar(self, foo: Foo) {
  foo.appendBar(self)
}
relation DoublyLinked Foo Bar cascade

foo = Foo()
Bar(foo)
Bar(foo)
for bar in foo.bars() {
    bar.destroy()
}


This is an error because we delete the bar that is the loop variable.  The C Rune compiler does not catch this, but the bootstrap compiler should.  In short, it should ensure that any held reference to an object is not accessed after the object is destroyed.

We also have "safe" iterators, which look like:

class Foo(self) {
}
class Bar(self, foo: Foo) {
  foo.appendBar(self)
}
relation DoublyLinked Foo Bar cascade

foo = Foo()
Bar(foo)
Bar(foo)
for bar in foo.safeBars() {
    bar.destroy()
}


This code safely deletes the loop variable.  In general, we could check that Bar.destroy() is not called in any path in the call hierarchy when a live Foo reference lifetime extends past the call.  For safe iterators, the lifetime of the loop variable bar extends only to bar.destroy().  For other iterators, it also includes the end of the loop where bar is accessed again to update it for the next iteration.

A simple rule like this would have some consequences.  For example, it would be a compile time error to have a global object reference who's lifetime spans a potential call to a destructor of the same class type.  So, the following code would fail to compile:

class Foo(self) {
}
class Bar(self, foo: Foo) {
  foo.appendBar(self)
}
relation DoublyLinked Foo Bar cascade

foo = Foo()
bar1 = Bar(foo)
bar2 = Bar(foo)
bar2.destroy()
println bar1

The problem here is bar1's lifetime spans bar2.destroy().  Obviously they are not the same objects.  Maybe the compiler should detect a specific object's creation and destruction, and label such pairs as OK?  Similarly, it could detect in a safe loop that only the loop variable is destroyed, even when that happens in a function called from the loop.  This looks like fun code to write.

Bill
Reply all
Reply to author
Forward
0 new messages