www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - immutable T.init, and pointers to mutable data

reply "monarch_dodra" <monarchdodra gmail.com> writes:
I was playing around with how T.init works. And I think I may 
have found a type loophole.

Given that you may initialize a pointer member to the address to 
a static global:

//----
__gshared int a = 0;
struct S
{
     int* p = &a;
}
//----

Then, in theory, any variable, be they mutable or const, are 
initialized to T.init:

//----
void main()
{
     immutable S s;
}
//----

This is an issue, because I now have an immutable pointer that 
points to mutable data:
//----
     immutable S s = S.init;
     immutable int* p = s.p;
     assert(*p == 0); //OK
     a = 5;
     assert(*p == 5); //OK
//----

So this violates the type system...

The question here is:
Is this "legit" code? At what point do you think my code should 
have been rejected?
Sep 25 2014
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/25/14 5:47 AM, monarch_dodra wrote:
 I was playing around with how T.init works. And I think I may have found
 a type loophole.

 Given that you may initialize a pointer member to the address to a
 static global:

 //----
 __gshared int a = 0;
 struct S
 {
      int* p = &a;
 }
 //----

 Then, in theory, any variable, be they mutable or const, are initialized
 to T.init:

 //----
 void main()
 {
      immutable S s;
 }
 //----

 This is an issue, because I now have an immutable pointer that points to
 mutable data:
 //----
      immutable S s = S.init;
      immutable int* p = s.p;
      assert(*p == 0); //OK
      a = 5;
      assert(*p == 5); //OK
 //----

 So this violates the type system...

 The question here is:
 Is this "legit" code? At what point do you think my code should have
 been rejected?
It should be rejected. The declaration of s (the variable) should be the trigger, since it casts the pointer to immutable. Please file a bug report. -Steve
Sep 25 2014
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 25 September 2014 at 12:46:01 UTC, Steven 
Schveighoffer wrote:
 On 9/25/14 5:47 AM, monarch_dodra wrote:
 I was playing around with how T.init works. And I think I may 
 have found
 a type loophole.

 Given that you may initialize a pointer member to the address 
 to a
 static global:

 //----
 __gshared int a = 0;
 struct S
 {
     int* p = &a;
 }
 //----

 Then, in theory, any variable, be they mutable or const, are 
 initialized
 to T.init:

 //----
 void main()
 {
     immutable S s;
 }
 //----

 This is an issue, because I now have an immutable pointer that 
 points to
 mutable data:
 //----
     immutable S s = S.init;
     immutable int* p = s.p;
     assert(*p == 0); //OK
     a = 5;
     assert(*p == 5); //OK
 //----

 So this violates the type system...

 The question here is:
 Is this "legit" code? At what point do you think my code 
 should have
 been rejected?
It should be rejected. The declaration of s (the variable) should be the trigger, since it casts the pointer to immutable. Please file a bug report. -Steve
Hum... So that means certain types just *can't* be initialized (as immutable) at all?
Sep 25 2014
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/25/14 9:00 AM, monarch_dodra wrote:
 On Thursday, 25 September 2014 at 12:46:01 UTC, Steven Schveighoffer wrote:
 On 9/25/14 5:47 AM, monarch_dodra wrote:
 I was playing around with how T.init works. And I think I may have found
 a type loophole.

 Given that you may initialize a pointer member to the address to a
 static global:

 //----
 __gshared int a = 0;
 struct S
 {
     int* p = &a;
 }
 //----

 Then, in theory, any variable, be they mutable or const, are initialized
 to T.init:

 //----
 void main()
 {
     immutable S s;
 }
 //----

 This is an issue, because I now have an immutable pointer that points to
 mutable data:
 //----
     immutable S s = S.init;
     immutable int* p = s.p;
     assert(*p == 0); //OK
     a = 5;
     assert(*p == 5); //OK
 //----

 So this violates the type system...

 The question here is:
 Is this "legit" code? At what point do you think my code should have
 been rejected?
It should be rejected. The declaration of s (the variable) should be the trigger, since it casts the pointer to immutable. Please file a bug report. -Steve
Hum... So that means certain types just *can't* be initialized (as immutable) at all?
I wouldn't say that: immutable s = S(null); But clearly, any code that results in an immutable pointer to mutable data without casts is incorrect. We should start by outlawing such code, and if there are ways we can carve out certain usages, we can do that. -Steve
Sep 25 2014
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 25 September 2014 at 13:37:52 UTC, Steven 
Schveighoffer wrote:
 On 9/25/14 9:00 AM, monarch_dodra wrote:
 On Thursday, 25 September 2014 at 12:46:01 UTC, Steven 
 Schveighoffer wrote:
 On 9/25/14 5:47 AM, monarch_dodra wrote:
 I was playing around with how T.init works. And I think I 
 may have found
 a type loophole.

 Given that you may initialize a pointer member to the 
 address to a
 static global:

 //----
 __gshared int a = 0;
 struct S
 {
    int* p = &a;
 }
 //----

 Then, in theory, any variable, be they mutable or const, are 
 initialized
 to T.init:

 //----
 void main()
 {
    immutable S s;
 }
 //----

 This is an issue, because I now have an immutable pointer 
 that points to
 mutable data:
 //----
    immutable S s = S.init;
    immutable int* p = s.p;
    assert(*p == 0); //OK
    a = 5;
    assert(*p == 5); //OK
 //----

 So this violates the type system...

 The question here is:
 Is this "legit" code? At what point do you think my code 
 should have
 been rejected?
It should be rejected. The declaration of s (the variable) should be the trigger, since it casts the pointer to immutable. Please file a bug report. -Steve
Hum... So that means certain types just *can't* be initialized (as immutable) at all?
I wouldn't say that: immutable s = S(null); But clearly, any code that results in an immutable pointer to mutable data without casts is incorrect. We should start by outlawing such code, and if there are ways we can carve out certain usages, we can do that. -Steve
Hum... right, but I meant "T.init" itself would not be valid. As in: alias T = immutable(S); T t = T.init; //Illegal? This might be a borderline case, but I kind of figured that that piece of code was the *only* one that was universally valid in generic code. The context was this pull request: https://github.com/D-Programming-Language/phobos/pull/2172 This sucks...
Sep 25 2014
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/25/14 10:56 AM, monarch_dodra wrote:
 On Thursday, 25 September 2014 at 13:37:52 UTC, Steven Schveighoffer wrote:
 But clearly, any code that results in an immutable pointer to mutable
 data without casts is incorrect. We should start by outlawing such
 code, and if there are ways we can carve out certain usages, we can do
 that.
Hum... right, but I meant "T.init" itself would not be valid. As in: alias T = immutable(S); T t = T.init; //Illegal?
I would say yes, illegal. There's some interesting issues with this. For instance, what about: T[] t; t.length = 2; This is a runtime function, and the runtime isn't necessarily aware of all the intricacies of a type, it has only blunt instruments (namely the TypeInfo init data). So it really can't be asked to know what to do. I'm kind of leaning towards the notion that immutable(S) should just be illegal on principle. But that is quite limiting if you wanted to just override the type system. If we had better implicit casting mechanisms, there may have been a way to fix this, but I don't know.
 This might be a borderline case, but I kind of figured that that piece
 of code was the *only* one that was universally valid in generic code.
I think it's very borderline, not likely to affect many projects. -Steve
Sep 25 2014