digitalmars.D - prog segfaults
- Ant (30/30) Jul 27 2004 (for sure I'm overseeing something)
- Derek Parnell (31/47) Jul 27 2004 When function 'f' gets its parameters, the 'a' will be null because of t...
- Ant (5/28) Jul 27 2004 yes, that's what I was trying to confirm.
- Andy Friesen (6/23) Jul 27 2004 assert(a); is a special case in the language: it is not a boolean
- Ant (4/11) Jul 27 2004 so looks like a bug, smells like a bug, is it a bug?
- Walter (5/15) Jul 27 2004 No. assert(a) doesn't bother checking to see if a is null before calling...
- Derek Parnell (7/27) Jul 27 2004 Because assert() gives us filename and line number, but "Access Violatio...
- Regan Heath (6/33) Jul 27 2004 Good point, in fact in debug mode I want all errors to give a file and
- Walter (7/30) Jul 27 2004 part
- Derek Parnell (8/41) Jul 27 2004 Sorry, too glib. Not impressed.
- Walter (15/23) Jul 28 2004 Violation"
- Daniel Horn (6/45) Jul 28 2004 can't assert print the stack (if you have the frame pointer)?
- Walter (5/10) Jul 28 2004 It's not so easy since the debug data needed is sometimes separate. The
- Ant (6/8) Jul 28 2004 Is it possible under linux?
- Ben Hinkle (7/21) Jul 28 2004 I've been using gdb but I've noticed
- Ant (7/13) Jul 28 2004 So, why do you use it? What can you get?
- Ben Hinkle (3/19) Jul 28 2004 usually the stack trace is correct. that's all I use it for.
- Ant (4/7) Jul 28 2004 thanks, Ben and Walter and guys I can see the stack! :)
- Walter (7/16) Jul 28 2004 again)
- Nick (3/10) Jul 28 2004 Also, you can try/catch the assert if you're so inclined.
- Walter (6/16) Jul 28 2004 calling the
- Nick (19/22) Jul 28 2004 Well, it doesn't seem to work for me... (using linux). Running the
- Russ Lewis (24/49) Jul 28 2004 No. The problem here is exactly the "feature" that Walter is using.
- Walter (4/53) Jul 28 2004 The catch will work under Windows, I just haven't implemented the linux ...
- Ant (4/23) Jul 28 2004 To give a line number and file name to the poor guy that spends hours
- Walter (5/11) Jul 28 2004 the
- Regan Heath (23/37) Jul 28 2004 Ok, but, now assume the piece of software is a mail server, which you ha...
- Walter (8/27) Jul 28 2004 Yes. First of all, you can catch access violations with the catch clause
- Regan Heath (32/68) Jul 28 2004 Cool. Is "access violation" == SIGSEGV
- Walter (14/29) Jul 28 2004 */
- Mickey Finn (15/45) Jul 29 2004 function
- Mickey Finn (3/11) Jul 29 2004 5) dmd.exe uses __FILE__ & __LINE__ itself: I just got this message from...
-
Farmer
(21/24)
Jul 29 2004
"Walter"
wrote in - Sean Kelly (6/11) Jul 29 2004 There have been articles written by very smart people on how to (in code...
- Russ Lewis (20/32) Jul 29 2004 It is possible to do a portable stack trace if you know the starting
- Regan Heath (9/44) Jul 29 2004 I think some little help by the compiler would go a long way to making a...
- Regan Heath (12/49) Jul 29 2004 So change the names. debug.file and debug.line are fine by me.
- Russ Lewis (42/42) Jul 29 2004 I have written some code that allows you to view & dump the current
- Ant (6/8) Jul 29 2004 50 lines of code?
- parabolis (6/12) Jul 29 2004 Why not add char[] stackDump to Exception and fill it in in the
- Russ Lewis (7/50) Jul 29 2004 Well, what I've posted already is the distilled core of the code. I'll
- Regan Heath (11/58) Jul 29 2004 I agree. If some sort of compiler support was added for this then the
- parabolis (14/23) Jul 30 2004 I can see your point. I am just not sure how one would catch an
- Russ Lewis (22/36) Jul 30 2004 I'm pretty sure that 'esp' is the name of the Stack Pointer register in
- parabolis (32/60) Jul 30 2004 Yes ESP is the stack pointer and leaving the 'stack frame' means
- Russ Lewis (5/81) Jul 30 2004 As soon as your catch block calls printStackTrace(), you are creating a
- parabolis (32/38) Jul 30 2004 I am assuming the ESP is already corrupt by the time you would
- Russ Lewis (37/37) Jul 30 2004 Assuming that the function "catcher" has the catch block which will
- parabolis (35/48) Jul 30 2004 Yes I see what you mean. However all is not lost:
- Regan Heath (20/64) Jul 31 2004 I don't agree. I think the general case is more like:
- parabolis (8/31) Aug 01 2004 Sorry I should have been more clear. What I meant to get across
- Arcane Jill (9/15) Aug 01 2004 I think you may be forgetting that an exception (in the X86 sense, not i...
- parabolis (8/18) Aug 01 2004 I am not forgetting these process switches are thrown. I was
- parabolis (13/31) Jul 30 2004 That is pretty slick code... Treating all of memory as an array,
- Russ Lewis (12/24) Jul 30 2004 When you dump your own stack, your code is probably far better. But I
- parabolis (6/20) Jul 30 2004 Yeah I kind of suspected you might not know asm. That is why I
(for sure I'm overseeing something) bug report (?) should I post on the bugs group? I was trying to confirm we need to initialize objects pass with "out" and the executable for this just segfaults: class A { int a; } void f(out A a) { assert(a); // OK IF REPLACE BY assert(a!==null); printf("hello\n"); } void main() { A a = new A(); f(a); } Ant here is the 10 lines version: class A{int a;} void f(out A a) { assert(a); printf("hello\n"); } void main() {A a = new A();f(a);}
Jul 27 2004
On Tue, 27 Jul 2004 21:09:07 -0400, Ant wrote:class A { int a; } void f(out A a) { assert(a); // OK IF REPLACE BY assert(a!==null); printf("hello\n"); } void main() { A a = new A(); f(a); }When function 'f' gets its parameters, the 'a' will be null because of the 'out' option. Even though you passed a new instance of A to it, the out option will initialize it to null. The assert is probably redundant as this is the expected behaviour of the language. Try this code, it should crash with an access violation on the second writef() call because the f() call's out option initialized it. <code> import std.stdio; class A { int x; } void f(out A a) { assert(a is null); writef("hello\n"); } void main() { A a = new A; a.x = 1; writef("before= %d\n", a.x); f(a); writef("after = %d\n", a.x); } </code> -- Derek Melbourne, Australia 28/Jul/04 12:12:07 PM
Jul 27 2004
On Wed, 28 Jul 2004 12:18:37 +1000, Derek Parnell wrote:On Tue, 27 Jul 2004 21:09:07 -0400, Ant wrote:yes, that's what I was trying to confirm. but the program shouldn't segfault! it should print and assertion failure. (?) Antclass A { int a; } void f(out A a) { assert(a); // OK IF REPLACE BY assert(a!==null); printf("hello\n"); } void main() { A a = new A(); f(a); }When function 'f' gets its parameters, the 'a' will be null because of the 'out' option. Even though you passed a new instance of A to it, the out option will initialize it to null. The assert is probably redundant as this is the expected behaviour of the language.
Jul 27 2004
Ant wrote:On Wed, 28 Jul 2004 12:18:37 +1000, Derek Parnell wrote:assert(a); is a special case in the language: it is not a boolean not-null test, it runs A's invariant to assert that 'a' is correct. Still, you would think that an assertion failure would trip, since part of Object.invariant is "assert(this!==null);" -- andyyes, that's what I was trying to confirm. but the program shouldn't segfault! it should print and assertion failure. (?)void f(out A a) { assert(a); // OK IF REPLACE BY assert(a!==null); printf("hello\n"); }When function 'f' gets its parameters, the 'a' will be null because of the 'out' option. Even though you passed a new instance of A to it, the out option will initialize it to null. The assert is probably redundant as this is the expected behaviour of the language.
Jul 27 2004
On Tue, 27 Jul 2004 20:02:06 -0700, Andy Friesen wrote:assert(a); is a special case in the language: it is not a boolean not-null test, it runs A's invariant to assert that 'a' is correct.I didn't know that, cheking documentation ... checked, good!Still, you would think that an assertion failure would trip, since part of Object.invariant is "assert(this!==null);"so looks like a bug, smells like a bug, is it a bug? Ant
Jul 27 2004
"Ant" <duitoolkit yahoo.ca> wrote in message news:pan.2004.07.28.03.06.34.780054 yahoo.ca...On Tue, 27 Jul 2004 20:02:06 -0700, Andy Friesen wrote:No. assert(a) doesn't bother checking to see if a is null before calling the invariant, because the hardware will do that for you. Why duplicate what the hardware does?assert(a); is a special case in the language: it is not a boolean not-null test, it runs A's invariant to assert that 'a' is correct.I didn't know that, cheking documentation ... checked, good!Still, you would think that an assertion failure would trip, since part of Object.invariant is "assert(this!==null);"so looks like a bug, smells like a bug, is it a bug?
Jul 27 2004
On Tue, 27 Jul 2004 20:41:56 -0700, Walter wrote:"Ant" <duitoolkit yahoo.ca> wrote in message news:pan.2004.07.28.03.06.34.780054 yahoo.ca...Because assert() gives us filename and line number, but "Access Violation" doesn't. -- Derek Melbourne, Australia 28/Jul/04 2:29:38 PMOn Tue, 27 Jul 2004 20:02:06 -0700, Andy Friesen wrote:No. assert(a) doesn't bother checking to see if a is null before calling the invariant, because the hardware will do that for you. Why duplicate what the hardware does?assert(a); is a special case in the language: it is not a boolean not-null test, it runs A's invariant to assert that 'a' is correct.I didn't know that, cheking documentation ... checked, good!Still, you would think that an assertion failure would trip, since part of Object.invariant is "assert(this!==null);"so looks like a bug, smells like a bug, is it a bug?
Jul 27 2004
On Wed, 28 Jul 2004 14:35:05 +1000, Derek Parnell <derek psych.ward> wrote:On Tue, 27 Jul 2004 20:41:56 -0700, Walter wrote:Good point, in fact in debug mode I want all errors to give a file and line number, including access violation. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/"Ant" <duitoolkit yahoo.ca> wrote in message news:pan.2004.07.28.03.06.34.780054 yahoo.ca...Because assert() gives us filename and line number, but "Access Violation" doesn't.On Tue, 27 Jul 2004 20:02:06 -0700, Andy Friesen wrote:No. assert(a) doesn't bother checking to see if a is null before calling the invariant, because the hardware will do that for you. Why duplicate what the hardware does?assert(a); is a special case in the language: it is not a boolean not-null test, it runs A's invariant to assert that 'a' is correct.I didn't know that, cheking documentation ... checked, good!Still, you would think that an assertion failure would trip, since part of Object.invariant is "assert(this!==null);"so looks like a bug, smells like a bug, is it a bug?
Jul 27 2004
"Derek Parnell" <derek psych.ward> wrote in message news:ce7aei$2une$1 digitaldaemon.com...On Tue, 27 Jul 2004 20:41:56 -0700, Walter wrote:part"Ant" <duitoolkit yahoo.ca> wrote in message news:pan.2004.07.28.03.06.34.780054 yahoo.ca...On Tue, 27 Jul 2004 20:02:06 -0700, Andy Friesen wrote:assert(a); is a special case in the language: it is not a boolean not-null test, it runs A's invariant to assert that 'a' is correct.I didn't know that, cheking documentation ... checked, good!Still, you would think that an assertion failure would trip, sincetheNo. assert(a) doesn't bother checking to see if a is null before callingof Object.invariant is "assert(this!==null);"so looks like a bug, smells like a bug, is it a bug?theinvariant, because the hardware will do that for you. Why duplicate whatRun it under the debugger, and the debugger will open up a window and put the cursor on it <g>.hardware does?Because assert() gives us filename and line number, but "Access Violation" doesn't.
Jul 27 2004
On Tue, 27 Jul 2004 22:53:31 -0700, Walter wrote:"Derek Parnell" <derek psych.ward> wrote in message news:ce7aei$2une$1 digitaldaemon.com...Sorry, too glib. Not impressed. Why bother having assert give this info? And which "the debugger" are you referring to? -- Derek Melbourne, Australia 28/Jul/04 4:40:23 PMOn Tue, 27 Jul 2004 20:41:56 -0700, Walter wrote:part"Ant" <duitoolkit yahoo.ca> wrote in message news:pan.2004.07.28.03.06.34.780054 yahoo.ca...On Tue, 27 Jul 2004 20:02:06 -0700, Andy Friesen wrote:assert(a); is a special case in the language: it is not a boolean not-null test, it runs A's invariant to assert that 'a' is correct.I didn't know that, cheking documentation ... checked, good!Still, you would think that an assertion failure would trip, sincetheNo. assert(a) doesn't bother checking to see if a is null before callingof Object.invariant is "assert(this!==null);"so looks like a bug, smells like a bug, is it a bug?theinvariant, because the hardware will do that for you. Why duplicate whatRun it under the debugger, and the debugger will open up a window and put the cursor on it <g>.hardware does?Because assert() gives us filename and line number, but "Access Violation" doesn't.
Jul 27 2004
"Derek Parnell" <derek psych.ward> wrote in message news:ce7ijg$30vm$1 digitaldaemon.com...Violation"Because assert() gives us filename and line number, but "Accessputdoesn't.Run it under the debugger, and the debugger will open up a window andBecause debuggers don't work off of asserts.the cursor on it <g>.Sorry, too glib. Not impressed. Why bother having assert give this info?And which "the debugger" are you referring to?Most any debugger will do it. In fact, it's one of the main features of a semi-decent debugger. I can't remember any protected mode debugger that didn't do it. Debuggers will also give a stack trace, which is so useful that sometimes I'll replace the assert with a *(char*)0=0; just to run it under a debugger to get the stack trace. GPFs have an undeservedly bad rap. There's nothing inherently worse about it than an assert failure. They're really the same thing, and the GPF has the nice feature that you get such checking with 0 extra overhead (unlike asserts). The GPF does in hardware what the assert does in software, that's all.
Jul 28 2004
can't assert print the stack (if you have the frame pointer)? I mean you just need some logic that does the same thing that the debugger would do...and call that on an assert... it's useless to have an assert not throw a signal otherwise...usually the assert isn't where the problem is occuring, but n frame(s) above it. Walter wrote:"Derek Parnell" <derek psych.ward> wrote in message news:ce7ijg$30vm$1 digitaldaemon.com...Violation"Because assert() gives us filename and line number, but "Accessputdoesn't.Run it under the debugger, and the debugger will open up a window andBecause debuggers don't work off of asserts.the cursor on it <g>.Sorry, too glib. Not impressed. Why bother having assert give this info?And which "the debugger" are you referring to?Most any debugger will do it. In fact, it's one of the main features of a semi-decent debugger. I can't remember any protected mode debugger that didn't do it. Debuggers will also give a stack trace, which is so useful that sometimes I'll replace the assert with a *(char*)0=0; just to run it under a debugger to get the stack trace. GPFs have an undeservedly bad rap. There's nothing inherently worse about it than an assert failure. They're really the same thing, and the GPF has the nice feature that you get such checking with 0 extra overhead (unlike asserts). The GPF does in hardware what the assert does in software, that's all.
Jul 28 2004
"Daniel Horn" <hellcatv hotmail.com> wrote in message news:ce8nrb$es2$2 digitaldaemon.com...can't assert print the stack (if you have the frame pointer)? I mean you just need some logic that does the same thing that the debugger would do...and call that on an assert... it's useless to have an assert not throw a signal otherwise...usually the assert isn't where the problem is occuring, but n frame(s) above it.It's not so easy since the debug data needed is sometimes separate. The debugger has the debug data, and so can do a stack trace easilly. That's why I sometimes replace an assert with *(char*)0=0;.
Jul 28 2004
In article <ce7fjr$30a6$1 digitaldaemon.com>, Walter says...Run it under the debugger, and the debugger will open up a window and put the cursor on it <g>.Is it possible under linux? (I know I asked this before and nobody answer, I promiss I won't ask again) Walter sais he uses gdb but I can't convince it to show the D source (no problem with C source). Ant
Jul 28 2004
Ant wrote:In article <ce7fjr$30a6$1 digitaldaemon.com>, Walter says...I've been using gdb but I've noticed 1) the source doesn't show up - annoying but not a big deal for me since I don't have much code 2) sometimes the stack traces printed out by "bt" look pretty messed up even for simple things 3) I can't look at variables when stoppedRun it under the debugger, and the debugger will open up a window and put the cursor on it <g>.Is it possible under linux? (I know I asked this before and nobody answer, I promiss I won't ask again) Walter sais he uses gdb but I can't convince it to show the D source (no problem with C source). Ant
Jul 28 2004
In article <ce86dc$7pd$1 digitaldaemon.com>, Ben Hinkle says...I've been using gdb but I've noticed 1) the source doesn't show up - annoying but not a big deal for me since I don't have much code 2) sometimes the stack traces printed out by "bt" look pretty messed up even for simple things 3) I can't look at variables when stoppedSo, why do you use it? What can you get? (It's an honest question. not a joke) What do you get from it? I've been using it (with DDD front end) to debug the interface with C (on DUI) but it doesn't help me with D. Ant
Jul 28 2004
Ant wrote:In article <ce86dc$7pd$1 digitaldaemon.com>, Ben Hinkle says...usually the stack trace is correct. that's all I use it for.I've been using gdb but I've noticed 1) the source doesn't show up - annoying but not a big deal for me since I don't have much code 2) sometimes the stack traces printed out by "bt" look pretty messed up even for simple things 3) I can't look at variables when stoppedSo, why do you use it? What can you get? (It's an honest question. not a joke) What do you get from it?I've been using it (with DDD front end) to debug the interface with C (on DUI) but it doesn't help me with D. Ant
Jul 28 2004
On Wed, 28 Jul 2004 12:22:35 -0400, Ben Hinkle wrote:usually the stack trace is correct. that's all I use it for.thanks, Ben and Walter and guys I can see the stack! :) (finally :p) Ant
Jul 28 2004
"Ant" <Ant_member pathlink.com> wrote in message news:ce83ht$6in$1 digitaldaemon.com...In article <ce7fjr$30a6$1 digitaldaemon.com>, Walter says...again)Run it under the debugger, and the debugger will open up a window and put the cursor on it <g>.Is it possible under linux? (I know I asked this before and nobody answer, I promiss I won't askWalter sais he uses gdb but I can't convince it to show the D source (no problem with C source).That's because I've been lazy and have not gotten the debug data written out correctly in the elf format. gdb will, however, give the stack trace, and with the 'disassemble' command will show you which instruction failed, which if you turn optimization off is pretty easy to spot which line it is on.
Jul 28 2004
Dixit Derek Parnell says:On Tue, 27 Jul 2004 20:41:56 -0700, Walter wrote:Also, you can try/catch the assert if you're so inclined. NickNo. assert(a) doesn't bother checking to see if a is null before calling the invariant, because the hardware will do that for you. Why duplicate what the hardware does?Because assert() gives us filename and line number, but "Access Violation" doesn't.
Jul 28 2004
"Nick" <Nick_member pathlink.com> wrote in message news:ce8ubj$if6$1 digitaldaemon.com...Dixit Derek Parnell says:calling theOn Tue, 27 Jul 2004 20:41:56 -0700, Walter wrote:No. assert(a) doesn't bother checking to see if a is null beforewhat theinvariant, because the hardware will do that for you. Why duplicateViolation"hardware does?Because assert() gives us filename and line number, but "AccessYou can catch the access violations, too!doesn't.Also, you can try/catch the assert if you're so inclined.
Jul 28 2004
Walter wrote:Well, it doesn't seem to work for me... (using linux). Running the following just gives a segmentation fault: import std.stdio; class A {} void main() { A a; try { assert(a); } catch { writefln("catch"); } } Perhaps it's just a linux bug? NickAlso, you can try/catch the assert if you're so inclined.You can catch the access violations, too!
Jul 28 2004
Nick wrote:Walter wrote:No. The problem here is exactly the "feature" that Walter is using. Your assert is failing because of a segmentation fault, because the line is attempting to read data at address 0. A segmentation fault is caught by the operating system, not the program, an as such doesn't call under the try/catch paradigm. To catch a segfault in linux, you have to register a signal handler for that. See "man signal" or "man sigaction". I wonder if you can throw an exception inside of a signal handler, and have it caught by the failing code? Something like this: * WARNING WARNING WARNING * * I have no idea if this would work... * void main() { register_signal_handler(SIG_SEGV, &segfault_handler); A a; try { assert(a); } catch(SegFaultException e) { // whatever } } void segfault_handler() { throw new SegFaultException(); }Well, it doesn't seem to work for me... (using linux). Running the following just gives a segmentation fault: import std.stdio; class A {} void main() { A a; try { assert(a); } catch { writefln("catch"); } } Perhaps it's just a linux bug?Also, you can try/catch the assert if you're so inclined.You can catch the access violations, too!
Jul 28 2004
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:ce94kf$kti$1 digitaldaemon.com...Nick wrote:The catch will work under Windows, I just haven't implemented the linux end. I think your scheme will work.Walter wrote:No. The problem here is exactly the "feature" that Walter is using. Your assert is failing because of a segmentation fault, because the line is attempting to read data at address 0. A segmentation fault is caught by the operating system, not the program, an as such doesn't call under the try/catch paradigm. To catch a segfault in linux, you have to register a signal handler for that. See "man signal" or "man sigaction". I wonder if you can throw an exception inside of a signal handler, and have it caught by the failing code? Something like this: * WARNING WARNING WARNING * * I have no idea if this would work... * void main() { register_signal_handler(SIG_SEGV, &segfault_handler); A a; try { assert(a); } catch(SegFaultException e) { // whatever } } void segfault_handler() { throw new SegFaultException(); }Well, it doesn't seem to work for me... (using linux). Running the following just gives a segmentation fault: import std.stdio; class A {} void main() { A a; try { assert(a); } catch { writefln("catch"); } } Perhaps it's just a linux bug?Also, you can try/catch the assert if you're so inclined.You can catch the access violations, too!
Jul 28 2004
In article <ce77fg$2sh7$1 digitaldaemon.com>, Walter says..."Ant" <duitoolkit yahoo.ca> wrote in message news:pan.2004.07.28.03.06.34.780054 yahoo.ca...To give a line number and file name to the poor guy that spends hours looking at his or someone else's code? AntOn Tue, 27 Jul 2004 20:02:06 -0700, Andy Friesen wrote:No. assert(a) doesn't bother checking to see if a is null before calling the invariant, because the hardware will do that for you. Why duplicate what the hardware does?assert(a); is a special case in the language: it is not a boolean not-null test, it runs A's invariant to assert that 'a' is correct.I didn't know that, cheking documentation ... checked, good!Still, you would think that an assertion failure would trip, since part of Object.invariant is "assert(this!==null);"so looks like a bug, smells like a bug, is it a bug?
Jul 28 2004
"Ant" <Ant_member pathlink.com> wrote in message news:ce838c$6fe$1 digitaldaemon.com...In article <ce77fg$2sh7$1 digitaldaemon.com>, Walter says...theNo. assert(a) doesn't bother checking to see if a is null before callingtheinvariant, because the hardware will do that for you. Why duplicate whatThe debugger can do that for you.hardware does?To give a line number and file name to the poor guy that spends hours looking at his or someone else's code?
Jul 28 2004
On Wed, 28 Jul 2004 13:04:12 -0700, Walter <newshound digitalmars.com> wrote:"Ant" <Ant_member pathlink.com> wrote in message news:ce838c$6fe$1 digitaldaemon.com...Ok, but, now assume the piece of software is a mail server, which you have written, which is running on a large production system. It crashes due to a bug which is not reproducable due to it's specific nature, i.e. under heavy load on that specific operating system etc. You cannot use a debugger to find this bug. You could use one on a core _if_ it dropped one (it is common for systems to be configured not to drop one - this is experience talking) What you ideally want is for your application to do it's own debugging. On the event of an assert or Access Violation you catch it, and write a log file containing the file and line number, a complete stack trace, and excerpts from the various log files it writes, you notify the watching process and die. The watcher grabs the crash log, emails it to the sysadmin, and restarts the mail server. Is all that possible with D currently? I believe most of it is, I don't think I can get the __FILE__ and __LINE__ data. A nice cross platform stack trace lib would be ideal. A nice cross platform assert and access violation (plus other signals) catching lib would be ideal. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/In article <ce77fg$2sh7$1 digitaldaemon.com>, Walter says...theNo. assert(a) doesn't bother checking to see if a is null beforecallingtheinvariant, because the hardware will do that for you. Why duplicatewhatThe debugger can do that for you.hardware does?To give a line number and file name to the poor guy that spends hours looking at his or someone else's code?
Jul 28 2004
"Regan Heath" <regan netwin.co.nz> wrote in message news:opsbvck2ao5a2sq9 digitalmars.com...Yes. First of all, you can catch access violations with the catch clause (works under Windows, I haven't made it work under linux yet). Next, given the address of where it faulted, it can be compared with the line number info in the program's debug data to get the file/line. Normally, the debugger does this for you, but there's no reason one cannot do it with a specially written chunk of code that reads the debug data.Ok, but, now assume the piece of software is a mail server, which you have written, which is running on a large production system. It crashes due to a bug which is not reproducable due to it's specific nature, i.e. under heavy load on that specific operating system etc. You cannot use a debugger to find this bug. You could use one on a core _if_ it dropped one (it is common for systems to be configured not to drop one - this is experience talking) What you ideally want is for your application to do it's own debugging. On the event of an assert or Access Violation you catch it, and write a log file containing the file and line number, a complete stack trace, and excerpts from the various log files it writes, you notify the watching process and die. The watcher grabs the crash log, emails it to the sysadmin, and restarts the mail server. Is all that possible with D currently? I believe most of it is, I don't think I can get the __FILE__ and __LINE__ data.To give a line number and file name to the poor guy that spends hours looking at his or someone else's code?The debugger can do that for you.
Jul 28 2004
On Wed, 28 Jul 2004 19:33:48 -0700, Walter <newshound digitalmars.com> wrote:"Regan Heath" <regan netwin.co.nz> wrote in message news:opsbvck2ao5a2sq9 digitalmars.com...Cool. Is "access violation" == SIGSEGV Does it catch anything else as well? It would be cool if I could catch: #define SIGINT 2 /* interrupt */ #define SIGILL 4 /* illegal instruction - invalid function image */ #define SIGFPE 8 /* floating point exception */ #define SIGSEGV 11 /* segment violation */ #define SIGTERM 15 /* Software termination signal from kill */ #define SIGBREAK 21 /* Ctrl-Break sequence */ #define SIGABRT 22 /* abnormal termination triggered by abort call */ (the above are just the windows signals) If try/catch and exceptions are to be the error handling mechanism it makes sense that you can do all your error handling this way, including signals, access violations, asserts, etc.Yes. First of all, you can catch access violations with the catch clause (works under Windows, I haven't made it work under linux yet).Ok, but, now assume the piece of software is a mail server, which you have written, which is running on a large production system. It crashes due to a bug which is not reproducable due to it's specific nature, i.e. under heavy load on that specific operating system etc. You cannot use a debugger to find this bug. You could use one on a core _if_ it dropped one (it is common for systems to be configured not to drop one - this is experience talking) What you ideally want is for your application to do it's own debugging. On the event of an assert or Access Violation you catch it, and write a log file containing the file and line number, a complete stack trace, and excerpts from the various log files it writes, you notify the watching process and die. The watcher grabs the crash log, emails it to the sysadmin, and restarts the mail server. Is all that possible with D currently? I believe most of it is, I don't think I can get the __FILE__ and __LINE__ data.To give a line number and file name to the poor guy that spends hours looking at his or someone else's code?The debugger can do that for you.Next, given the address of where it faulted, it can be compared with the line number info in the program's debug data to get the file/line. Normally, the debugger does this for you, but there's no reason one cannot do it with a specially written chunk of code that reads the debug data.Great, but, I have no idea how to do that. So either: - I have to wait till someone else does it and releases it. - I have to learn how. or the third option, my favourite: - The compiler defines a 'char[] file' and 'uint line' which I can access. Why is that so hard to do? try { } catch { //access violation printf("Access Violation: %.*s:%d\n",file,line); } Regan. -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Jul 28 2004
"Regan Heath" <regan netwin.co.nz> wrote in message news:opsbvo8cpg5a2sq9 digitalmars.com...Cool. Is "access violation" == SIGSEGV Does it catch anything else as well? It would be cool if I could catch: #define SIGINT 2 /* interrupt */ #define SIGILL 4 /* illegal instruction - invalid function image */ #define SIGFPE 8 /* floating point exception */ #define SIGSEGV 11 /* segment violation */ #define SIGTERM 15 /* Software termination signal from kill*/#define SIGBREAK 21 /* Ctrl-Break sequence */ #define SIGABRT 22 /* abnormal termination triggered by abort call */ (the above are just the windows signals)Yes. If you want to see how it's done, see internal\deh.c function _d_translate_se_to_d_exception()or the third option, my favourite: - The compiler defines a 'char[] file' and 'uint line' which I canaccess.Why is that so hard to do?I always thought __FILE__ and __LINE__ are just so ugly. But when you think about it, __FILE__ and __LINE__ only really make sense for macros. Using them directly is pointless, isn't it? Wouldn't it make sense to throw a string, and then grep on that string if you can't remember where it came from? You can also simply write: assert(p != null); and not generate a seg fault.
Jul 28 2004
"Walter" <newshound digitalmars.com> wrote in message news:cea6oh$14c3$1 digitaldaemon.com..."Regan Heath" <regan netwin.co.nz> wrote in message news:opsbvo8cpg5a2sq9 digitalmars.com...functionCool. Is "access violation" == SIGSEGV Does it catch anything else as well? It would be cool if I could catch: #define SIGINT 2 /* interrupt */ #define SIGILL 4 /* illegal instruction - invalidabortimage */ #define SIGFPE 8 /* floating point exception */ #define SIGSEGV 11 /* segment violation */ #define SIGTERM 15 /* Software termination signal from kill*/#define SIGBREAK 21 /* Ctrl-Break sequence */ #define SIGABRT 22 /* abnormal termination triggered bythinkcall */ (the above are just the windows signals)Yes. If you want to see how it's done, see internal\deh.c function _d_translate_se_to_d_exception()or the third option, my favourite: - The compiler defines a 'char[] file' and 'uint line' which I canaccess.Why is that so hard to do?I always thought __FILE__ and __LINE__ are just so ugly. But when youabout it, __FILE__ and __LINE__ only really make sense for macros. Using them directly is pointless, isn't it? Wouldn't it make sense to throw a string, and then grep on that string if you can't remember where it came from?1) Sometimes the same exception message is used in multiple places, so it can be hard to track down. 2) Sometimes you don't have the source, but still need to know the culprit 3) the message itself might be manufactured (via localization/externalization) so wouldn't be found with a grep 4) it's very useful to place this information into a 'log' message, so you can easily see what produced a message witthout having to scan the source. etc. If you're concerned about exposing the __FILE__ as a symbol, is it possible to wrap it? Perhaps as an instrinsic function (like rol/ror)?
Jul 29 2004
1) Sometimes the same exception message is used in multiple places, so it can be hard to track down. 2) Sometimes you don't have the source, but still need to know the culprit 3) the message itself might be manufactured (via localization/externalization) so wouldn't be found with a grep 4) it's very useful to place this information into a 'log' message, so you can easily see what produced a message witthout having to scan the source. etc.5) dmd.exe uses __FILE__ & __LINE__ itself: I just got this message from the compiler :-) Internal error: s2ir.c 457
Jul 29 2004
"Walter" <newshound digitalmars.com> wrote in news:cea6oh$14c3$1 digitaldaemon.com:You can also simply write: assert(p != null); and not generate a seg fault.Sure it does! (I checked with DMD 0.96) You probably meant: assert(p isnot null); // ;-) Joking aside, exception stacktraces would be a boon to programmers. The pain with exceptions is that in well refactored code, exceptions are often thrown in on function, but that function is called via various code paths. So you know where the exception was thrown and where it was caught, but you don't known what happened in between. I for one, refused to use exceptions in C++ mainly for that reason. And the one time, I did use exceptions, I actually hacked the stacktrace in my code by hand and a little help from the preprocessor. The __FILE__, __LINE__ and especially __FUNCTION__ (non-standard) data is very handy for writting log files. Please, consider that log files are *very* important to some people, so they create all this information by hand if a language doesn't provide it or in Java's case cannot produce it fast enough. Farmer.
Jul 29 2004
In article <Xns9536AC639A46itsFarmer 63.105.9.61>, Farmer says...So you know where the exception was thrown and where it was caught, but you don't known what happened in between. I for one, refused to use exceptions in C++ mainly for that reason. And the one time, I did use exceptions, I actually hacked the stacktrace in my code by hand and a little help from the preprocessor.There have been articles written by very smart people on how to (in code) generate stack traces in C++ when exceptions are thrown. IIRC the conclusion was that it's just not possible to do very well. I agree that it would be nice to have compiler support for stack traces when exceptions are thrown. Sean
Jul 29 2004
Sean Kelly wrote:In article <Xns9536AC639A46itsFarmer 63.105.9.61>, Farmer says...It is possible to do a portable stack trace if you know the starting address and size of every function in the program. That is something that could be provided in a portable way by the compiler. Something like this: struct FunctionInfo { char[] name; // name would include module name, and, for nested // or literal functions, the nested function name. // Something like: // foo.bar.baz.MyFunc(int).nestedFunc1(char) char[] linkname; // this would be the C-compatible name, as it is // in the object file byte *startingAddr; size_t size; FunctionInfo[] subFunctions; // nested functions and literal functions go here }; FunctionInfo[] GetAllFunctions() {...}So you know where the exception was thrown and where it was caught, but you don't known what happened in between. I for one, refused to use exceptions in C++ mainly for that reason. And the one time, I did use exceptions, I actually hacked the stacktrace in my code by hand and a little help from the preprocessor.There have been articles written by very smart people on how to (in code) generate stack traces in C++ when exceptions are thrown. IIRC the conclusion was that it's just not possible to do very well. I agree that it would be nice to have compiler support for stack traces when exceptions are thrown.
Jul 29 2004
On Thu, 29 Jul 2004 21:48:00 -0700, Russ Lewis <spamhole-2001-07-16 deming-os.org> wrote:Sean Kelly wrote:I think some little help by the compiler would go a long way to making a stack trace nice and easy to implement. Then someone could write one, put it in phobos, and I could use it (I dont need it right now, I just know I will need it when I write commercial server software in D) Regan. -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/In article <Xns9536AC639A46itsFarmer 63.105.9.61>, Farmer says...It is possible to do a portable stack trace if you know the starting address and size of every function in the program. That is something that could be provided in a portable way by the compiler. Something like this: struct FunctionInfo { char[] name; // name would include module name, and, for nested // or literal functions, the nested function name. // Something like: // foo.bar.baz.MyFunc(int).nestedFunc1(char) char[] linkname; // this would be the C-compatible name, as it is // in the object file byte *startingAddr; size_t size; FunctionInfo[] subFunctions; // nested functions and literal functions go here }; FunctionInfo[] GetAllFunctions() {...}So you know where the exception was thrown and where it was caught, but you don't known what happened in between. I for one, refused to use exceptions in C++ mainly for that reason. And the one time, I did use exceptions, I actually hacked the stacktrace in my code by hand and a little help from the preprocessor.There have been articles written by very smart people on how to (in code) generate stack traces in C++ when exceptions are thrown. IIRC the conclusion was that it's just not possible to do very well. I agree that it would be nice to have compiler support for stack traces when exceptions are thrown.
Jul 29 2004
On Wed, 28 Jul 2004 23:43:33 -0700, Walter <newshound digitalmars.com> wrote:"Regan Heath" <regan netwin.co.nz> wrote in message news:opsbvo8cpg5a2sq9 digitalmars.com...So change the names. debug.file and debug.line are fine by me.Cool. Is "access violation" == SIGSEGV Does it catch anything else as well? It would be cool if I could catch: #define SIGINT 2 /* interrupt */ #define SIGILL 4 /* illegal instruction - invalid function image */ #define SIGFPE 8 /* floating point exception */ #define SIGSEGV 11 /* segment violation */ #define SIGTERM 15 /* Software termination signal from kill*/#define SIGBREAK 21 /* Ctrl-Break sequence */ #define SIGABRT 22 /* abnormal termination triggered by abort call */ (the above are just the windows signals)Yes. If you want to see how it's done, see internal\deh.c function _d_translate_se_to_d_exception()or the third option, my favourite: - The compiler defines a 'char[] file' and 'uint line' which I canaccess.Why is that so hard to do?I always thought __FILE__ and __LINE__ are just so ugly.But when you think about it, __FILE__ and __LINE__ only really make sense for macros. Using them directly is pointless, isn't it?No.Wouldn't it make sense to throw a string, and then grep on that string if you can't remember where it came from?Then you have to make sure all your strings aren't the same, if the same problem is thrown from several locations "Out of memory" you want the same string.You can also simply write: assert(p != null); and not generate a seg fault.Yeah, as long as I remember to check for them all time, I'd rather not have to, like you said why do this when the hardware will do it for me ;) Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Jul 29 2004
I have written some code that allows you to view & dump the current stack. My thought is that many exception types should, by default, perform this stack dump when they are created. Then, whenever they are caught, the user can implement a stack backtrace. We need to add these functions to class Thread: class Thread { ... static byte[] ViewStack() { Thread t = <getCurrentThread>; return t.ViewStack(); } byte[] ViewStack() { // swap the array indices for STACK_GROWS_UP assert(this.stackBottom > Thread.getESP()); return (cast(byte*)0)[Thread.getESP()..this.stackBottom]; } ... } I created this class. Some types of exceptions probably should not do a stack dump; others (like SegFault and AssertError) should do so. Perhaps AssertError should be a child of a class something like this: class Error_DumpsStack : Error { byte[] stackDump; this(char[] arg) { super(arg); stackDump = Thread.ViewStack().dup; } } Finally, users (or perhaps the standard D loader function?) should do this. This code requires that somebody write a function PrintStackBackTrace(byte[]): int main(char[] args) { try { ...put your main code here... } catch(Error_DumpsStack e) { PrintStackBacktrace(e.stackDump); } catch(Error e) { ...whatever... } }
Jul 29 2004
On Thu, 29 Jul 2004 17:51:36 -0700, Russ Lewis wrote:I have written some code that allows you to view & dump the current stack.50 lines of code? What are we waiting? oh, right, it took 1 year to get listdir on linux version. Walter, please, this should have been there since 0.01. Ant
Jul 29 2004
Russ Lewis wrote:I have written some code that allows you to view & dump the current stack. My thought is that many exception types should, by default,Any chance you will post it?perform this stack dump when they are created. Then, whenever they are caught, the user can implement a stack backtrace. We need to add these functions to class Thread:Why not add char[] stackDump to Exception and fill it in in the Exception construction? You should also be able to add a function printStackTrace() to Exception and all Errors will thus have the data by default.
Jul 29 2004
parabolis wrote:Russ Lewis wrote:Well, what I've posted already is the distilled core of the code. I'll post the whole program at the bottom of this message.I have written some code that allows you to view & dump the current stack. My thought is that many exception types should, by default,Any chance you will post it?Why not add char[] stackDump to Exception and fill it in in the Exception construction? You should also be able to add a function printStackTrace() to Exception and all Errors will thus have the data by default.IMHO, you shouldn't have stack trace in every Exception because some are likely to be caught and handled...and then doing a stack trace would be wasteful. Perhaps I am wrong, though. Here's the complete program. It compiles and (seems to) work on linux.import std.thread; import std.string; byte[] ViewStack(Thread t) { assert(t.stackBottom > Thread.getESP()); return (cast(byte*)0)[Thread.getESP()..t.stackBottom]; } byte[] ViewStack() { return ViewStack(Thread.getAll()[0]); } class Error_DumpsStack : Error { byte[] stackDump; this(char[] arg) { super(arg); stackDump = ViewStack().dup; } } int main() { byte[] stackView = ViewStack(); byte[] stackCopy = stackView.dup; try { throw new Error_DumpsStack("test"); } catch(Error_DumpsStack e) { printf("stackView = %d/%p stackCopy=%d/%p stackDump=%d,%p\n", stackView,stackCopy,e.stackDump); printf("cmp(...) = %d\n", cmp(cast(char[])stackView[stackView.length/2..stackView.length],cast(char[])e.stackDump[e.stackDump.length-stackView.length/2..e.stackDump.length])); } return 0; }
Jul 29 2004
On Thu, 29 Jul 2004 21:40:02 -0700, Russ Lewis <spamhole-2001-07-16 deming-os.org> wrote:parabolis wrote:I agree. If some sort of compiler support was added for this then the catch could indicate stack information was required eg. try { } catch(Exception e, Stack[] s) { } or something similar.Russ Lewis wrote:Well, what I've posted already is the distilled core of the code. I'll post the whole program at the bottom of this message.I have written some code that allows you to view & dump the current stack. My thought is that many exception types should, by default,Any chance you will post it?Why not add char[] stackDump to Exception and fill it in in the Exception construction? You should also be able to add a function printStackTrace() to Exception and all Errors will thus have the data by default.IMHO, you shouldn't have stack trace in every Exception because some are likely to be caught and handled...and then doing a stack trace would be wasteful. Perhaps I am wrong, though.Here's the complete program. It compiles and (seems to) work on linux.-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/import std.thread; import std.string; byte[] ViewStack(Thread t) { assert(t.stackBottom > Thread.getESP()); return (cast(byte*)0)[Thread.getESP()..t.stackBottom]; } byte[] ViewStack() { return ViewStack(Thread.getAll()[0]); } class Error_DumpsStack : Error { byte[] stackDump; this(char[] arg) { super(arg); stackDump = ViewStack().dup; } } int main() { byte[] stackView = ViewStack(); byte[] stackCopy = stackView.dup; try { throw new Error_DumpsStack("test"); } catch(Error_DumpsStack e) { printf("stackView = %d/%p stackCopy=%d/%p stackDump=%d,%p\n", stackView,stackCopy,e.stackDump); printf("cmp(...) = %d\n", cmp(cast(char[])stackView[stackView.length/2..stackView.length],cast(char[])e.stackDump[e.stackDump.length-stackView.length/2..e.stackDump.length])); } return 0; }
Jul 29 2004
Russ Lewis wrote:I can see your point. I am just not sure how one would catch an error thrown by, for example, source you do not control. Say std.utf's validate(). Also I was (and still do) think it might be possible without actually copying the entire stack itself. Provided that Exceptions chaining back through a program do not change ESP then it would be possible for my suggested printStackTrace() to simply start walking from ESP back to main(). However if ESP is changed while Exceptions propagate back then then your current implementation fails to display the part of the stack that actually caused the Error/Exception to be thrown. The only way to fix that is copy the entire stack for each new Error/Exception.Why not add char[] stackDump to Exception and fill it in in the Exception construction? You should also be able to add a function printStackTrace() to Exception and all Errors will thus have the data by default.IMHO, you shouldn't have stack trace in every Exception because some are likely to be caught and handled...and then doing a stack trace would be wasteful. Perhaps I am wrong, though.
Jul 30 2004
parabolis wrote:I can see your point. I am just not sure how one would catch an error thrown by, for example, source you do not control. Say std.utf's validate(). Also I was (and still do) think it might be possible without actually copying the entire stack itself. Provided that Exceptions chaining back through a program do not change ESP then it would be possible for my suggested printStackTrace() to simply start walking from ESP back to main(). However if ESP is changed while Exceptions propagate back then then your current implementation fails to display the part of the stack that actually caused the Error/Exception to be thrown. The only way to fix that is copy the entire stack for each new Error/Exception.I'm pretty sure that 'esp' is the name of the Stack Pointer register in i386. So yeah, getESP() will probably change as soon as you leave your current stack frame. Come to think of it, I've seen it change when I just declare another local variable: uint a = Thread.getESP(); uint b = Thread.getESP(); // b will be a+4, IIRC Plus, when you go back many stack frames to a catch() block and then run code there, you are overwriting old stack frames and a backtrace is impossible. I'm starting to think that the "stackDump" variable should be added to Error itself, but only some types of Error would initialize it by default. But you could add a stack dump at any time if you wanted: try { CallLibraryFunction(); } catch(Error e) { if(e.stackDump.length == 0) e.DumpStack(); }
Jul 30 2004
Russ Lewis wrote:I'm pretty sure that 'esp' is the name of the Stack Pointer register in i386. So yeah, getESP() will probably change as soon as you leave your current stack frame.Yes ESP is the stack pointer and leaving the 'stack frame' means that you either called a function (call ???) or returned from a function (ret). The call instruction pushes the current IP onto the stack and ret results in a previously pushed IP being popped so ESP is pretty much guaranteed to change. However from what I have seen D's 'stack frame' is nothing more than just the IP that is pushed during a call instruction. (I am no expert an hope any real experts will point out any errors/over simplifications I made)Come to think of it, I've seen it change when I just declare another local variable: uint a = Thread.getESP(); uint b = Thread.getESP(); // b will be a+4, IIRCUsually local variables are stored on the stack and so allocating variables is done by moving ESP to account for the amount of variable you just allocated. (Again - I am no expert an hope any real experts will point out any errors/over simplifications I made)Plus, when you go back many stack frames to a catch() block and then run code there, you are overwriting old stack frames and a backtrace is impossible.I am not yet familiar enough with D's internals to know how the try/catch/finally semantics are actually implemented.I'm starting to think that the "stackDump" variable should be added to Error itself, but only some types of Error would initialize it by default. But you could add a stack dump at any time if you wanted: try { CallLibraryFunction(); } catch(Error e) { if(e.stackDump.length == 0) e.DumpStack(); }I was writing a (rather long) post to explain why I still think my suggestion of adding a printStackTrace() function to Exception (instead of Error as Error inherits from Exception) is what you want to do. I would implement such a function by assuming the try/catch/finally implementation does not write to the stack on the way back towards main. If this is true then all you really need to know to implement printStackTrace() is what the value of ESP was when the Error/Exception was thrown. Then if a used wants a stack trace the printStackTrace() function will provide it. It has only a cost of 4 bytes additional memory for Exception/Error classes and it is a simple mov instruction to initialise it in the constructor. So this method essentially takes absolutely no time or memory to implement. Again any oversights or suggestions are requested.
Jul 30 2004
parabolis wrote:Russ Lewis wrote:As soon as your catch block calls printStackTrace(), you are creating a new stack frame that overwrites the old call stack. The moment you call printStackTrace, it becomes impossible to do a stack backtrace from the old ESP.I'm pretty sure that 'esp' is the name of the Stack Pointer register in i386. So yeah, getESP() will probably change as soon as you leave your current stack frame.Yes ESP is the stack pointer and leaving the 'stack frame' means that you either called a function (call ???) or returned from a function (ret). The call instruction pushes the current IP onto the stack and ret results in a previously pushed IP being popped so ESP is pretty much guaranteed to change. However from what I have seen D's 'stack frame' is nothing more than just the IP that is pushed during a call instruction. (I am no expert an hope any real experts will point out any errors/over simplifications I made)Come to think of it, I've seen it change when I just declare another local variable: uint a = Thread.getESP(); uint b = Thread.getESP(); // b will be a+4, IIRCUsually local variables are stored on the stack and so allocating variables is done by moving ESP to account for the amount of variable you just allocated. (Again - I am no expert an hope any real experts will point out any errors/over simplifications I made)Plus, when you go back many stack frames to a catch() block and then run code there, you are overwriting old stack frames and a backtrace is impossible.I am not yet familiar enough with D's internals to know how the try/catch/finally semantics are actually implemented.I'm starting to think that the "stackDump" variable should be added to Error itself, but only some types of Error would initialize it by default. But you could add a stack dump at any time if you wanted: try { CallLibraryFunction(); } catch(Error e) { if(e.stackDump.length == 0) e.DumpStack(); }I was writing a (rather long) post to explain why I still think my suggestion of adding a printStackTrace() function to Exception (instead of Error as Error inherits from Exception) is what you want to do. I would implement such a function by assuming the try/catch/finally implementation does not write to the stack on the way back towards main. If this is true then all you really need to know to implement printStackTrace() is what the value of ESP was when the Error/Exception was thrown. Then if a used wants a stack trace the printStackTrace() function will provide it. It has only a cost of 4 bytes additional memory for Exception/Error classes and it is a simple mov instruction to initialise it in the constructor. So this method essentially takes absolutely no time or memory to implement. Again any oversights or suggestions are requested.
Jul 30 2004
Russ Lewis wrote:As soon as your catch block calls printStackTrace(), you are creating a new stack frame that overwrites the old call stack. The moment you call printStackTrace, it becomes impossible to do a stack backtrace from the old ESP.I am assuming the ESP is already corrupt by the time you would call printStackTrace(). Thus: ================================================================ class Exception { uint esp_cache; this( char[] msg ) { asm { mov esp_cache, ESP; } esp_cache -= 2; // see note below // ... } void printStackTrace() { /* .... */ } class Error : Exception { } ================================================================ The "esp_cache -= 2" is assuming ESP reflects a value 8 bytes above the ESP before this object was created. The first is the return address and the second is the pointer passed to this(). Actually the esp_cache adjustment is more involved than just adjusting for the ESP change resulting from calling the constructor. You are going to have to walk back down the stack when subclasses are created and their constructors alter ESP before the Exception class constructor is called. The code is just to illustrate roughly how the ESP is saved and how it would be accessed in printStackTrace(). Of course you will get strange results if you keep a reference to an Exception class and start using the stack again and then finally call printStackTrace(). Also you get strange results if you just create a new Exception to have it around and then call printStackTrace(). However it may be possible to change things around to alleviate the odd cases.
Jul 30 2004
Assuming that the function "catcher" has the catch block which will catch a certain exception, the stack will look something like this: foo bar baz fred catcher <try-block> wilma barney function_with_error Error.this() <- ESP points here during Error constructor Now, when the error gets thrown, then the stack looks like this: foo bar baz fred catcher <catch-block> If you then call ANY function or create ANY local variables, then it looks like this: foo bar baz fred catcher <catch-block> printStackTrace() Notice that printStackTrace() now resides at the same place (more or less) as where the wilma function used to be. So printStackTrace() is overwriting the data from wilma! printStackTrace() is, by its very nature, corrupting the very stack that it is trying to dump. That's why, if you want to do a stack dump in a catch block, you MUST MUST MUST duplicate the stack data before actually throwing the exception. Once you've thrown your way out of a function frame, you can't know whether ANY of that frame is still valid.
Jul 30 2004
Russ Lewis wrote:If you then call ANY function or create ANY local variables, then it looks like this: foo bar baz fred catcher <catch-block> printStackTrace() Notice that printStackTrace() now resides at the same place (more or less) as where the wilma function used to be. So printStackTrace() isYes I see what you mean. However all is not lost: ================================================================ r-type fred( params ... ) { // ... try { // ... wilma() // Exception thrown // ... } catch( Exception e ) { e.printStackTrace(); } } ================================================================ This is what I consider the general case. Should this happen then (not counting the constructor issue I mentioned before) the only *write* to the stack /should/ be "call printStackTrace" which as I have will only write the return address which will be in fred. That means you can inspect all the stack variables in wilma and you can find that wilma called barney and again see all the stack variables in barney. The same goes with function_with_error. You can walk way up to the Exception constructor. Furthermore you can walk down the stack back to main. Sadly the only thing you /cannont/ do is figure out which function wilma is which is a rather important piece of information. I just found that part of the exception handling is done with src/phobos/internal/deh2.d which has some helpful looking structs in it. Given that D's exception handler has already run when you call printStackTrace() and that you can walk back up to the handler's info you might be able to add something like an array of all the return addresses on the way back down to main. With that information you would be able to get the information that is overwritten by a call to printStackTrace() and have it work as expected.
Jul 30 2004
On Fri, 30 Jul 2004 18:26:55 -0400, parabolis <parabolis softhome.net> wrote:Russ Lewis wrote:I don't agree. I think the general case is more like: void main() { try { ..entire program code goes in here.. } catch (Exception e) { ..catches any/all exceptions that are not caught and handled inside the program code.. e.printStackTrace(); } }If you then call ANY function or create ANY local variables, then it looks like this: foo bar baz fred catcher <catch-block> printStackTrace() Notice that printStackTrace() now resides at the same place (more or less) as where the wilma function used to be. So printStackTrace() isYes I see what you mean. However all is not lost: ================================================================ r-type fred( params ... ) { // ... try { // ... wilma() // Exception thrown // ... } catch( Exception e ) { e.printStackTrace(); } } ================================================================ This is what I consider the general case.Should this happen then (not counting the constructor issue I mentioned before) the only *write* to the stack /should/ be "call printStackTrace" which as I have will only write the return address which will be in fred. That means you can inspect all the stack variables in wilma and you can find that wilma called barney and again see all the stack variables in barney. The same goes with function_with_error. You can walk way up to the Exception constructor. Furthermore you can walk down the stack back to main. Sadly the only thing you /cannont/ do is figure out which function wilma is which is a rather important piece of information. I just found that part of the exception handling is done with src/phobos/internal/deh2.d which has some helpful looking structs in it. Given that D's exception handler has already run when you call printStackTrace() and that you can walk back up to the handler's info you might be able to add something like an array of all the return addresses on the way back down to main. With that information you would be able to get the information that is overwritten by a call to printStackTrace() and have it work as expected.Yes, I think actual compiler support can make this a trivial thing to implement. I was kinda hoping for the ability to say catch (Exception e, Stack s) { ..use s to output the stack where e was thrown.. } Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Jul 31 2004
Regan Heath wrote:Sorry I should have been more clear. What I meant to get across with my general case example was that printStackTrace() would be immediately inside a catch block. Your example agrees with what I was assuming the general case would be. The case where printStackStrace() might have odd performance is a case in the stack is modified before calling printStackTrace().This is what I consider the general case.I don't agree. I think the general case is more like: void main() { try { ..entire program code goes in here.. } catch (Exception e) { ..catches any/all exceptions that are not caught and handled inside the program code.. e.printStackTrace(); } }Yes, I think actual compiler support can make this a trivial thing to implement. I was kinda hoping for the ability to say catch (Exception e, Stack s) { ..use s to output the stack where e was thrown.. }That is an interesting suggestion.
Aug 01 2004
In article <ceehvn$6qm$1 digitaldaemon.com>, parabolis says...================================================================ This is what I consider the general case. Should this happen then (not counting the constructor issue I mentioned before) the only *write* to the stack /should/ be "call printStackTrace" which as I have will only write the return address which will be in fred.I think you may be forgetting that an exception (in the X86 sense, not in the D sense) could be thrown at any time. For example, an interrupt is a hardware exception, and one of these will be thrown every few milliseconds to determine whether or not a process-switch is required. When this happens, every register (and a few other things besides) are backed up onto the stack. In general, an (X86) exception handler can utilise arbitrary amounts of stack space. In summary, everything beyond the top of the stack must always be assumed to be corrupt.
Aug 01 2004
Arcane Jill wrote:I think you may be forgetting that an exception (in the X86 sense, not in the D sense) could be thrown at any time. For example, an interrupt is a hardware exception, and one of these will be thrown every few milliseconds to determine whether or not a process-switch is required. When this happens, every register (and a few other things besides) are backed up onto the stack. In general, an (X86) exception handler can utilise arbitrary amounts of stack space. In summary, everything beyond the top of the stack must always be assumed to be corrupt.I am not forgetting these process switches are thrown. I was (wrongly I take it) assuming that such contect switches would be handled by preallocating space at the bottom of the stack when a process is created explicitly for storing registers during context switches. That is exacactly the sort of information I am most thankful to hear. I will have to look into this. Thanks!
Aug 01 2004
Russ Lewis wrote:We need to add these functions to class Thread: class Thread { .... static byte[] ViewStack() { Thread t = <getCurrentThread>; return t.ViewStack(); } byte[] ViewStack() { // swap the array indices for STACK_GROWS_UP assert(this.stackBottom > Thread.getESP()); return (cast(byte*)0)[Thread.getESP()..this.stackBottom]; } .... }That is pretty slick code... Treating all of memory as an array, slicing it and then duplicating. :) However I do not understand why you need a reference to the current thread (or to change std.thread.d) to do this. Shouldn't you be able to get the current thread's ESP just by using: ================================================================ byte[] ViewStack() { uint stack_top; asm { mov stack_top, ESP; } return (cast(byte*)0)[stack_top..this.stackBottom] } ================================================================
Jul 30 2004
parabolis wrote:That is pretty slick code... Treating all of memory as an array, slicing it and then duplicating. :)I was pretty proud of it when I stumbled upon it :)However I do not understand why you need a reference to the current thread (or to change std.thread.d) to do this. Shouldn't you be able to get the current thread's ESP just by using: ================================================================ byte[] ViewStack() { uint stack_top; asm { mov stack_top, ESP; } return (cast(byte*)0)[stack_top..this.stackBottom] } ================================================================When you dump your own stack, your code is probably far better. But I have never taken the time to learn asm, so I use library functions instead. Well, I do think that you should be able to dump the stack from other threads. For instance, if you are about to die, you might want to do this: Thread.pauseAll(); foreach(Thread t; Thread.getAll()) { printf("Stack backtrace of thread %p:\n", t); PrintStackBacktrace(t.ViewStack()); } kill_program();
Jul 30 2004
Russ Lewis wrote:When you dump your own stack, your code is probably far better. But I have never taken the time to learn asm, so I use library functions instead.Yeah I kind of suspected you might not know asm. That is why I sent the code. Now your code can be fast too. :)Well, I do think that you should be able to dump the stack from other threads. For instance, if you are about to die, you might want to do this: Thread.pauseAll(); foreach(Thread t; Thread.getAll()) { printf("Stack backtrace of thread %p:\n", t); PrintStackBacktrace(t.ViewStack()); } kill_program();Sute I can see why that might be useful. You should be /absolutely/ sure nothing you do after Threa.pauseAll that results in a synchronised block being excuted however.
Jul 30 2004