Tell us your DIP1000 woes
Richard (Rikki) Andrew Cattermole
richard at cattermole.co.nz
Thu Aug 29 08:53:09 UTC 2024
I've been thinking about swap/move functions some more for my own proposal.
The following applies to swap just as much as move, but I'll use move as
its simpler to understand here.
Lets say you don't have owner escape analysis (so just DIP1000).
And you have some stack memory that then gets borrowed from.
You can corrupt the borrowed memory, by calling a function like move.
Simply because a dependency exists of the thing being moved/swapped.
```d
int* value = ...;
int** ptr = &value; // ptr depends upon value
int* another = move(value);
// ugh oh, ptr is now corrupted
```
Now lets say you are able to annotate the escape sets fully (DIP1000 can
do move).
```d
T move(T)(ref return T input);
```
Thing is, this signature just says the parameter contributes towards the
return, it doesn't consume and invalidate the original input variable.
So a solution is to throw a new attribute into the mix like
``@escapeas(return)``. To show that it'll consume the input and it will
go to a specific variable.
```d
void swap(T)(ref @escapeas(input2) T input1, ref @escapeas(input1) T
input2);
```
Ok great, you modeled the escapes, congratulations.
Or you could use owner escape analysis to say "if have borrow, make
effectively const" there cannot be assigned to.
Boom, neither swap nor move could modify the original and it all works.
So there are three scenarios here that I can think of:
1. Attribute the exact variable it'll escape to, to know that it will
invalidate the input, preventing any relationships from it from being
corrupted
2. Make these functions ``@system`` and say its a rare enough thing that
it doesn't need to be made ``@safe``
3. Use owner escape analysis to provide the effectively const guarantees
to prevent the mutation
Full example of a move in ``@safe`` code, that can corrupt memory (null,
wrong length, wrong value ext.):
```d
@safe:
void main() {
int*[1] value;
int** ptr = &value[0];
int* another = move(value[0]);
}
T move(T)(scope ref return T input) {
T temp = input;
input = T.init;
return temp;
}
```
More information about the Digitalmars-d
mailing list