Thread overview
Design by contract - detecting reentrancy
Nov 11, 2001
John Nagle
Nov 11, 2001
Walter
Nov 11, 2001
John Nagle
Nov 12, 2001
Walter
Nov 12, 2001
Russell Borogove
Nov 12, 2001
Walter
November 11, 2001
   There's been some interest in what's usually called "design by
contract", with "entry", "exit", and "class invariant" assertions.
The class invariants are supposed to be true whenever control
is not within the object.  If you take that seriously, you have to
be explicit about when control leaves the object.  That's rarely done.

   The difficult problem in the single-thread case is deciding
when control has left the via a call, rather than a return.  If
a call out of an object results in entering the object reentrantly,
the assumption that the object is in a valid (invariant=true) state
at entry is violated.  This often leads to errors.  (It's a
common problem inside GUI libraries.)

   Does D deal with this problem at all?  I haven't seen
any indication that it does.

   A starting point would be to provide a way to indicate that
you're leaving an object.  I'd once suggested using "public"
for this in C++, so that you'd write a member function like

   void foo()
   {	x = 1;
	public { /* control has left the object */ }
	y = 2;
   }

Within a "public" block, you can't access private members
of the object.  But you can call public methods of the object.
The "public" block is thus "outside" the object.
The class invariant has to be true at the start of a public
block.

    If you call a function outside an object from within
a member function, without using a "public" block, then
somehow it must be determined that object-reentry
via recursion is imposible.  This is easy to check at run
time, but hard to detect at compile time.  It's worth
thinking about conservative compile-time detection of recursion.

    Comments?

					John Nagle
					Animats
November 11, 2001
The class invariant is called at the entry and exit of each public member function. I do not see how this can be evaded in the scenario you described.

"John Nagle" <nagle@animats.com> wrote in message news:3BEDDB78.4517D814@animats.com...
>    There's been some interest in what's usually called "design by
> contract", with "entry", "exit", and "class invariant" assertions.
> The class invariants are supposed to be true whenever control
> is not within the object.  If you take that seriously, you have to
> be explicit about when control leaves the object.  That's rarely done.
>
>    The difficult problem in the single-thread case is deciding
> when control has left the via a call, rather than a return.  If
> a call out of an object results in entering the object reentrantly,
> the assumption that the object is in a valid (invariant=true) state
> at entry is violated.  This often leads to errors.  (It's a
> common problem inside GUI libraries.)
>
>    Does D deal with this problem at all?  I haven't seen
> any indication that it does.
>
>    A starting point would be to provide a way to indicate that
> you're leaving an object.  I'd once suggested using "public"
> for this in C++, so that you'd write a member function like
>
>    void foo()
>    { x = 1;
> public { /* control has left the object */ }
> y = 2;
>    }
>
> Within a "public" block, you can't access private members
> of the object.  But you can call public methods of the object.
> The "public" block is thus "outside" the object.
> The class invariant has to be true at the start of a public
> block.
>
>     If you call a function outside an object from within
> a member function, without using a "public" block, then
> somehow it must be determined that object-reentry
> via recursion is imposible.  This is easy to check at run
> time, but hard to detect at compile time.  It's worth
> thinking about conservative compile-time detection of recursion.
>
>     Comments?
>
> John Nagle
> Animats


November 11, 2001
   If you really know when control is outside the object, you
don't have to check the invariant at entry, just at exit.
Even better, you only have to check the parts of the invariant that
mention variables changed in the function.  This allows big invariants
with less overhead.

   The other case where control "leaves" the object is when
a thread unlocks a "synchronized" object in the Java sense.
That's "leaving the object", since some other thread can get in.
If the language knows about synchronization, it needs to know
about that.

					John Nagle
					Animats

