digitalmars.D.learn - Why is &array[0] safer than array.ptr?
- Atila Neves (12/12) Jan 24 2017 void main() {
- Stefan Koch (2/14) Jan 24 2017 the type is still a type with bounds and not an unbounded pointer.
- TheFlyingFiddle (9/21) Jan 24 2017 Just a speculative guess.
- Atila Neves (10/37) Jan 24 2017 &array[5] makes sense to bounds check, and I guess then the issue
- David Nadlinger (6/9) Jan 25 2017 How do you know it does not screw up anything? Presumably, the
- Jonathan M Davis via Digitalmars-d-learn (9/20) Jan 24 2017 Likely because it does bounds checking, so you at least know that it's n...
- Rene Zwanenburg (20/28) Jan 24 2017 Pointer arithmetic is forbidden in @safe code so that's not a
- Jonathan M Davis via Digitalmars-d-learn (10/39) Jan 24 2017 Sure, there can be problems with .ptr. It's not necessarily a problem th...
- Dukc (7/10) Jan 24 2017 That may well be. But I believe everything that can provably be
- Kagamin (4/7) Jan 25 2017 When you ensure pointers point to existing data, you can
- Jonathan M Davis via Digitalmars-d-learn (12/19) Jan 25 2017 Fine, but in the vast majority of cases, you're calling .ptr, because yo...
- David Nadlinger (9/16) Jan 25 2017 In that case, calling the C function isn't going to be @safe
- Jerry (5/9) Jan 25 2017 Sure I see your point. But I feel like deprecations should also
- David Nadlinger (7/9) Jan 25 2017 Wrong – one is correct, the other is not. This is because every
- Adam D. Ruppe (4/5) Jan 25 2017 But null pointers are allowed in SafeD and arr.ptr is either
- David Nadlinger (16/21) Jan 25 2017 This is a fallacy:
- Adam D. Ruppe (4/5) Jan 25 2017 Ah, yes indeed, that was mentioned earlier in the thread too, it
- Jonathan M Davis via Digitalmars-d-learn (28/36) Jan 25 2017 Yes, but my point is that you're normally only going to use .ptr to pass
- David Nadlinger (15/21) Jan 25 2017 Wrong again. If this were the case, we wouldn't have needed to
- Dukc (7/13) Jan 26 2017 Pehaps it should say something like: arr.ptr is deprecated in
void main() { foo; } void foo() safe { int[] array; auto ptr = array.ptr; } foo.d(7): Deprecation: array.ptr cannot be used in safe code, use &array[0] instead &array[0] is incredibly ugly and feels like an unnecessary hack, and I'm wondering why it's safe. Atila
Jan 24 2017
On Tuesday, 24 January 2017 at 11:28:17 UTC, Atila Neves wrote:void main() { foo; } void foo() safe { int[] array; auto ptr = array.ptr; } foo.d(7): Deprecation: array.ptr cannot be used in safe code, use &array[0] instead &array[0] is incredibly ugly and feels like an unnecessary hack, and I'm wondering why it's safe. Atilathe type is still a type with bounds and not an unbounded pointer.
Jan 24 2017
On Tuesday, 24 January 2017 at 11:28:17 UTC, Atila Neves wrote:void main() { foo; } void foo() safe { int[] array; auto ptr = array.ptr; } foo.d(7): Deprecation: array.ptr cannot be used in safe code, use &array[0] instead &array[0] is incredibly ugly and feels like an unnecessary hack, and I'm wondering why it's safe. AtilaJust a speculative guess. unittest safe { int[] array; auto ptr = array.ptr; //could be null auto ptr2 = &array[0]; //Does a bounds check? auto ptr3 = &array[5]; //Should do a bounds check. }
Jan 24 2017
On Tuesday, 24 January 2017 at 11:32:47 UTC, TheFlyingFiddle wrote:On Tuesday, 24 January 2017 at 11:28:17 UTC, Atila Neves wrote:&array[5] makes sense to bounds check, and I guess then the issue is I could instead do `array.ptr + 5` which would be bad. But it's still annoying to have to do &array[0] just to pass it to a C function, since `my_c_func(array.ptr)` isn't going to screw up anything. BTW, in that example above array.ptr is null even though array is null. It doesn't crash. Atilavoid main() { foo; } void foo() safe { int[] array; auto ptr = array.ptr; } foo.d(7): Deprecation: array.ptr cannot be used in safe code, use &array[0] instead &array[0] is incredibly ugly and feels like an unnecessary hack, and I'm wondering why it's safe. AtilaJust a speculative guess. unittest safe { int[] array; auto ptr = array.ptr; //could be null auto ptr2 = &array[0]; //Does a bounds check? auto ptr3 = &array[5]; //Should do a bounds check. }
Jan 24 2017
On Tuesday, 24 January 2017 at 11:49:59 UTC, Atila Neves wrote:But it's still annoying to have to do &array[0] just to pass it to a C function, since `my_c_func(array.ptr)` isn't going to screw up anything.How do you know it does not screw up anything? Presumably, the function somehow accesses the object the pointer targets. How would this be safe to call if the pointer were not dereferencable? — David
Jan 25 2017
On Tuesday, January 24, 2017 11:28:17 Atila Neves via Digitalmars-d-learn wrote:void main() { foo; } void foo() safe { int[] array; auto ptr = array.ptr; } foo.d(7): Deprecation: array.ptr cannot be used in safe code, use &array[0] instead &array[0] is incredibly ugly and feels like an unnecessary hack, and I'm wondering why it's safe.Likely because it does bounds checking, so you at least know that it's not null. But I don't see why that would really improve much considering that the odds are that you're really going to be accessing far more than just the first element with the pointer. It seems _slightly_ better from a safety perspective but only slightly. So, I don't know what the point is in suggesting it as an alternative. - Jonathan M Davis
Jan 24 2017
On Tuesday, 24 January 2017 at 11:38:16 UTC, Jonathan M Davis wrote:Likely because it does bounds checking, so you at least know that it's not null. But I don't see why that would really improve much considering that the odds are that you're really going to be accessing far more than just the first element with the pointer. It seems _slightly_ better from a safety perspective but only slightly. So, I don't know what the point is in suggesting it as an alternative. - Jonathan M DavisPointer arithmetic is forbidden in safe code so that's not a problem. The reason this was introduced was indeed bounds checking. For example: safe: int parse(ref char[] input) { // Pop all numeric characters from the front of the input slice and convert to int } void main() { auto input = "123".dup; parse(input); // Since all numeric chars have been popped, input is now effectively input[$ .. $]. // This means input.ptr is pointing past the end of the array. writeln(input.ptr); // Out of bounds access }
Jan 24 2017
On Tuesday, January 24, 2017 11:50:16 Rene Zwanenburg via Digitalmars-d- learn wrote:On Tuesday, 24 January 2017 at 11:38:16 UTC, Jonathan M Davis wrote:Sure, there can be problems with .ptr. It's not necessarily a problem that it's not safe. But doing &arr[0] instead of arr.ptr is almost pointless. All it does is verify that the array isn't null or empty. If you're doing arr.ptr, you're almost certainly passing it to C code, and that code will almost certainly read well past the arr[0]. So, while it makes sense to say that .ptr can't be used in safe code, it really doesn't make sense to suggest &arr[0] as an alternative. - Jonathan M DavisLikely because it does bounds checking, so you at least know that it's not null. But I don't see why that would really improve much considering that the odds are that you're really going to be accessing far more than just the first element with the pointer. It seems _slightly_ better from a safety perspective but only slightly. So, I don't know what the point is in suggesting it as an alternative. - Jonathan M DavisPointer arithmetic is forbidden in safe code so that's not a problem. The reason this was introduced was indeed bounds checking. For example: safe: int parse(ref char[] input) { // Pop all numeric characters from the front of the input slice and convert to int } void main() { auto input = "123".dup; parse(input); // Since all numeric chars have been popped, input is now effectively input[$ .. $]. // This means input.ptr is pointing past the end of the array. writeln(input.ptr); // Out of bounds access }
Jan 24 2017
On Tuesday, 24 January 2017 at 12:01:35 UTC, Jonathan M Davis wrote:So, while it makes sense to say that .ptr can't be used in safe code, it really doesn't make sense to suggest &arr[0] as an alternative.That may well be. But I believe everything that can provably be safe are made so even when apparently pointeless, because someone may find creative uses for those things. Ones the creators did not think of. And even if there are none now, that may change in the future with the language or libraries.
Jan 24 2017
On Tuesday, 24 January 2017 at 12:01:35 UTC, Jonathan M Davis wrote:So, while it makes sense to say that .ptr can't be used in safe code, it really doesn't make sense to suggest &arr[0] as an alternative.When you ensure pointers point to existing data, you can dereference them in safe code, otherwise you can't.
Jan 25 2017
On Wednesday, January 25, 2017 10:52:51 Kagamin via Digitalmars-d-learn wrote:On Tuesday, 24 January 2017 at 12:01:35 UTC, Jonathan M Davis wrote:Fine, but in the vast majority of cases, you're calling .ptr, because you're going to be passing the pointer to C code, in which case, doing &arr[0] buys you very little, since the C code is inevitably going to be reading more than that one element, and &arr[0] hasn't verified anything beyond the first element. So, telling the programmer to use &arr[0] instead of arr.ptr is just plain bizarre. Doing &arr[0] makes sense when you're just going to be messing with that one element in D code, but that's pretty much it. Otherwise, you might as well just use arr.ptr, because it's up to the programmer to verify the safety of what's going on at that point anyway. - Jonathan M DavisSo, while it makes sense to say that .ptr can't be used in safe code, it really doesn't make sense to suggest &arr[0] as an alternative.When you ensure pointers point to existing data, you can dereference them in safe code, otherwise you can't.
Jan 25 2017
On Wednesday, 25 January 2017 at 18:12:18 UTC, Jonathan M Davis wrote:Fine, but in the vast majority of cases, you're calling .ptr, because you're going to be passing the pointer to C code, in which case, doing &arr[0] buys you very little, since the C code is inevitably going to be reading more than that one element,In that case, calling the C function isn't going to be safe anyway, so you might as well use .ptr.So, telling the programmer to use &arr[0] instead of arr.ptr is just plain bizarre.What you call bizarre is a simple, actionable explanation (which is especially important as the behaviour was necessarily a backwards-incompatible change). If &arr[0] doesn't actually apply to your code, then it was mistakenly safe before. — David
Jan 25 2017
On Tuesday, 24 January 2017 at 12:01:35 UTC, Jonathan M Davis wrote:So, while it makes sense to say that .ptr can't be used in safe code, it really doesn't make sense to suggest &arr[0] as an alternative. - Jonathan M DavisSure I see your point. But I feel like deprecations should also list what one can do instead. So in that regard the suggestion makes sense.
Jan 25 2017
On Tuesday, 24 January 2017 at 11:38:16 UTC, Jonathan M Davis wrote:It seems _slightly_ better from a safety perspective but only slightly.Wrong – one is correct, the other is not. This is because every pointer in SafeD is dereferencable. Pointer arithmetic is not allowed in SafeD, so your concerns about reading from other memory do not apply. — David
Jan 25 2017
On Wednesday, 25 January 2017 at 22:46:10 UTC, David Nadlinger wrote:This is because every pointer in SafeD is dereferencable.But null pointers are allowed in SafeD and arr.ptr is either arr[0] or null....
Jan 25 2017
On Wednesday, 25 January 2017 at 22:54:32 UTC, Adam D. Ruppe wrote:On Wednesday, 25 January 2017 at 22:46:10 UTC, David Nadlinger wrote:This is a fallacy: --- safe: // Deprecated, though. ubyte oops(ubyte[] b) { return *b.ptr; } void main() { oops(new ubyte[0]); // - or - auto b = new ubyte[42]; oops(b[$ .. $]); } --- — DavidThis is because every pointer in SafeD is dereferencable.But null pointers are allowed in SafeD and arr.ptr is either arr[0] or null....
Jan 25 2017
On Wednesday, 25 January 2017 at 23:09:11 UTC, David Nadlinger wrote:This is a fallacy:Ah, yes indeed, that was mentioned earlier in the thread too, it just slipped my mind again.
Jan 25 2017
On Wednesday, January 25, 2017 22:46:10 David Nadlinger via Digitalmars-d- learn wrote:On Tuesday, 24 January 2017 at 11:38:16 UTC, Jonathan M Davis wrote:Yes, but my point is that you're normally only going to use .ptr to pass something to a C function, and even if you're doing more with it in D, odds are, you're going to be doing pointer arithmetic. All &arr[0] does over arr.ptr is check the first element. It makes it safe, but then everything else you're going to be doing after that almost certainly won't be safe. And when you combine it with marking C function trusted, this is actually pretty bad. It makes it trivial to do something like extern(C) int cFunc(int* ptr, size_t length) trusted; auto result = cFunc(&arr[0], 12); and have it be considered safe, when it's not safe at all. Now, most code would then do auto result = cFunc(&arr[0], arr.length); so in practice, it won't usally be a problem, but it makes it easy to have code treated like it's completely safe when in fact it isn't. Now, really, the fix there is to not mark the C function as trusted and require that the caller make sure they pass in arguments that are safe, but at least if they were doing auto result = cFunc(arr.ptr, arr.length); the compiler would have caught that it was system even with the C function being marked as trusted, whereas if you do &arr[0], it wouldn't. So, yes, if all you're planning to do is look at the pointer to the first element in the array, then &arr[0] is safer, but odds are quite low that that's actually what you're going to do, and in all of the other cases, you might as well just use .ptr. So, telling folks to go use &arr[0] instead of .ptr doesn't seem very helpful to me. - Jonathan M DavisIt seems _slightly_ better from a safety perspective but only slightly.Wrong – one is correct, the other is not. This is because every pointer in SafeD is dereferencable. Pointer arithmetic is not allowed in SafeD, so your concerns about reading from other memory do not apply.
Jan 25 2017
On Wednesday, 25 January 2017 at 22:59:55 UTC, Jonathan M Davis wrote:Yes, but my point is that you're normally only going to use .ptr to pass something to a C function, and even if you're doing more with it in D, odds are, you're going to be doing pointer arithmetic.Wrong again. If this were the case, we wouldn't have needed to make it a deprecation at all, since all uses would have been mistakes. A non-negligible amount of real-world D code actually uses single-object pointers. Look up the change history if you are interested – and indeed, making sure one understands the topic sufficiently well to meaningfully contribute before typing out a wall-length sermon would collectively save us a good chunk of time.And when you combine it with marking C function trusted, this is actually pretty bad.Ex falso quodlibet – once you have a piece of code mistakenly marked trusted, all guarantees are out of the window even without suspicious-looking client code. safe-ty is about mechanically verifiable code, not faith-based programming. — David
Jan 25 2017
On Wednesday, 25 January 2017 at 22:59:55 UTC, Jonathan M Davis wrote:So, yes, if all you're planning to do is look at the pointer to the first element in the array, then &arr[0] is safer, but odds are quite low that that's actually what you're going to do, and in all of the other cases, you might as well just use .ptr. So, telling folks to go use &arr[0] instead of .ptr doesn't seem very helpful to me.Pehaps it should say something like: arr.ptr is deprecated in safe code. Use &arr[0] for checked access or remove the safe attribute. That would make it clear that .ptr is not an issue, only .ptr in safe.
Jan 26 2017