[cpp-threads] Prism 0.9.1, and further on the effects of races

Herb Sutter hsutter at microsoft.com
Tue Sep 12 20:31:28 BST 2006


Jeremy wrote:
> That doesn't really solve (B), of course.  Although you could change the
> semantics slightly:
>
> a) say that if you share an object via a data race, you don't
> necessarily invoke the right method, because the object may not be fully
> constructed, and

But it's worse, you're actually indexing to an invalid vtable index.

For clarity, esp. for others on this thread who are newer to the issue, as I am, I should add an actual clarifying example. See below for a first cut, comments welcome.

> b) if the pointer is /actually/ garbage, and you get a bus error, retry.
>
> I don't know if that is even faintly realistic, though.

Wouldn't you have a null an arbitrary number of "extra" entries at the end of every base class's vtable though? How would you know how many are enough? A random memory location could have a value that happens to be an address in a code segment.

The example is this:

  class Base {
  public:
    Base() { /* some work */ }
    virtual void BaseFunc() { }    // vtable slot 0
  };

  class Derived : public Base {
  public:
    Derived() { /* some work */ }
    virtual void DerivedFunc() { } // vtable slot 1
  };

And we have:

  thread 1: global_ptr = new Derived();

With no constraints, this could execute as:

            global_ptr = (Derived*)operator new( sizeof(Derived) );
            global_ptr->vptr = &Base::vtable;     // a
            global_ptr->Base ctor body;
            global_ptr->vptr = &Derived::vtable;  // b
            global_ptr->Derived ctor body;

And in a race we perform:

  thread 2: global_ptr->DerivedFunc();            // c

Even without reordering, the issue is that we can still get line c executing between a and b: Line a sets the vptr to point to an array of length one (highest valid slot is 0), and line c tries to read a pointer out of slot 1 which doesn't exist (probably garbage), and executes it (undefined behavior).

Herb


> -----Original Message-----
> From: cpp-threads-bounces at decadentplace.org.uk [mailto:cpp-threads-
> bounces at decadentplace.org.uk] On Behalf Of Jeremy Manson
> Sent: Tuesday, September 12, 2006 11:18 AM
> To: C++ threads standardisation
> Cc: Bjarne Stroustrup
> Subject: Re: [cpp-threads] Prism 0.9.1, and further on the effects of
> races
>
> Herb Sutter wrote:
>
> > Thoughts?
>
> Not necessarily a thought on C++, but I thought it would be worth
> pointing out that we had the conversation about (A) for Java.
> Basically, it wasn't much of a problem for us, because all memory in
> Java is zeroed out before allocation.  So all we needed to do was
> perform a memory barrier and try again in the case of a
> NullPointerException.
>
> Hypothetically, you could try to apply this to C++.  If your new()
> implementation zeroes memory, for example, this would work.
>
> That doesn't really solve (B), of course.  Although you could change the
> semantics slightly:
>
> a) say that if you share an object via a data race, you don't
> necessarily invoke the right method, because the object may not be fully
> constructed, and
>
> b) if the pointer is /actually/ garbage, and you get a bus error, retry.
>
> I don't know if that is even faintly realistic, though.
>
>                                         Jeremy
>
> --
> cpp-threads mailing list
> cpp-threads at decadentplace.org.uk
> http://www.decadentplace.org.uk/cgi-bin/mailman/listinfo/cpp-threads



More information about the cpp-threads mailing list