July 28, 2004
"Nick" <Nick_member@pathlink.com> wrote in message news:ce8ubj$if6$1@digitaldaemon.com...
> Dixit Derek Parnell says:
>
> >On Tue, 27 Jul 2004 20:41:56 -0700, Walter 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?
> >
> >Because assert() gives us filename and line number, but "Access
Violation"
> >doesn't.
>
> Also, you can try/catch the assert if you're so inclined.

You can catch the access violations, too!


July 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...
> >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?
>
> 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.


July 28, 2004
Walter wrote:
>>Also, you can try/catch the assert if you're so inclined.
> 
> You can catch the access violations, too!

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?

Nick

July 28, 2004
Nick wrote:
> Walter wrote:
> 
>>> Also, you can try/catch the assert if you're so inclined.
>>
>> You can catch the access violations, too!
> 
> 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?

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();
}

July 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...
>> In article <ce77fg$2sh7$1@digitaldaemon.com>, Walter says...
>> >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?
>>
>> 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.

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/
July 29, 2004
"Russ Lewis" <spamhole-2001-07-16@deming-os.org> wrote in message news:ce94kf$kti$1@digitaldaemon.com...
> Nick wrote:
> > Walter wrote:
> >
> >>> Also, you can try/catch the assert if you're so inclined.
> >>
> >> You can catch the access violations, too!
> >
> > 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?
>
> 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();
> }

The catch will work under Windows, I just haven't implemented the linux end. I think your scheme will work.


July 29, 2004
"Regan Heath" <regan@netwin.co.nz> wrote in message news:opsbvck2ao5a2sq9@digitalmars.com...
> >> 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.
>
> 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.

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.


July 29, 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...
>> >> 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.
>>
>> 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.
>
> 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).

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.

> 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/
July 29, 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

July 29, 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 can
access.
>
> 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.