digitalmars.D - Shouldn't invalid references like this fail at compile time?
- Aedt (15/15) Jan 22 2018 I was asked in Reddit
- Mike Franklin (7/22) Jan 22 2018 D is not memory safe by default (unfortunately), so it's not
- Seb (3/11) Jan 22 2018 Yep, DMD will complain:
- ag0aep6g (13/15) Jan 22 2018 You might get surprised then, if you expect the compiler to reject code
- Mike Franklin (2/7) Jan 22 2018 https://issues.dlang.org/show_bug.cgi?id=18281
- Mike Franklin (4/9) Jan 22 2018 In trying to work out a solution to that, I ran across this
- Mike Franklin (24/29) Jan 22 2018 Due to the aforementioned bugs in my prior posts, I couldn't even
- Mike Franklin (24/42) Jan 22 2018 Gah!!! I screwed up that example, and I can't edit the post. See
- Mike Franklin (2/3) Jan 22 2018 https://issues.dlang.org/show_bug.cgi?id=18283
- ag0aep6g (8/36) Jan 22 2018 No bug.
- Nicholas Wilson (4/9) Jan 22 2018 The compiler should be taught that any access to a `.destroy()`ed
- Mike Franklin (34/37) Jan 22 2018 Interestingly, `destroy` is an unsafe operation for classes.
- Steven Schveighoffer (30/42) Jan 23 2018 Because it's calling a @system function, rt_finalize. This function
- Mike Franklin (5/12) Jan 23 2018 Are there any bugzilla issues that you are aware of that document
- Mike Franklin (8/15) Jan 23 2018 That's what kindof ticks me off about this "null is memory safe"
- Walter Bright (8/12) Jan 23 2018 It's an extremely useful argument, though, as modern computers have virt...
- Mike Franklin (18/20) Jan 23 2018 I think you need to get involved in programming microcontrollers
- Jonathan M Davis (17/36) Jan 23 2018 Well, we can just mandate that dereferencing null be @safe such that if ...
- Walter Bright (7/9) Jan 24 2018 I put a limit in at one time for struct/class sizes to prevent this issu...
- Jonathan M Davis (23/32) Jan 24 2018 Yes, but we need to do _something_ about the overly large structs/classe...
- Steven Schveighoffer (9/21) Jan 25 2018 You don't need to ban them from @safe code, what you need to do is
- lobo (15/37) Jan 23 2018 Well if your embedded device has all that on it you should be
- Mike Franklin (7/10) Jan 23 2018 I don't see how the OS can help if the underlying hardware
- lobo (26/37) Jan 24 2018 OK I'll state here that personally I don't agree with the
- Kagamin (2/5) Jan 24 2018 If you write everything from scratch with safety-oriented design?
- Mike Franklin (2/4) Jan 25 2018 Yep, I know exactly what you mean.
- H. S. Teoh (11/17) Jan 25 2018 Me Too (tm). After having gotten used to D, working with C/C++ (or just
- Jonathan M Davis (8/18) Jan 26 2018 Well at least you don't have to program in Java. :)
- H. S. Teoh (41/62) Jan 26 2018 I haven't touched Java in a long while, but the last time I looked, it
- Steven Schveighoffer (28/50) Jan 24 2018 While I understand your argument, the truth is that avoiding null
- Seb (6/14) Jan 24 2018 There's also:
- Jonathan M Davis (3/19) Jan 24 2018 Those really have nothing to do with null pointers though.
- Walter Bright (4/7) Jan 24 2018 Ok, but are these devices with 0 being a valid address?
- Mike Franklin (14/17) Jan 24 2018 Yes, 0 is a valid address and typically points to ROM
- Mike Franklin (3/6) Jan 24 2018 Sorry! Wrong link. Try this one:
- Walter Bright (3/7) Jan 24 2018 "These values are then loaded into the appropriate CPU registers at rese...
- Mike Franklin (7/9) Jan 24 2018 I'm not sure what you mean. When you upload your firmware to the
- Mike Franklin (5/7) Jan 24 2018 Yes, ROM is at address 0. Address 0 contains the initial stack
- Mike Franklin (6/9) Jan 24 2018 Keep in mind too that the ROM, on these devices, is actually
- Walter Bright (6/13) Jan 24 2018 I've posted online many times that people creating embedded systems shou...
- Kagamin (3/5) Jan 23 2018 Well, if you want to check much at compile time, you probably
I was asked in Reddit (https://www.reddit.com/r/learnprogramming/comments/7ru82l/i_was_thinking_of_using d_haxe_or_another/) how would D handle the following similar D code. I'm surprised that both dmd and ldc provides no warnings even with -w argument passed. import std.stdio; void main() { string foo = "foo"; string* p1, p2; string*[] ls; ls ~= &foo; p1 = ls[0]; ls.destroy(); p2 = ls[0]; writeln(p2); }
Jan 22 2018
On Monday, 22 January 2018 at 23:30:16 UTC, Aedt wrote:I was asked in Reddit (https://www.reddit.com/r/learnprogramming/comments/7ru82l/i_was_thinking_of_using d_haxe_or_another/) how would D handle the following similar D code. I'm surprised that both dmd and ldc provides no warnings even with -w argument passed. import std.stdio; void main() { string foo = "foo"; string* p1, p2; string*[] ls; ls ~= &foo; p1 = ls[0]; ls.destroy(); p2 = ls[0]; writeln(p2); }D is not memory safe by default (unfortunately), so it's not surprising to me that you can do this in ` system` code. I would be surprised if the compiler allowed you to do something like this in ` safe` code. To make your programs memory safe, you should add ` safe` to your `main` function. Mike
Jan 22 2018
On Tuesday, 23 January 2018 at 00:20:45 UTC, Mike Franklin wrote:On Monday, 22 January 2018 at 23:30:16 UTC, Aedt wrote:Yep, DMD will complain: https://run.dlang.io/is/x0Xfx8[...]D is not memory safe by default (unfortunately), so it's not surprising to me that you can do this in ` system` code. I would be surprised if the compiler allowed you to do something like this in ` safe` code. To make your programs memory safe, you should add ` safe` to your `main` function. Mike
Jan 22 2018
On 01/23/2018 01:20 AM, Mike Franklin wrote:I would be surprised if the compiler allowed you to do something like this in ` safe` code.You might get surprised then, if you expect the compiler to reject code like that statically. If you add ` safe`, the compiler rejects this line: ls ~= &foo; But that line would only be problematic if the pointer would leave the scope of the function. It doesn't, so this is actually safe. But the compiler isn't smart enough to see this. The real question is about this line: p2 = ls[0]; That's an out-of-bounds access, and the compiler does not catch this statically. Instead, it inserts bounds-checking code that crashes the program safely with an `Error`.
Jan 22 2018
On Tuesday, 23 January 2018 at 01:08:19 UTC, ag0aep6g wrote:If you add ` safe`, the compiler rejects this line: ls ~= &foo; But that line would only be problematic if the pointer would leave the scope of the function. It doesn't, so this is actually safe. But the compiler isn't smart enough to see this.https://issues.dlang.org/show_bug.cgi?id=18281
Jan 22 2018
On Tuesday, 23 January 2018 at 01:08:19 UTC, ag0aep6g wrote:The real question is about this line: p2 = ls[0]; That's an out-of-bounds access, and the compiler does not catch this statically. Instead, it inserts bounds-checking code that crashes the program safely with an `Error`.In trying to work out a solution to that, I ran across this oddity: https://issues.dlang.org/show_bug.cgi?id=18282
Jan 22 2018
On Tuesday, 23 January 2018 at 01:08:19 UTC, ag0aep6g wrote:The real question is about this line: p2 = ls[0]; That's an out-of-bounds access, and the compiler does not catch this statically. Instead, it inserts bounds-checking code that crashes the program safely with an `Error`.Due to the aforementioned bugs in my prior posts, I couldn't even make an example to demonstrate in safe code, so I modified the example slightly in an effort to reproduce the same problem. import std.stdio; void main() safe { string foo = "foo"; string* ls0; string* p1, p2; ls0 = &foo; p1 = ls0; ls0.destroy(); p2 = ls0; writeln(p2.length); } Error: program killed by signal 11 https://run.dlang.io/is/ecYAKZ Yeah, that's pretty poopy. Not sure how to precisely define the problem here. Should `destroy` be ` system` so it can't be called in ` safe` code, or should the compiler be smart enough to figure out the flow control and throw an error? Mike
Jan 22 2018
On Tuesday, 23 January 2018 at 02:25:57 UTC, Mike Franklin wrote:Due to the aforementioned bugs in my prior posts, I couldn't even make an example to demonstrate in safe code, so I modified the example slightly in an effort to reproduce the same problem. import std.stdio; void main() safe { string foo = "foo"; string* ls0; string* p1, p2; ls0 = &foo; p1 = ls0; ls0.destroy(); p2 = ls0; writeln(p2.length); } Error: program killed by signal 11 https://run.dlang.io/is/ecYAKZGah!!! I screwed up that example, and I can't edit the post. See the example here: import std.stdio; void main() safe { string foo = "foo"; string* ls0; string* p1, p2; ls0 = &foo; p1 = ls0; ls0.destroy(); p2 = ls0; writeln(p2.length); } Compile with `-dip1000` Error: program killed by signal 11 https://run.dlang.io/is/6L6zcH So that's bad. But it looks like a bug in `-dip1000`, because if I compile without `-dip1000`, I get: onlineapp.d(9): Error: cannot take address of local foo in safe function main https://run.dlang.io/is/rHpuf1 Mike
Jan 22 2018
On Tuesday, 23 January 2018 at 02:38:42 UTC, Mike Franklin wrote:So that's bad. But it looks like a bug in `-dip1000`https://issues.dlang.org/show_bug.cgi?id=18283
Jan 22 2018
On 01/23/2018 03:38 AM, Mike Franklin wrote:import std.stdio; void main() safe { string foo = "foo"; string* ls0; string* p1, p2; ls0 = &foo; p1 = ls0; ls0.destroy(); p2 = ls0; writeln(p2.length); } Compile with `-dip1000` Error: program killed by signal 11 https://run.dlang.io/is/6L6zcH So that's bad. But it looks like a bug in `-dip1000`, because if I compile without `-dip1000`, I get: onlineapp.d(9): Error: cannot take address of local foo in safe function main https://run.dlang.io/is/rHpuf1No bug. `&foo` never leaves the scope, so `-dip1000` correctly allows it. If you try to `return p1;` or `return p2;`, you get errors from `-dip1000`. Other than that, `ls0.destroy();` just does `ls0 = null;` and then the `writeln` does a null dereference which is considered to be a guaranteed segfault. Segfaults are considered safe and ` safe` is not supposed to prevent them.
Jan 22 2018
On Tuesday, 23 January 2018 at 02:25:57 UTC, Mike Franklin wrote:Not sure how to precisely define the problem here. Should `destroy` be ` system` so it can't be called in ` safe` code, or should the compiler be smart enough to figure out the flow control and throw an error? MikeThe compiler should be taught that any access to a `.destroy()`ed object is invalid i.e. that its lifetime ends when destroy is called.
Jan 22 2018
On Tuesday, 23 January 2018 at 02:25:57 UTC, Mike Franklin wrote:Should `destroy` be ` system` so it can't be called in ` safe` code, or should the compiler be smart enough to figure out the flow control and throw an error?Interestingly, `destroy` is an unsafe operation for classes. import std.stdio; class A { void hello() safe { writeln("hello"); } } void main() safe { A a = new A(); a.hello(); destroy(a); // onlineapp.d(12): Error: safe function 'D main' cannot call // system function 'object.destroy!(A).destroy' a.hello(); } https://run.dlang.io/is/AwKBc3 But it's not an unsafe operation for structs import std.stdio; struct A { int i; void print() safe { writeln(i); } } void main() safe { A* a = new A(); a.print(); // OK a.destroy(); a.print(); // Error! } https://run.dlang.io/is/Fm7qBR Not sure if that's a bug or not. Mike
Jan 22 2018
On 1/22/18 11:11 PM, Mike Franklin wrote:On Tuesday, 23 January 2018 at 02:25:57 UTC, Mike Franklin wrote:Because it's calling a system function, rt_finalize. This function calls whatever is in the destructor, and because it works on Object level, it has no idea what the actual attributes of the derived destructor are. This needs to be fixed, but a whole host of issues like this exist with Object.Should `destroy` be ` system` so it can't be called in ` safe` code, or should the compiler be smart enough to figure out the flow control and throw an error?Interestingly, `destroy` is an unsafe operation for classes.But it's not an unsafe operation for structsBecause struct destructors are not virtual. The compiler can tell when a struct destructor is unsafe: https://run.dlang.io/is/o3ujrP Note, I had to call destroy in a sub-function because if I made main safe, it would fail to compile due to automatic destruction.Not sure if that's a bug or not.Not a bug. Also, as others have pointed out, null dereferences are also considered safe [1]. destroying an object doesn't actually deallocate it. It puts it into a state that is safe to call, but will likely crash. On 1/22/18 9:43 PM, Nicholas Wilson wrote:The compiler should be taught that any access to a `.destroy()`ed object is invalid i.e. that its lifetime ends when destroy is called.destroy is just a function, there shouldn't be any special magic for it (we have enough of that already). And in fact its lifetime has not ended, it's just destructed, and left as an empty shell. The idea behind destroy is to decouple destruction from deallocation (as delete combines the two). safe is all about memory safety, nothing else. As long as you can't corrupt memory, it is safe. -Steve [1] Note: the reason they are safe is because they generally result in a segfault, which doesn't harm any memory. This is very much a user-space POV, and doesn't take into account kernel-space where null dereferences may actually be valid memory! It also doesn't (currently) take into account possible huge objects that could extend into valid memory space, even in user space.
Jan 23 2018
On Tuesday, 23 January 2018 at 21:53:24 UTC, Steven Schveighoffer wrote:Are there any bugzilla issues that you are aware of that document this? MikeInterestingly, `destroy` is an unsafe operation for classes.Because it's calling a system function, rt_finalize. This function calls whatever is in the destructor, and because it works on Object level, it has no idea what the actual attributes of the derived destructor are. This needs to be fixed, but a whole host of issues like this exist with Object.
Jan 23 2018
On Tuesday, 23 January 2018 at 21:53:24 UTC, Steven Schveighoffer wrote:[1] Note: the reason they are safe is because they generally result in a segfault, which doesn't harm any memory. This is very much a user-space POV, and doesn't take into account kernel-space where null dereferences may actually be valid memory! It also doesn't (currently) take into account possible huge objects that could extend into valid memory space, even in user space.That's what kindof ticks me off about this "null is memory safe" argument; it seems to be only applicable to a specific platform and environment. I have a micocontroller in front of me where an address of null (essentially 0) is a perfectly valid memory address. Mike
Jan 23 2018
On 1/23/2018 4:42 PM, Mike Franklin wrote:That's what kindof ticks me off about this "null is memory safe" argument; it seems to be only applicable to a specific platform and environment.It's an extremely useful argument, though, as modern computers have virtual memory systems that map 0 to a seg fault, and have since the 80's, specifically because it DOES catch lots and lots of bugs. I always thought the IBM PC should have put the ROMs at address 0 instead of FFFF0. It probably would have saved billions of dollars.I have a micocontroller in front of me where an address of null (essentially 0) is a perfectly valid memory address.Microcontroller code tends to be small and so it's unlikely that you'll need to worry about it.
Jan 23 2018
On Wednesday, 24 January 2018 at 01:44:51 UTC, Walter Bright wrote:Microcontroller code tends to be small and so it's unlikely that you'll need to worry about it.I think you need to get involved in programming microcontrollers again because the landscape has changed drastically. The microcontrollers I use now are more powerful than PCs of the 90's. The project I'm currently working on is an HMI for industrial control with a full touchscreen 2D GUI. The code base is 240,084 lines of code and that doesn't even include the 3rd party libraries I'm using (e.g. 2D graphics library, newlib C library, FreeType font rendering library). That's not "small" by my standard of measure. And with devices such as this being increasingly connected to the Internet, such carelessness can easily be exploited as evident in https://en.wikipedia.org/wiki/2016_Dyn_cyberattack And that's not to mention the types of critical systems that run on such platforms that we are increasingly becoming more dependent on. We better start worrying about it. Mike
Jan 23 2018
On Wednesday, January 24, 2018 02:28:12 Mike Franklin via Digitalmars-d wrote:On Wednesday, 24 January 2018 at 01:44:51 UTC, Walter Bright wrote:Well, we can just mandate that dereferencing null be safe such that if it's not guaranteed that dereferencing null will segfault, the compiler will have to insert additional checks. We need to do that anyway for the overly large objects (and unfortunately don't last I heard). But as long as null checks aren't inserted when the target is going to segfault on dereferencing null, then we're not inserting unnecessary checks. That way, stuff running on a normal CPU would be the same as now (save for the objects that are too large for segfaulting to work), and targets like a microcontroller would get the extra checks so that they behaved more like if they were going to segfault on dereferencing null. But making dereferencing null system makes no sense, because that would mean that dereferencing pointers and references in general could not be safe. So, basically, anything that's not on the stack would then be system. And that would destroy safe. - Jonathan M DavisMicrocontroller code tends to be small and so it's unlikely that you'll need to worry about it.I think you need to get involved in programming microcontrollers again because the landscape has changed drastically. The microcontrollers I use now are more powerful than PCs of the 90's. The project I'm currently working on is an HMI for industrial control with a full touchscreen 2D GUI. The code base is 240,084 lines of code and that doesn't even include the 3rd party libraries I'm using (e.g. 2D graphics library, newlib C library, FreeType font rendering library). That's not "small" by my standard of measure. And with devices such as this being increasingly connected to the Internet, such carelessness can easily be exploited as evident in https://en.wikipedia.org/wiki/2016_Dyn_cyberattack And that's not to mention the types of critical systems that run on such platforms that we are increasingly becoming more dependent on. We better start worrying about it.
Jan 23 2018
On 1/23/2018 7:22 PM, Jonathan M Davis wrote:We need to do that anyway for the overly large objects (and unfortunately don't last I heard).I put a limit in at one time for struct/class sizes to prevent this issue, but got a lot of pushback on it and it was reverted. Perhaps we can revisit that - and have large struct/classes be allow only in non- safe code. In general, though, if you don't have struct/class object sizes larger than the protected memory at null, you're safe with null dereferences.
Jan 24 2018
On Wednesday, January 24, 2018 18:46:38 Walter Bright via Digitalmars-d wrote:On 1/23/2018 7:22 PM, Jonathan M Davis wrote:Yes, but we need to do _something_ about the overly large structs/classes if we want safe to be bulletproof like it's supposed to be (barring misuse of trusted, of course). I'd be inclined towards adding extra null-checks in those cases just because you'd end up with a balooning of system code in your code if we made dereferencing pointers/references to them system, but regardless, the important thing is that we do something with them (whatever that may be) so that we don't have code that the compiler claims to be safe and then goes and does something naughty with memory. Right now, those types are a lot like dynamic arrays with -noboundscheck except that the programmer didn't knowingly choose to be unsafe. Personally, I doubt that I've ever written code with types that large, but I really have no idea, because I don't know what the boundary is. I just know that I don't usually have really large types. But right now, it probably wouldn't be all that hard to shoot yourself in the foot by having a particularly large static array, and most folks would probably have no idea that they were making it so that they wouldn't get segfaults on null. The only reason that I know that that's possible is because of previous discussions on the topic here in the newsgroup, and I'm sure that plenty of other folks are in the same boat except that they haven't read those discussions and so still have no clue about it. - Jonathan M DavisWe need to do that anyway for the overly large objects (and unfortunately don't last I heard).I put a limit in at one time for struct/class sizes to prevent this issue, but got a lot of pushback on it and it was reverted. Perhaps we can revisit that - and have large struct/classes be allow only in non- safe code. In general, though, if you don't have struct/class object sizes larger than the protected memory at null, you're safe with null dereferences.
Jan 24 2018
On 1/24/18 9:46 PM, Walter Bright wrote:On 1/23/2018 7:22 PM, Jonathan M Davis wrote:You don't need to ban them from safe code, what you need to do is determine if the field itself is beyond the zero page (which causes a segfault), and if so, either read from the first byte of the struct (to cause the segfault if it's in there), or verify the struct's address is not within the zero page. We recently removed an assert for null this from all functions. Perhaps for structs that are large, in safe code add that check back. -SteveWe need to do that anyway for the overly large objects (and unfortunately don't last I heard).I put a limit in at one time for struct/class sizes to prevent this issue, but got a lot of pushback on it and it was reverted. Perhaps we can revisit that - and have large struct/classes be allow only in non- safe code. In general, though, if you don't have struct/class object sizes larger than the protected memory at null, you're safe with null dereferences.
Jan 25 2018
On Wednesday, 24 January 2018 at 02:28:12 UTC, Mike Franklin wrote:On Wednesday, 24 January 2018 at 01:44:51 UTC, Walter Bright wrote:Well if your embedded device has all that on it you should be sitting on an OS with proper memory management support. Even the hokey FreeRTOS can be configured to throw a hardware exception on nullptr access. I work on critical systems SW developing life support and pace makers. For us nullptrs and memory management is not an issue. It is not hard to design these problems out of the critical component architecture. The bigger problem is code logic bugs and for that we make heavy use of asserts and in-out contracts. We don't use D, it is all C++ and some Ada in the older systems. bye, loboMicrocontroller code tends to be small and so it's unlikely that you'll need to worry about it.I think you need to get involved in programming microcontrollers again because the landscape has changed drastically. The microcontrollers I use now are more powerful than PCs of the 90's. The project I'm currently working on is an HMI for industrial control with a full touchscreen 2D GUI. The code base is 240,084 lines of code and that doesn't even include the 3rd party libraries I'm using (e.g. 2D graphics library, newlib C library, FreeType font rendering library). That's not "small" by my standard of measure. And with devices such as this being increasingly connected to the Internet, such carelessness can easily be exploited as evident in https://en.wikipedia.org/wiki/2016_Dyn_cyberattack And that's not to mention the types of critical systems that run on such platforms that we are increasingly becoming more dependent on. We better start worrying about it. Mike
Jan 23 2018
On Wednesday, 24 January 2018 at 03:46:41 UTC, lobo wrote:Well if your embedded device has all that on it you should be sitting on an OS with proper memory management support.I don't see how the OS can help if the underlying hardware doesn't have an MMU. That being said, admittedly, the more capable microcontrollers do have an MPU that can be configured to throw a hardware exception.We don't use D, it is all C++ and some Ada in the older systems.Why don't you use D? Mike
Jan 23 2018
On Wednesday, 24 January 2018 at 04:15:27 UTC, Mike Franklin wrote:On Wednesday, 24 January 2018 at 03:46:41 UTC, lobo wrote:OK I'll state here that personally I don't agree with the segfault argument if the nullptr access can be detected at compile time. Anything that can be done at compile time should not be pushed out to runtime. That said you can architect code so that nullptrs go away and the MMU is not necessary. E.g. no pointers and no allocations after main() are just two of a number of steps you can take. Good engineering works; in the 10yrs I've been with the Health Care Devices group we haven't had one memory corruption issue in a critical component. The last memory corruption issue we had in non-critcal was 4yrs ago, in older C++ code. Memory corruption really is becoming a thing of the past in modern C++. Now the biggest problems for us are security because everything has to be internet enabled!Well if your embedded device has all that on it you should be sitting on an OS with proper memory management support.I don't see how the OS can help if the underlying hardware doesn't have an MMU. That being said, admittedly, the more capable microcontrollers do have an MPU that can be configured to throw a hardware exception.We're looking into D but at the moment but the general consensus is that the tooling is not mature enough on ARM (STM32) or Atmel AVR32 (used in our older devices). Rust is in the same boat. We have ~250 devs and there are basically three groups, C/C++, D and Rust. But it pains me to say that all three groups agree that modern C++ is probably going to win in the end. And I'm broken after using D, going back to C++ is awful and Rust just has too much friction to be enjoyable. bye, loboWe don't use D, it is all C++ and some Ada in the older systems.Why don't you use D? Mike
Jan 24 2018
On Wednesday, 24 January 2018 at 09:35:44 UTC, lobo wrote:The last memory corruption issue we had in non-critcal was 4yrs ago, in older C++ code. Memory corruption really is becoming a thing of the past in modern C++.If you write everything from scratch with safety-oriented design?
Jan 24 2018
On Wednesday, 24 January 2018 at 09:35:44 UTC, lobo wrote:And I'm broken after using D, going back to C++ is awful and Rust just has too much friction to be enjoyable.Yep, I know exactly what you mean.
Jan 25 2018
On Fri, Jan 26, 2018 at 01:08:10AM +0000, Mike Franklin via Digitalmars-d wrote:On Wednesday, 24 January 2018 at 09:35:44 UTC, lobo wrote:Me Too (tm). After having gotten used to D, working with C/C++ (or just about any other language, really) is just extremely painful. Unfortunately, I have no choice because my day job requires C/C++. D has officially ruined my life. :-D T -- Notwithstanding the eloquent discontent that you have just respectfully expressed at length against my verbal capabilities, I am afraid that I must unfortunately bring it to your attention that I am, in fact, NOT verbose.And I'm broken after using D, going back to C++ is awful and Rust just has too much friction to be enjoyable.Yep, I know exactly what you mean.
Jan 25 2018
On Thursday, January 25, 2018 17:20:21 H. S. Teoh via Digitalmars-d wrote:On Fri, Jan 26, 2018 at 01:08:10AM +0000, Mike Franklin via Digitalmars-dwrote:Well at least you don't have to program in Java. :) Unless something has changed in one of the recent versions, you can't even write a swap function in Java. :| It's definitely painful to have to program in C++ after programming in D, but I still find C++ to be more pleasant than the alternatives other than D. - Jonathan M DavisOn Wednesday, 24 January 2018 at 09:35:44 UTC, lobo wrote:Me Too (tm). After having gotten used to D, working with C/C++ (or just about any other language, really) is just extremely painful. Unfortunately, I have no choice because my day job requires C/C++. D has officially ruined my life. :-DAnd I'm broken after using D, going back to C++ is awful and Rust just has too much friction to be enjoyable.Yep, I know exactly what you mean.
Jan 26 2018
On Fri, Jan 26, 2018 at 04:36:18AM -0700, Jonathan M Davis via Digitalmars-d wrote:On Thursday, January 25, 2018 17:20:21 H. S. Teoh via Digitalmars-d wrote:I haven't touched Java in a long while, but the last time I looked, it wasn't too horrible of a language. Needlessly verbose, yes. Breaks DRY, yes. Shoehorns everything into an OO model, even where it doesn't fit, yes. But in terms of the language itself, it's kinda pretty in its own way, even if it's in an idealistic, detached-from-the-real-world kind of way. At least you're not worried about buffer overruns, memory leaks, and inscrutible pointer bugs that could literally be *anywhere* in the entire 20,000-file codebase. Overall, I'd say Java is an OK language, not horrible, but not that great either. The only thing that makes it shine is really the wealth of libraries out there that you can draw from. I'd rate it as a "meh", whereas C is pretty horrible in spite of being extremely powerful, and C++ is just masochistic (though I confess I haven't looked into its latest incarnations -- the C++ code I have to work with dates back to C++98 and probably isn't going to change anytime in the foreseeable future).On Fri, Jan 26, 2018 at 01:08:10AM +0000, Mike Franklin via Digitalmars-dwrote:Well at least you don't have to program in Java. :) Unless something has changed in one of the recent versions, you can't even write a swap function in Java. :|On Wednesday, 24 January 2018 at 09:35:44 UTC, lobo wrote:Me Too (tm). After having gotten used to D, working with C/C++ (or just about any other language, really) is just extremely painful. Unfortunately, I have no choice because my day job requires C/C++. D has officially ruined my life. :-DAnd I'm broken after using D, going back to C++ is awful and Rust just has too much friction to be enjoyable.Yep, I know exactly what you mean.It's definitely painful to have to program in C++ after programming in D, but I still find C++ to be more pleasant than the alternatives other than D.[...] I'm torn between whether C or C++ is worse. In some ways, I actually prefer C because the language is smaller, the semantics are more straightforward, and the potential dangers are well-known and well-studied. It doesn't lessen the pain, but at least you have well-established maps with which to navigate through the minefield. C++, OTOH... perhaps my opinion is biased by having had the misfortune of working with an overengineered, overdesigned C++ codebase that exemplified all the flaws of C++ and none of its advantages (thankfully, said codebase has been replaced... good riddance *shudder*). But when you're dealing with code where useful work is done inside dtors and where making a conceptual function call involves 6 layers of abstraction, one step of which involves fwrite()'ing parameters into a temporary file and fread()'ing from the other end, the only thing that can possibly come to mind is "where's my 10-foot pole and why am I not using it", and "is it even humanly possible to understand what this code actually does?!". C++ is just far too big, far too complex for any mortal to fully comprehend, and that's not even beginning to touch the semantics of a convoluted codebase that abuses the language in every possible way. No thanks, if I had the choice, I'm staying away from C++ as far as I possibly can. T -- MAS = Mana Ada Sistem?
Jan 26 2018
On 1/23/18 9:28 PM, Mike Franklin wrote:On Wednesday, 24 January 2018 at 01:44:51 UTC, Walter Bright wrote:While I understand your argument, the truth is that avoiding null dereferencing *statically* has to be built into the language from the beginning. As D is already too far along to retrofit this, your 2 options are: a) instrument the code, as Jonathan suggests (every dereference checks for null ahead of time). b) restrict your code, design, and functions that you use to ensure null pointers cannot happen. a) is something we could implement in D, and I think it might make sense as a specialized version of the compiler for certain situations. b) is something you can do in any language, and D gives you much of the tools to do so. Even implementing features of the compiler to help with option b is feasible, but I don't know what that is. An example that is slightly unrelated but on the same path: D arrays throw an error when you access an out-of-bounds value. An error is not recoverable, which means that the entire process has to die, or face undefined behavior. For vibe.d programs, this means killing the whole server if one route is implemented incorrectly. While you can restart the server, any in-progress calls will also be killed, unnecessarily. My solution to this was to create an array type that decays to a real array, but where out-of-bounds indexing throws an exception instead. I just have to be diligent about using this array type anywhere it might be an issue, and the problem is solved. And in fact, it was quite easy to do, due to the awesome powers of introspection in D. -SteveMicrocontroller code tends to be small and so it's unlikely that you'll need to worry about it.I think you need to get involved in programming microcontrollers again because the landscape has changed drastically. The microcontrollers I use now are more powerful than PCs of the 90's. The project I'm currently working on is an HMI for industrial control with a full touchscreen 2D GUI. The code base is 240,084 lines of code and that doesn't even include the 3rd party libraries I'm using (e.g. 2D graphics library, newlib C library, FreeType font rendering library). That's not "small" by my standard of measure. And with devices such as this being increasingly connected to the Internet, such carelessness can easily be exploited as evident in https://en.wikipedia.org/wiki/2016_Dyn_cyberattack And that's not to mention the types of critical systems that run on such platforms that we are increasingly becoming more dependent on. We better start worrying about it.
Jan 24 2018
On Wednesday, 24 January 2018 at 19:12:50 UTC, Steven Schveighoffer wrote:While I understand your argument, the truth is that avoiding null dereferencing *statically* has to be built into the language from the beginning. As D is already too far along to retrofit this, your 2 options are: a) instrument the code, as Jonathan suggests (every dereference checks for null ahead of time). b) restrict your code, design, and functions that you use to ensure null pointers cannot happen.There's also: c) Improve/split the language by introducing -dip25 / -dip1000 and hope that people interested in memory safety will migrate their code to it.
Jan 24 2018
On Wednesday, January 24, 2018 21:24:16 Seb via Digitalmars-d wrote:On Wednesday, 24 January 2018 at 19:12:50 UTC, Steven Schveighoffer wrote:Those really have nothing to do with null pointers though. - Jonathan M DavisWhile I understand your argument, the truth is that avoiding null dereferencing *statically* has to be built into the language from the beginning. As D is already too far along to retrofit this, your 2 options are: a) instrument the code, as Jonathan suggests (every dereference checks for null ahead of time). b) restrict your code, design, and functions that you use to ensure null pointers cannot happen.There's also: c) Improve/split the language by introducing -dip25 / -dip1000 and hope that people interested in memory safety will migrate their code to it.
Jan 24 2018
On 1/23/2018 6:28 PM, Mike Franklin wrote:I think you need to get involved in programming microcontrollers again because the landscape has changed drastically. The microcontrollers I use now are more powerful than PCs of the 90's.Ok, but are these devices with 0 being a valid address? It seems weird to me that any sane modern CPU design that can access megabytes of memory would have 0 be a valid address.
Jan 24 2018
On Thursday, 25 January 2018 at 02:41:53 UTC, Walter Bright wrote:Ok, but are these devices with 0 being a valid address? It seems weird to me that any sane modern CPU design that can access megabytes of memory would have 0 be a valid address.Yes, 0 is a valid address and typically points to ROM (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/CHDBIJJE.html). "The initial stack pointer and the address of the reset handler must be located at 0x0 and 0x4 respectively." (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/CHDBIJJE.html) So you read address 0, dereference it, and you're at the bottom of the stack. Some microcontrollers have an MPU to mitigate this. You can read one technique here: http://nuttx.org/doku.php?id=wiki:howtos:stm32-null-pointer But the MPU is an optional component, and many microcontrollers in the ARM Cortex-M family do not have one. Mike
Jan 24 2018
On Thursday, 25 January 2018 at 04:01:47 UTC, Mike Franklin wrote:"The initial stack pointer and the address of the reset handler must be located at 0x0 and 0x4 respectively." (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/CHDBIJJE.html)Sorry! Wrong link. Try this one: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0179b/ar01s01s01.html
Jan 24 2018
On 1/24/2018 8:31 PM, Mike Franklin wrote:On Thursday, 25 January 2018 at 04:01:47 UTC, Mike Franklin wrote:"These values are then loaded into the appropriate CPU registers at reset." This implies a ROM must be located there. Else how do initial values get there?"The initial stack pointer and the address of the reset handler must be located at 0x0 and 0x4 respectively."http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0 79b/ar01s01s01.html
Jan 24 2018
On Thursday, 25 January 2018 at 04:45:34 UTC, Walter Bright wrote:This implies a ROM must be located there. Else how do initial values get there?I'm not sure what you mean. When you upload your firmware to the MCU, it writes the initial stack pointer to address 0x00 and the address of the reset handler to 0x04. It is up the developer to set these values properly in the linker script (a.k.a scatter file). Mike
Jan 24 2018
On Thursday, 25 January 2018 at 04:45:34 UTC, Walter Bright wrote:This implies a ROM must be located there. Else how do initial values get there?Yes, ROM is at address 0. Address 0 contains the initial stack pointer. So you read address 0, dereference it, and then do your damage. Mike
Jan 24 2018
On Thursday, 25 January 2018 at 04:59:55 UTC, Mike Franklin wrote:Yes, ROM is at address 0. Address 0 contains the initial stack pointer. So you read address 0, dereference it, and then do your damage.Keep in mind too that the ROM, on these devices, is actually reprogrammable from the firmware itself, so one could do some clever exploitation of that feature to insert whatever they want into the product's firmware. Mike
Jan 24 2018
On 1/24/2018 9:04 PM, Mike Franklin wrote:On Thursday, 25 January 2018 at 04:59:55 UTC, Mike Franklin wrote:This is from the "what were they thinking" school of CPU design. Blargh.Yes, ROM is at address 0. Address 0 contains the initial stack pointer. So you read address 0, dereference it, and then do your damage.Keep in mind too that the ROM, on these devices, is actually reprogrammable from the firmware itself, so one could do some clever exploitation of that feature to insert whatever they want into the product's firmware.I've posted online many times that people creating embedded systems should put the firmware in ROM, so malware will not survive a reset. The riposte I get is the firmware must be rewritable from the internet in order to fix malware written to it from the internet :-)
Jan 24 2018
On Monday, 22 January 2018 at 23:30:16 UTC, Aedt wrote:I was asked in Reddit (https://www.reddit.com/r/learnprogramming/comments/7ru82l/i_was_thinking_of_using d_haxe_or_another/) how would D handle the following similar D code. I'm surprised that both dmd and ldc provides no warnings even with -w argument passed.Well, if you want to check much at compile time, you probably want SPARK or F* (fstar).
Jan 23 2018