Bug 18529 – .ptr on arrays can no longer be used in @safe code prevents valid code
Status
RESOLVED
Resolution
INVALID
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2018-02-27T06:43:25Z
Last change time
2018-02-28T12:35:20Z
Assigned to
No Owner
Creator
Timothee Cour
Comments
Comment #0 by timothee.cour2 — 2018-02-27T06:43:25Z
We should un-deprecate .ptr on arrays in @safe code.
It prevents valid code, eg:
// from core.demangle
printf( “shifting (%.*s)\n”, cast(int) val.length, val.ptr );
compiler issues error: Error: val.ptr cannot be used in @safe code, use &val[0] instead
However, `&val[0]` will throw if val.length==0
and the following is perfectly valid even with val.length==0:
printf( “shifting (%.*s)\n”, cast(int) val.length, val.ptr );
NOTE: the rationale for that deprecation was that the pointer can't be dereferenced. However that's no different from the following:
class A{...}
A a;
// valid in safe code even though `a` is null and can't be derefenced.
In short, &arr[0] does not replace .ptr even in safe code, because arr could have 0 elements.
See other discussions on slack:
https://dlang.slack.com/archives/C1ZDHBB2S/p1519504756000002https://dlang.slack.com/archives/C1ZDHBB2S/p1519439288000141
and other use case that gets broken:
int[]a=[0,1];
auto ptr = &a[0];
a.length=0;
a.assumeSafeAppend;
assert(a.ptr == ptr); // disallowed
assert( &a[0] == ptr); // would throw bounds error
Comment #1 by dfj1esp02 — 2018-02-27T08:29:34Z
No, array's ptr can't be blindly dereferenced:
---
int[1] a;
*a[$..$].ptr=0;
---
This is not trivial and requires a DIP.
Comment #2 by timothee.cour2 — 2018-02-27T08:39:45Z
> No, array's ptr can't be blindly dereferenced
indeed, I never said .ptr can be dereferenced; as I stated, this is no different from `class A{...} A a;` where `a` can't be dereferenced
We shouldn't deprecate unless we can suggest to users a valid alternative for `a.ptr`; as I showed, `&a[0]` is not equivalent (in case a.length==0) and it breaks valid code.
Anecdotically, all of core.demangle is broken.
Comment #3 by dfj1esp02 — 2018-02-27T08:58:47Z
---
int[]a=[0,1];
auto b = a[0..0];
a.length=0;
a.assumeSafeAppend;
assert(a[0..0] is b);
---
Would this work?
Comment #4 by slavo5150 — 2018-02-27T09:19:31Z
The original deprecation was made with this PR: https://github.com/dlang/dmd/pull/5860
It would be prudent to review the comments there in order understand the motivation and rationale.
Comment #5 by dfj1esp02 — 2018-02-27T09:46:28Z
(In reply to Timothee Cour from comment #2)
> and it breaks valid code.
Your complaint is that there was no deprecation period?
> Anecdotically, all of core.demangle is broken.
Are you sure? It has safe unittests, they wouldn't compile if it was broken.
Comment #6 by dfj1esp02 — 2018-02-27T10:18:40Z
(In reply to Timothee Cour from comment #0)
> // from core.demangle
> printf( “shifting (%.*s)\n”, cast(int) val.length, val.ptr );
> compiler issues error: Error: val.ptr cannot be used in @safe code, use
> &val[0] instead
That's issue 18407
Comment #7 by timothee.cour2 — 2018-02-27T10:25:03Z
>> Anecdotically, all of core.demangle is broken.
> Are you sure? It has safe unittests, they wouldn't compile if it was broken.
try with -debug=info
these will error:
debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr );
(many others in this file)
Why would this be suddently invalid? what's a workaround?
NOTE: this should work regardless of debug(info) being present; so: even if
https://issues.dlang.org/show_bug.cgi?id=18407 were fixed, what would be a workaround for:
printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr );
(not involving something like:
```
if(msg.length)
printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr );
else
printf( "overflow: \n");
```
)
Comment #8 by dfj1esp02 — 2018-02-27T11:30:53Z
Should go through trusted wrapper.
printf is a @system function and can't be called from safe code, arguments don't even matter.
Comment #9 by ag0aep6g — 2018-02-27T12:48:50Z
(In reply to Timothee Cour from comment #0)
> NOTE: the rationale for that deprecation was that the pointer can't be
> dereferenced. However that's no different from the following:
> class A{...}
> A a;
> // valid in safe code even though `a` is null and can't be derefenced.
Because no one seems to have addresses this so far:
Null dereferences are considered @safe. A null dereference is assumed to lead to a segfault which stops the program, preventing memory corruption.
The problem with `.ptr` isn't null. The problem is that the pointer can be invalid despite not being null.
Comment #10 by schveiguy — 2018-02-27T14:14:49Z
(In reply to anonymous4 from comment #8)
> Should go through trusted wrapper.
> printf is a @system function and can't be called from safe code, arguments
> don't even matter.
Yes, most of this argument is moot unless you find a better example.
The rational behind disallowing .ptr is simple: We want to be able to use pointers in safe D (disallowing them is too crippling). To that end we allow dereferencing a pointer, but not indexing a pointer.
In order for this to work, we must ensure that safe code cannot create a dangling pointer. That is, the pointer MUST point at valid data, or point at null.
An array with zero length does not generate a known-valid pointer with .ptr, therefore it's disallowed. Using &arr[0] works because it's first bounds-checked that the first element exists.
Comment #11 by timothee.cour2 — 2018-02-27T20:41:30Z
(In reply to Timothee Cour from comment #11)
> https://github.com/dlang/phobos/pull/6231
I doesn't allow your example though
assert(a.pointer == ptr); // silently null
assert( &a[0] == ptr); // would throw bounds error
Comment #13 by schveiguy — 2018-02-28T12:35:20Z
(In reply to anonymous4 from comment #12)
> I doesn't allow your example though
How so? The example is showing that when printf sees 0 as a length, it ignores the pointer. In his use case, the call to printf is @safe (note that even allowing the pointer call in safe code doesn't fix the fact that printf is @system anyway).
In any case, the PR was shot down by both Walter and Andrei.