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/p1519504756000002 https://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
Comment #12 by dfj1esp02 — 2018-02-28T08:40:31Z
(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.