www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Implicit Safe Resources

reply Menshikov <mensikovk817 gmail.com> writes:
Hi all.
I'm currently doing OpenGL type binding, and I noticed one 
assumption in the  safe code.
 safe, scope work only with explicit reference types, if your 
structure does not have such fields, then checks do not work.
In opengl, and in other APIs, we work with resources not through 
memory references, but through an integer descriptor.

```d
 safe:

struct BufferView {
   GLuint id;

   //...

   void destroy()  trusted scope {
     //...
   }
}

void doSmthScope(scope BufferRef buf) {...}
void doSmthGlobal(BufferRef buf) {...}

void test() {
   scope BufferView buffer = createBuffer();
   //we also could use generic RAII Handle type with view method
   scope(exit) buffer.dispose();

   doSmth1(buffer); //ok
   doSmth2(buffer); //ok????
}
```

A hack that can solve the problem is this:

```d
struct BufferView {
   union {
     protected uint _id;
     protected void* _hack;
   }

   auto id()  trusted => _id;
}
```

There are two problems here:
1. This is a stinky hack.
2. We have an unnecessary memory overhead. 2 bytes became 4 bytes.

I suggest this solution:

```d
import core.attributes: saferes; //SAFE RESource

 saferes
struct BufferView {
   protected uint id;
}
```

All checks for live, scope, safe, etc. must consider structures 
marked with core.attributes.saferes as a memory reference.

I don't understand the internals of the compiler, so I can't 
implement it myself. I just saw that there are few occurrences of 
hasPointers, so this function is not that difficult to implement.
It also doesn't break backwards compatibility.
You can only add  saferes at the parser level.
I don't think that DIP is needed for this function, if it is 
needed, then I can't write it myself, because I'm bad with 
English.

What do you think about this?
Sep 03 2023
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 04/09/2023 2:15 AM, Menshikov wrote:
 We have an unnecessary memory overhead. 2 bytes became 4 bytes.
A uint is 4 bytes. So it would be 4 to 8 on 32bits. On 64bit that would be 16 bytes due to alignment. But it doesn't have to be wasteful. ```d union { uint id; void* ptr; } ```
Sep 03 2023
parent reply Menshikov <mensikovk817 gmail.com> writes:
On Sunday, 3 September 2023 at 14:19:55 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 On 04/09/2023 2:15 AM, Menshikov wrote:
 We have an unnecessary memory overhead. 2 bytes became 4 bytes.
A uint is 4 bytes. So it would be 4 to 8 on 32bits. On 64bit that would be 16 bytes due to alignment. But it doesn't have to be wasteful. ```d union { uint id; void* ptr; } ```
ABI doesn't work that way, alignment happens over a larger field in the structure. ```d struct SafeRef {uint id;} struct PtrHack { union { uint id; void* ptr; } } pragma(msg, SafeRef.sizeof); // 4 pragma(msg, PtrHack.sizeof); // 8 void main(){} ```
Sep 03 2023
parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 04/09/2023 2:42 AM, Menshikov wrote:
 ABI doesn't work that way, alignment happens over a larger field in the 
 structure.
Yeah that's fine. In practice you're not saving anything by going below the size of a pointer and even if that wasn't a concern it'll align if you add more fields. Memory allocators can't allocate memory below the size of a pointer due to needing data structures like freelists.
Sep 03 2023
prev sibling parent Paul Backus <snarwin gmail.com> writes:
On Sunday, 3 September 2023 at 14:15:42 UTC, Menshikov wrote:
 Hi all.
 I'm currently doing OpenGL type binding, and I noticed one 
 assumption in the  safe code.
  safe, scope work only with explicit reference types, if your 
 structure does not have such fields, then checks do not work.
 In opengl, and in other APIs, we work with resources not 
 through memory references, but through an integer descriptor.

 ```d
  safe:

 struct BufferView {
   GLuint id;

   //...

   void destroy()  trusted scope {
     //...
   }
 }
 ```
This is one of the problems [DIP 1035's][1] system variables were designed to solve: ```d struct BufferView { system GLuint id //... } ``` When compiling with `-preview=systemVariables`, Variables with the system cannot be accessed from safe code, and are protected against accidental corruption via aliasing, unions, and so on (like how built-in reference types are protected). [1]: https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1035.md
Sep 03 2023