Possible @property compromise

TommiT tommitissari at hotmail.com
Fri Feb 1 05:04:17 PST 2013


On Friday, 1 February 2013 at 04:22:51 UTC, Zach the Mystic wrote:
> On Friday, 1 February 2013 at 03:39:19 UTC, TommiT wrote:
>> On Friday, 1 February 2013 at 03:13:42 UTC, Zach the Mystic 
>> wrote:
>>> On Friday, 1 February 2013 at 02:27:30 UTC, TommiT wrote:
>>>> And here's another example of why it is as big of a problem 
>>>> as I make it sound to be:
>>>>
>>>> import std.concurrency;
>>>>
>>>> struct Array
>>>> {
>>>>  int _len;
>>>>
>>>>  length struct // Using Zach's syntax
>>>>  {
>>>>      @property get() { return _len; }
>>>>      alias this = get;
>>>>      void opAssign(int rhs) { _len = rhs; }
>>>>  }
>>>> }
>>>>
>>>> void func(T)(T t)
>>>> {
>>>>  auto v = t;
>>>>  v = 10;
>>>> }
>>>>
>>>> void main()
>>>> {
>>>>  Array arr;
>>>>  spawn(&func!int, arr.length);
>>>>  arr.length = 20; // And here we have a data-race.
>>>>                   // Good luck trying to find these
>>>>                   // kinds of bugs.
>>>> }
>>>
>>> I'm sorry, I know very little about race conditions. If you 
>>> might explain just a little bit about what is happening here, 
>>> I'd be in a better position to understand what you're saying. 
>>> I really can't say anything other than please describe what 
>>> this does and why it's a problem at this time.
>>
>> spawn(&func!int, arr.length);
>>
>> ...creates a new thread and runs the following function call 
>> in it:
>> func!(int)(arr.length)
>>
>> While that function call is evaluating in the new thread, the 
>> old thread may simultaneosly execute:
>> arr.length = 20;
>>
>> Since both of those threads end up at some point calling 
>> arr.length.opAssign and therefore both of them may assign to 
>> arr._len simultaneously, that's a data-race. It would be 
>> data-race also if only one of them wrote to it and the other 
>> one just read it.
>
> I'm familiar with the fact that programmers face endless woes 
> with regard to data-races. I thought that D has unshared data 
> by default. But since Array arr is defined in main instead of 
> outside main, therefore it is sharable between the two threads? 
> If two threads have access to the same data, what makes length 
> as a property different from length as an int? This problem may 
> be over my head for now...

Actually, that example of mine was wrong - it's not a data-race. 
I failed to notice that in:
spawn(&func!int, arr.length);
...arr.length is actually converted to int using alias this. My 
bad.

Now I'm going to repeat the "spooky modification at a distance" 
problem I showed earlier, but this time, instead of writing it in 
the new syntax and the new struct behaviour you invented, I write 
it using current D syntax:

import std.concurrency;

struct Array
{
     int _len;

     struct PropType
     {
         Array* _outer; // In your syntax this was implicit

         @property int get()
         {
             return _outer._len;
         }

         alias this = get;

         void opAssign(int rhs)
         {
             _outer._len = rhs;
         }
     }

     PropType length;
}

void func(T)(T t)
     if (isImplicitlyConvertible!(T,int))
{
     // Given that is(T == Array.PropType), then
     // all 3 lines below do the same thing:
     t = 42;
     t.opAssign(42);
     t._outer._len = 42;
}

void main()
{
     Array arr;

     // setting the _outer pointer to the enclosing object:
     arr.length._outer = &arr;

     assert(arr._len == 0);
     func(arr.length); // no conversion to int happening here
     assert(arr._len == 42);
}

So, it's possible to modify arr._len just by passing arr.length 
by value to a function.


More information about the Digitalmars-d mailing list