digitalmars.D - null dereference
- luka8088 (34/34) Mar 15 2014 I was thinking and I am not sure about the reason for not having some
- bearophile (6/10) Mar 15 2014 Eventually reference deference in D will be guarded by an assert
- luka8088 (3/14) Mar 15 2014 I am very glad to hear that! It is very frustrating for a program to
- Ary Borenszweig (3/11) Mar 15 2014 Really? I thought Walter was against this. He always says you can fire
- luka8088 (9/25) Mar 15 2014 Hm, that is true, but i think it should be a default behavior in
- Jonathan M Davis (7/21) Mar 15 2014 He is against it. Very much so. Maybe it'll happen at some point, but th...
- Adam D. Ruppe (35/35) Mar 15 2014 There is a hidden module on Linux which can activate this, sort
- luka8088 (2/40) Mar 15 2014 I was not aware of this. Thanks!
- Jonathan M Davis (14/21) Mar 15 2014 Essentially what it comes down to is the fact that because the OS alread...
- luka8088 (21/46) Mar 16 2014 That is great. At least in theory, but at the end of the day the
- Francesco Cattoglio (10/20) Mar 16 2014 I read some _very_ old threads, and apparently a null dereference
I was thinking and I am not sure about the reason for not having some king of safeguard for null dereferencing in version(assert)/debug builds. One possible reason that comes to mind is that it somewhat affects performance but should this really be an issue in version(assert)/debug build? Especially given the benefit of having file/line number and stack information outputted. module program; import std.stdio; void main () { A a1 = new A(); // auto inserted by the compiler before accessing object member // on version(assert) (or maybe on debug?) version(assert) if (a1 is null) throw new NullDereferenceError("Null Dereference"); a1.f(); A a2; // auto inserted by the compiler before accessing object member // on version(assert) (or maybe on debug?) version(assert) if (a2 is null) throw new NullDereferenceError("Null Dereference"); a1.f(); } class A { void f () { writeln("A.f called"); } } class NullDereferenceError : Error { this (string msg, string file = __FILE__, size_t line = __LINE__) { super(msg, file, line); } }
Mar 15 2014
luka8088:I was thinking and I am not sure about the reason for not having some king of safeguard for null dereferencing in version(assert)/debug builds.Eventually reference deference in D will be guarded by an assert in non-release builds. This desire is a raising tide that eventually can't be stopped. Bye, bearophile
Mar 15 2014
On 15.3.2014. 12:25, bearophile wrote:luka8088:I am very glad to hear that! It is very frustrating for a program to segfault without giving any information (on linux) even in debug mode.I was thinking and I am not sure about the reason for not having some king of safeguard for null dereferencing in version(assert)/debug builds.Eventually reference deference in D will be guarded by an assert in non-release builds. This desire is a raising tide that eventually can't be stopped. Bye, bearophile
Mar 15 2014
On 3/15/14, 8:25 AM, bearophile wrote:luka8088:Really? I thought Walter was against this. He always says you can fire up a debugger and check where the dereference occurred.I was thinking and I am not sure about the reason for not having some king of safeguard for null dereferencing in version(assert)/debug builds.Eventually reference deference in D will be guarded by an assert in non-release builds. This desire is a raising tide that eventually can't be stopped. Bye, bearophile
Mar 15 2014
On 15.3.2014. 14:34, Ary Borenszweig wrote:On 3/15/14, 8:25 AM, bearophile wrote:Hm, that is true, but i think it should be a default behavior in version(assert). I saw many discussions on this topic and many arguments but I am still not able to digest that the following produces invalid memory operation: void main () safe { Object o = null; o.toHash(); }luka8088:Really? I thought Walter was against this. He always says you can fire up a debugger and check where the dereference occurred.I was thinking and I am not sure about the reason for not having some king of safeguard for null dereferencing in version(assert)/debug builds.Eventually reference deference in D will be guarded by an assert in non-release builds. This desire is a raising tide that eventually can't be stopped. Bye, bearophile
Mar 15 2014
On Saturday, March 15, 2014 10:34:39 Ary Borenszweig wrote:On 3/15/14, 8:25 AM, bearophile wrote:He is against it. Very much so. Maybe it'll happen at some point, but the entire basis for Bearophile's assertion that it's going to happen appears to be simply the fact that many folks want it. And yes, that might eventually sway Walter, but it's far from guaranteed, and honestly, I'd be surprised if it happened. - Jonathan M Davisluka8088:Really? I thought Walter was against this. He always says you can fire up a debugger and check where the dereference occurred.I was thinking and I am not sure about the reason for not having some king of safeguard for null dereferencing in version(assert)/debug builds.Eventually reference deference in D will be guarded by an assert in non-release builds. This desire is a raising tide that eventually can't be stopped. Bye, bearophile
Mar 15 2014
There is a hidden module on Linux which can activate this, sort of: void main() { // these two lines turn it on import etc.linux.memoryerror; registerMemoryErrorHandler(); Object o = null; o.toString(); // trigger it here } etc.linux.memoryerror.NullPointerError src/etc/linux/memoryerror.d(325): ---------------- ./test56(void etc.linux.memoryerror.sigsegvDataHandler()+0xb) [0x805d44b] ./test56(_Dmain+0xa) [0x805c8ea] ./test56(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll().void __lambda1()+0x10) [0x805cb58] ./test56(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate())+0x18) [0x805cad0] ./test56(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll()+0x27) [0x805cb1f] ./test56(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate())+0x18) [0x805cad0] ./test56(_d_run_main+0x117) [0x805ca67] ./test56(main+0x14) [0x805c90c] /lib/libc.so.6(__libc_start_main+0xe6) [0xf75f3b86] ./test56() [0x805c831] As you can see there, the top line doesn't really help much, it just lists the druntime module, but the stack trace can help: it shows _Dmain in there, and if you add other functions, you can see them too. So still not quite a file+line number for the exact place (you can get that in a debugger fairly easily though) but helps find where it is, especially if you have fairly small functions.
Mar 15 2014
On 15.3.2014. 16:37, Adam D. Ruppe wrote:There is a hidden module on Linux which can activate this, sort of: void main() { // these two lines turn it on import etc.linux.memoryerror; registerMemoryErrorHandler(); Object o = null; o.toString(); // trigger it here } etc.linux.memoryerror.NullPointerError src/etc/linux/memoryerror.d(325): ---------------- ../test56(void etc.linux.memoryerror.sigsegvDataHandler()+0xb) [0x805d44b] ../test56(_Dmain+0xa) [0x805c8ea] ../test56(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll().void __lambda1()+0x10) [0x805cb58] ../test56(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate())+0x18) [0x805cad0] ../test56(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll()+0x27) [0x805cb1f] ../test56(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate())+0x18) [0x805cad0] ../test56(_d_run_main+0x117) [0x805ca67] ../test56(main+0x14) [0x805c90c] /lib/libc.so.6(__libc_start_main+0xe6) [0xf75f3b86] ../test56() [0x805c831] As you can see there, the top line doesn't really help much, it just lists the druntime module, but the stack trace can help: it shows _Dmain in there, and if you add other functions, you can see them too. So still not quite a file+line number for the exact place (you can get that in a debugger fairly easily though) but helps find where it is, especially if you have fairly small functions.I was not aware of this. Thanks!
Mar 15 2014
On Saturday, March 15, 2014 11:05:42 luka8088 wrote:I was thinking and I am not sure about the reason for not having some king of safeguard for null dereferencing in version(assert)/debug builds. One possible reason that comes to mind is that it somewhat affects performance but should this really be an issue in version(assert)/debug build? Especially given the benefit of having file/line number and stack information outputted.Essentially what it comes down to is the fact that because the OS already detects null pointer dereferences for you (hence the segfault or access violation that you get when it occurs), Walter considers it unnecessary. If you want more details, look at the resulting core dump in a debugger or run the program in a debugger to begin with. Now, that obviously doesn't always work, which is part of why many folks argue in favor of adding additional checks, but that's Walter's position. I believe that there was some work done to make it so that druntime would detect a segfault and print a stacktrace when that happens, but it's not enabled normally, and I don't know quite what state it's in. That would probably be the ideal solution though, since it gives you the stacktrace without requiring additional checks. - Jonathan M Davis
Mar 15 2014
On 16.3.2014. 0:22, Jonathan M Davis wrote:On Saturday, March 15, 2014 11:05:42 luka8088 wrote:That is great. At least in theory, but at the end of the day the following code still performs invalid memory operation and ends up being killed by the os without any change of recovery. void main () safe { Object o = null; o.toHash(); } I saw multiple failed attempts to implement handlers for such operation and throwing exceptions instead. I don't remember why, and I can't find the post, but there where claims that it will never be turned on by default. etc.linux.memoryerror.registerMemoryErrorHandler(); that Adam pointed out is great but somewhat looses it's point if it not turned on by default. Consider a simple scenario. I am writing a vibed application, and I deploy it to a linux server. Now for testing purposes I make a non-release build and add: try { ... } catch (Throwable t) { logCrash(t); } Unfortunately null deference happened and I have no info why. For argument purposes let's say that this happens rarely and I am not able to reproduce it on my machine. Now I go to the docs looking for a way to get more info out of this. And there is nothing about it in the docs.I was thinking and I am not sure about the reason for not having some king of safeguard for null dereferencing in version(assert)/debug builds. One possible reason that comes to mind is that it somewhat affects performance but should this really be an issue in version(assert)/debug build? Especially given the benefit of having file/line number and stack information outputted.Essentially what it comes down to is the fact that because the OS already detects null pointer dereferences for you (hence the segfault or access violation that you get when it occurs), Walter considers it unnecessary. If you want more details, look at the resulting core dump in a debugger or run the program in a debugger to begin with. Now, that obviously doesn't always work, which is part of why many folks argue in favor of adding additional checks, but that's Walter's position. I believe that there was some work done to make it so that druntime would detect a segfault and print a stacktrace when that happens, but it's not enabled normally, and I don't know quite what state it's in. That would probably be the ideal solution though, since it gives you the stacktrace without requiring additional checks. - Jonathan M Davis
Mar 16 2014
On Saturday, 15 March 2014 at 23:23:04 UTC, Jonathan M Davis wrote:I believe that there was some work done to make it so that druntime would detect a segfault and print a stacktrace when that happens, but it's not enabled normally, and I don't know quite what state it's in. That would probably be the ideal solution though, since it gives you the stacktrace without requiring additional checks. - Jonathan M DavisI read some _very_ old threads, and apparently a null dereference raised an exception only on Windows, while on linux it still needed work to be implemented properly. Things probably changed a lot in the mean time, but I think the default behaviour should be "throw an exception" on every platform. A core dump with zero extra info is bad. I don't care if 95% of times you can fire up a debugger and find out what happened. This is not something that can be always done.
Mar 16 2014