Walter wrote:
> 
> The class invariant is called at the entry and exit of each public member function. I do not see how this can be evaded in the scenario you described.
> 
> "John Nagle" <nagle@animats.com> wrote in message news:3BEDDB78.4517D814@animats.com...
> >    There's been some interest in what's usually called "design by
> > contract", with "entry", "exit", and "class invariant" assertions.
> > The class invariants are supposed to be true whenever control
> > is not within the object.  If you take that seriously, you have to
> > be explicit about when control leaves the object.  That's rarely done.
> >
> >    The difficult problem in the single-thread case is deciding
> > when control has left the via a call, rather than a return.  If
> > a call out of an object results in entering the object reentrantly,
> > the assumption that the object is in a valid (invariant=true) state
> > at entry is violated.  This often leads to errors.  (It's a
> > common problem inside GUI libraries.)
> >
> >    Does D deal with this problem at all?  I haven't seen
> > any indication that it does.
> >
> >    A starting point would be to provide a way to indicate that
> > you're leaving an object.  I'd once suggested using "public"
> > for this in C++, so that you'd write a member function like
> >
> >    void foo()
> >    { x = 1;
> > public { /* control has left the object */ }
> > y = 2;
> >    }
> >
> > Within a "public" block, you can't access private members
> > of the object.  But you can call public methods of the object.
> > The "public" block is thus "outside" the object.
> > The class invariant has to be true at the start of a public
> > block.
> >
> >     If you call a function outside an object from within
> > a member function, without using a "public" block, then
> > somehow it must be determined that object-reentry
> > via recursion is imposible.  This is easy to check at run
> > time, but hard to detect at compile time.  It's worth
> > thinking about conservative compile-time detection of recursion.
> >
> >     Comments?
> >
> > John Nagle
> > Animats
November 12, 2001
But another thread getting into the object must necessarilly pass through an invariant first.

"John Nagle" <nagle@animats.com> wrote in message news:3BEED746.2D5B90F5@animats.com...
>    If you really know when control is outside the object, you
> don't have to check the invariant at entry, just at exit.
> Even better, you only have to check the parts of the invariant that
> mention variables changed in the function.  This allows big invariants
> with less overhead.
>
>    The other case where control "leaves" the object is when
> a thread unlocks a "synchronized" object in the Java sense.
> That's "leaving the object", since some other thread can get in.
> If the language knows about synchronization, it needs to know
> about that.
>
> John Nagle
> Animats
>
> Walter wrote:
> >
> > The class invariant is called at the entry and exit of each public
member
> > function. I do not see how this can be evaded in the scenario you
described.
> >
> > "John Nagle" <nagle@animats.com> wrote in message news:3BEDDB78.4517D814@animats.com...
> > >    There's been some interest in what's usually called "design by
> > > contract", with "entry", "exit", and "class invariant" assertions.
> > > The class invariants are supposed to be true whenever control
> > > is not within the object.  If you take that seriously, you have to
> > > be explicit about when control leaves the object.  That's rarely done.
> > >
> > >    The difficult problem in the single-thread case is deciding
> > > when control has left the via a call, rather than a return.  If
> > > a call out of an object results in entering the object reentrantly,
> > > the assumption that the object is in a valid (invariant=true) state
> > > at entry is violated.  This often leads to errors.  (It's a
> > > common problem inside GUI libraries.)
> > >
> > >    Does D deal with this problem at all?  I haven't seen
> > > any indication that it does.
> > >
> > >    A starting point would be to provide a way to indicate that
> > > you're leaving an object.  I'd once suggested using "public"
> > > for this in C++, so that you'd write a member function like
> > >
> > >    void foo()
> > >    { x = 1;
> > > public { /* control has left the object */ }
> > > y = 2;
> > >    }
> > >
> > > Within a "public" block, you can't access private members
> > > of the object.  But you can call public methods of the object.
> > > The "public" block is thus "outside" the object.
> > > The class invariant has to be true at the start of a public
> > > block.
> > >
> > >     If you call a function outside an object from within
> > > a member function, without using a "public" block, then
> > > somehow it must be determined that object-reentry
> > > via recursion is imposible.  This is easy to check at run
> > > time, but hard to detect at compile time.  It's worth
> > > thinking about conservative compile-time detection of recursion.
> > >
> > >     Comments?
> > >
> > > John Nagle
> > > Animats


November 12, 2001

John Nagle wrote:
> 
>    If you really know when control is outside the object, you
> don't have to check the invariant at entry, just at exit.
> Even better, you only have to check the parts of the invariant that
> mention variables changed in the function.  This allows big invariants
> with less overhead.

It seems to me that checking the invariant on entry, while redundant in the general case, can also help determine if some bug has trashed the object between calls.

=RB
November 12, 2001
"Russell Borogove" <kaleja@estarcion.com> wrote in message news:3BF010A6.9EEE7EAD@estarcion.com...
> John Nagle wrote:
> >    If you really know when control is outside the object, you
> > don't have to check the invariant at entry, just at exit.
> > Even better, you only have to check the parts of the invariant that
> > mention variables changed in the function.  This allows big invariants
> > with less overhead.
> It seems to me that checking the invariant on entry, while redundant in the general case, can also help determine if some bug has trashed the object between calls.

Yes. After all, D does have pointers, and you can still have pointer bugs <g>.

Also, entry invariant checking when combined with the memory stomping of the delete operator should detect detect dangling reference bugs.