caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* RE: Where did the exception occur?
@ 2000-10-30 15:09 Greg Morrisett
  0 siblings, 0 replies; 16+ messages in thread
From: Greg Morrisett @ 2000-10-30 15:09 UTC (permalink / raw)
  To: 'stephanh@win.tue.nl', Pierre Weis, orodeh; +Cc: caml-list

> I'm not the OP, but this can of course be implemented by having an
> additional (hidden) field in the exception which contains the source
> co-ordinate.

This is really cheap to add.  But it's not very useful in
practice.  The problem is that you call a higher order
function (e.g., find or something like that) and you really
need to know who called that function to narrow down the
context suffiently.  What you really want is a stack backtrace
hence my suggestion.  And Pierre is (rightfully) worried
about the overhead of supporting the full backtrace.

Still, it's so useful that I would highly encourage its
support.  (We've done this with our Popcorn compiler recently
in a rather naive way, and in spite of the overhead, I leave 
it on all the time because it's just so useful.)

-Greg



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Where did the exception occur?
  2000-10-30 12:12   ` David Mentré
@ 2000-11-02 17:29     ` Pierre Weis
  0 siblings, 0 replies; 16+ messages in thread
From: Pierre Weis @ 2000-11-02 17:29 UTC (permalink / raw)
  To: David Mentré; +Cc: caml-list

> Maybe a little example in the Ref. Manual or the FAQ would be useful, as
> I'm not the first one to be caught by this problem?
[...]

Let me propose this little tutorial for the debugger...

Launching the debugger:
-----------------------

Given the following obviously wrong program written in file
uncaught.ml, (the program raises an uncaught exception Not_found, when
evaluating the expression find_address "INRIA", since "IRIA" (and not
"INRIA") has been added to the list of adresses):

(* file uncaught.ml *)

let l = ref [];;

let find_address name = List.assoc name !l;;

let add_address name adress = l := (name, address) :: ! l;;

add_address "IRIA" "Rocquencourt";;

print_string (find_address "INRIA"); print_newline ();;

If you want to find where and why this exception has been raised, you
have to:

1) compile the program in debug mode:

ocamlc -g uncaught.ml

2) launch the debugger:

ocamldebug a.out

Then the debugger writes a banner and a prompt:

        Objective Caml Debugger version 3.00+14 (2000-09-06)

(ocd)

Finding the cause of a spurious exception:
------------------------------------------
Type r (for run); you get

(ocd) r
Loading program... done.
Time : 12
Program end.
Uncaught exception: Not_found
(ocd) 

Self explanatory, is'nt it ?

So, you want to step backward to set the program counter before the
time the exception is raised; hence type in b as backstep, and you get

(ocd) b
Time : 11 - pc : 15500 - module List
143     [] -> <|b|>raise Not_found

The debugger tells you that you are in module List, inside a pattern
matching on a list that allready chose the [] case and is about to
execute raise Not_found, since the program is stopped just before this
expression (as witnessed by the <|b|> mark).

But, as you know, you want the debugger to tell you which procedure
calls the one from list, and may who calls the procedure that call the
one from list; hence, you want a backtrace of the execution stack:

(ocd) bt
#0  Pc : 15500  List char 3562
#1  Pc : 19128  Uncaught char 221

So the last function called is from module List at charadcter 3562,
that is :

let rec assoc x = function
    [] -> raise Not_found
          ^
  | (a,b)::l -> if a = x then b else assoc x l

The function that calls it is in module Uncaught, file uncaught.ml char 221:
print_string (find_address "INRIA"); print_newline ();;
                                  ^
What else ?

If you're developping a program you can compile it with the -g option,
to be ready to debug it if necessary.  Hence, to find your spurious
exception you just need to type ocamldebug a.out, then r, b, and bt
gives you the backtrace.

Help and info in the debugger:
------------------------------

To get more info about the current status of the debugger you can ask
it directly at the toplevel prompt of the debugger; for instance:

(ocd) info breakpoints
No breakpoint.

(ocd) help break
  1      15396  in List, character 3539
break : Set breakpoint at specified line or function.
Syntax: break function-name
break @ [module] linenum
break @ [module] # characternum

Setting break points:
---------------------
Let's set up a breakpoint and rerun the entire program ((g)oto 0 then (r)un):

(ocd) break @Uncaught 9
Breakpoint 3 at 19112 : file Uncaught, line 9 column 34

(ocd) g 0
Time : 0
Beginning of program.

(ocd) r
Time : 6 - pc : 19112 - module Uncaught
Breakpoint : 1
9 add "IRIA" "Rocquencourt"<|a|>;;

Then, we can step and find what happens when find_address is about to
be called
(ocd) s
Time : 7 - pc : 19012 - module Uncaught
5 let find_address name = <|b|>List.assoc name !l;;

(ocd) p name
name : string = "INRIA"

(ocd) p !l
$1 : (string * string) list = ["IRIA", "Rocquencourt"]
(ocd)

Now we can guess that List.assoc will fail to find "INRIA" in the list...

Debugging under Emacs:
-----------------------
Note also that under Emacs you call the debugger using ESC-x camldebug
a.out. Then emacs will set you directly to the file and character
reported by the debugger, and you can step back and forth using ESC-b
and ESC-s, you can set up break points using CTRL-X space, and so on...

Hope this helps,

Pierre Weis

INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Where did the exception occur?
  2000-10-31 12:09 ` Mattias Waldau
@ 2000-10-31 16:52   ` Pierre Weis
  0 siblings, 0 replies; 16+ messages in thread
From: Pierre Weis @ 2000-10-31 16:52 UTC (permalink / raw)
  To: Mattias Waldau; +Cc: caml-list

> Static analysis wouldn't have help me in my case, since I know that I can
> get Not_found in 10 different places.
> 
> Of cource, I could catch each of these at their location, and raise a
> specific exception for each.
> 
> This, however, would mess up the code.
> 
> /mattias

In those 10 places add 2 lines:

try ...
with Not_found -> assert false

where ... is the old code.

You will obtain exactly the behaviour you want: the file and line will
be reported by the runtime system.

(Joking) Furthermore, your boss will be proud of you since the program will be
10 lines longer (Joking).

Best regards,

Pierre Weis

INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Where did the exception occur?
  2000-10-31 10:14 Damien Doligez
  2000-10-31 12:09 ` Mattias Waldau
@ 2000-10-31 15:27 ` CREGUT Pierre FTRD/DTL/LAN
  1 sibling, 0 replies; 16+ messages in thread
From: CREGUT Pierre FTRD/DTL/LAN @ 2000-10-31 15:27 UTC (permalink / raw)
  To: caml-list

I do not agree with you Damien

- static analysis is important but will not solve everything
    ocamlexc delivers you the perfect information but only for perfect code. 
    You have to take care of every case to catch every possible exception to 
    make ocamlexc useful. This is necessary for production code but is 
    tedious for prototyping. These are two different uses of ocaml.

- the debugger is heavy, most of the time the only thing you want is a
  backtrace of your stack as with most debuggers for most languages.
    could it be possible that you do not need to do anything when you
    raise the exception to get a stack dump ? After all, if it is uncaught, 
    nobody should have overwritten the stack between the time where the 
    exception was raised and the time where it is caught by the toplevel
    except may be the stack pointer itself that should be saved.

Another point is that exceptions as a syntaxic construct are still the dark 
side of the language, we lack constructs to express efficiently the way 
we want to deal with them :

      let x = B1 in B2
      f B1 B2

How to catch exceptions raised in B1 but not the one raised in B2 ?
Yes sure you can go back to sum types (note for jocaml users : the problem
is definitely worse with parallelism and replies).
We also need some kind of abbreviation for try ... with EX -> assert false 
for use with ocamlexc

If error handling clutters your code then this code becomes unreadable.
If you do not deal with error handling then you will have unsecure code.

Pierre Crégut

-- 
Pierre Cregut - pierre.cregut@rd.francetelecom.fr - +33 2 96 05 16 28
FTR&D - DTL/MSV - 2 avenue Pierre Marzin - 22307 Lannion Cedex - France



^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: Where did the exception occur?
  2000-10-31 10:14 Damien Doligez
@ 2000-10-31 12:09 ` Mattias Waldau
  2000-10-31 16:52   ` Pierre Weis
  2000-10-31 15:27 ` CREGUT Pierre FTRD/DTL/LAN
  1 sibling, 1 reply; 16+ messages in thread
From: Mattias Waldau @ 2000-10-31 12:09 UTC (permalink / raw)
  To: Damien Doligez, caml-list

Static analysis wouldn't have help me in my case, since I know that I can
get
Not_found in 10 different places.

Of cource, I could catch each of these at their location, and raise a
specific exception for each.

This, however, would mess up the code.

/mattias

-----Original Message-----
From: Pierre.Weis@inria.fr [mailto:Pierre.Weis@inria.fr]On Behalf Of
Damien Doligez
Sent: Tuesday, October 31, 2000 11:14 AM
To: caml-list@inria.fr
Subject: Re: Where did the exception occur?


>From: "David McClain" <dmcclain@azstarnet.com>

>I found that the location of the exception is rarely the source of
>a problem...

Indeed, this discussion started because of an uncaught "Not_found".
Most likely, this is raised by Hashtbl.find, List.assoc, or
String.index (there are a few other).  Knowing exactly which one is
unlikely to help very much.

I don't like the idea of adding run-time information just for the case
when you cannot run the debugger, especially if it incurs a lot of
overhead.  IMO, it would be more interesting to make the debugger work
for embedded code.

In the short term, static analysis seems to be the way to go.

-- Damien



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re:  Where did the exception occur?
@ 2000-10-31 10:14 Damien Doligez
  2000-10-31 12:09 ` Mattias Waldau
  2000-10-31 15:27 ` CREGUT Pierre FTRD/DTL/LAN
  0 siblings, 2 replies; 16+ messages in thread
From: Damien Doligez @ 2000-10-31 10:14 UTC (permalink / raw)
  To: caml-list

>From: "David McClain" <dmcclain@azstarnet.com>

>I found that the location of the exception is rarely the source of
>a problem...

Indeed, this discussion started because of an uncaught "Not_found".
Most likely, this is raised by Hashtbl.find, List.assoc, or
String.index (there are a few other).  Knowing exactly which one is
unlikely to help very much.

I don't like the idea of adding run-time information just for the case
when you cannot run the debugger, especially if it incurs a lot of
overhead.  IMO, it would be more interesting to make the debugger work
for embedded code.

In the short term, static analysis seems to be the way to go.

-- Damien



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Where did the exception occur?
@ 2000-10-30 15:21 David McClain
  0 siblings, 0 replies; 16+ messages in thread
From: David McClain @ 2000-10-30 15:21 UTC (permalink / raw)
  To: caml-list

Here is another one to think about... I once wrote a major program in OCaml
using CPS. This is a nightmare to traceback since every function exits by
calling another. How would a stack frame help here? You don't have infinite
memory.

- DM



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Where did the exception occur?
@ 2000-10-30 15:19 David McClain
  0 siblings, 0 replies; 16+ messages in thread
From: David McClain @ 2000-10-30 15:19 UTC (permalink / raw)
  To: caml-list

I would like to point out the folly of spending too much effort on language
design directed at displaying the location of an exception. As one who did
so, I can report that the effort was merciless, and although it does as
expected, I found that the location of the exception is rarely the source of
a problem...

Hence, I implemented an entire stack of last visited nodes to provide a
traceback. (I'm a glutton for punishment!).  This not only slows the system
down, but only offers marginal improvement to debugging.

The best way to achieve the stated goal, so far, that I have found, is to
plant a "source coordinate" in the exception itself - something you can do
manually after declaring the exception type to contain this information. But
beware! you will often halt at nonsensical places...

- D.McClain




^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: Where did the exception occur?
@ 2000-10-30 14:39 Greg Morrisett
  0 siblings, 0 replies; 16+ messages in thread
From: Greg Morrisett @ 2000-10-30 14:39 UTC (permalink / raw)
  To: 'Pierre Weis', orodeh; +Cc: caml-list

> Otherwise, the addition you mentioned is interesting, if only we could
> implement it with no penalty on the speed of exception raising. Have
> you an idea of such a compilation scheme ?

If you have a mapping from return addresses to functions,
then when raising an exception, you could walk the stack
frames and add the name of each function to a list that
gets accumulated as part of the exception packet.  This
only has overhead for exception raising, but believe me,
it's well worth it.  At the worst you could make it a compiler
option (like array bounds checks.)  

(To avoid allocating, you could pre-allocate k slots in
the exception packet and only record the first k stack
frames' function names.)

-Greg



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Where did the exception occur?
  2000-10-30  7:36 ` Pierre Weis
  2000-10-30  7:57   ` Ohad Rodeh
@ 2000-10-30 12:12   ` David Mentré
  2000-11-02 17:29     ` Pierre Weis
  1 sibling, 1 reply; 16+ messages in thread
From: David Mentré @ 2000-10-30 12:12 UTC (permalink / raw)
  To: Pierre Weis; +Cc: caml-list

Pierre Weis <Pierre.Weis@inria.fr> writes:

> However, you've got a nice replay debugger that allows you to step
> back anywhere in the past of the computation of your (bte-code)
> compiled program. So, you just have to go back to the point where the
> exception is raised and then use the usual top-level of the debugger.

About that specific point, I would say that the reference manual is not
very clear on how to use this replay feature. More precisely, how to go
to the point where the exception is raised? I was once trapped in this
unknown origin exception issue, and I did not succeed in using replay.

Maybe a little example in the Ref. Manual or the FAQ would be useful, as
I'm not the first one to be caught by this problem?

Best regards,
d.
-- 
 David.Mentre@irisa.fr -- http://www.irisa.fr/prive/dmentre/
 Opinions expressed here are only mine.



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Where did the exception occur?
  2000-10-30 11:02     ` Pierre Weis
@ 2000-10-30 11:33       ` Stephan Houben
  0 siblings, 0 replies; 16+ messages in thread
From: Stephan Houben @ 2000-10-30 11:33 UTC (permalink / raw)
  To: Pierre Weis, Ohad Rodeh; +Cc: caml-list

On Mon, 30 Oct 2000, Pierre Weis wrote:
> > List, 
> >   I'd like to point out, that my application (LARGE OCaml project) is
> > embedded in C code, so one cannot use the OCaml debugger to replay and
> > find the exception.  I'd be happy if a feature would be added to the
> > language to point out which line in the code the exception came from (I
> > understand this was added to SML ?).

> Otherwise, the addition you mentioned is interesting, if only we could
> implement it with no penalty on the speed of exception raising. Have
> you an idea of such a compilation scheme ?

I'm not the OP, but this can of course be implemented by having an
additional (hidden) field in the exception which contains the source
co-ordinate.

I'm not sure how expensive this would be. But it would be useful to have,
at least as a compiler option. I suppose raising of an exception is
expected to be slow anyway, as opposed to installing an exception
handler.

Stephan

-- 
ir. Stephan H.M.J. Houben
tel. +31-40-2474358 / +31-40-2743497
e-mail: stephanh@win.tue.nl



^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: Where did the exception occur?
@ 2000-10-30 11:20 Dave Berry
  0 siblings, 0 replies; 16+ messages in thread
From: Dave Berry @ 2000-10-30 11:20 UTC (permalink / raw)
  To: Ohad Rodeh, Pierre Weis; +Cc: Mattias Waldau, caml-list

People seem to be confusing "language" and "implementation".  MLWorks (a now
defunct implementation of SML) implemented "pop" semantics by "pushing" a
handler onto the stack, which enabled debugging of the stack from the
debugger.  (Then again, MLWorks code couldn't be called from C, so Ohad's
case couldn't arise).  Other implementations of SML may well report the line
number where the exception occurred: this is definitely a useful feature.

Dave.


-----Original Message-----
From: Ohad Rodeh [mailto:orodeh@cs.huji.ac.il]
Sent: Monday, October 30, 2000 7:57
To: Pierre Weis
Cc: Mattias Waldau; caml-list@inria.fr
Subject: Re: Where did the exception occur?


List, 
  I'd like to point out, that my application (LARGE OCaml project) is
embedded in C code, so one cannot use the OCaml debugger to replay and
find the exception.  I'd be happy if a feature would be added to the
language to point out which line in the code the exception came from (I
understand this was added to SML ?).

	Ohad.



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Where did the exception occur?
  2000-10-30  7:57   ` Ohad Rodeh
@ 2000-10-30 11:02     ` Pierre Weis
  2000-10-30 11:33       ` Stephan Houben
  0 siblings, 1 reply; 16+ messages in thread
From: Pierre Weis @ 2000-10-30 11:02 UTC (permalink / raw)
  To: Ohad Rodeh; +Cc: caml-list

> List, 
>   I'd like to point out, that my application (LARGE OCaml project) is
> embedded in C code, so one cannot use the OCaml debugger to replay and
> find the exception.  I'd be happy if a feature would be added to the
> language to point out which line in the code the exception came from (I
> understand this was added to SML ?).
> 
> 	Ohad.

Have you tried François Pessaux's spurious exceptions static analyser ?

Otherwise, the addition you mentioned is interesting, if only we could
implement it with no penalty on the speed of exception raising. Have
you an idea of such a compilation scheme ?

Pierre Weis

INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Where did the exception occur?
  2000-10-30  7:36 ` Pierre Weis
@ 2000-10-30  7:57   ` Ohad Rodeh
  2000-10-30 11:02     ` Pierre Weis
  2000-10-30 12:12   ` David Mentré
  1 sibling, 1 reply; 16+ messages in thread
From: Ohad Rodeh @ 2000-10-30  7:57 UTC (permalink / raw)
  To: Pierre Weis; +Cc: Mattias Waldau, caml-list

List, 
  I'd like to point out, that my application (LARGE OCaml project) is
embedded in C code, so one cannot use the OCaml debugger to replay and
find the exception.  I'd be happy if a feature would be added to the
language to point out which line in the code the exception came from (I
understand this was added to SML ?).

	Ohad.

On Mon, 30 Oct 2000, Pierre Weis wrote:

> > I am running my program from the top-level, and the programs aborts to the
> > toplevel ans says:
> >
> > Uncaught exception: Not_found.
> >
> > Is there a way to tell where the exception occured, for example program
> > languages like SICStus Prolog, Lisp, Visual C++, Visual Basic normally stops
> > in a top-loop at the stack frame of the error. Is there a similar feature in
> > OCaml?
> >
> > ----
> > Mattias Waldau
> 
> Some programming languages use ``pushing'' exceptions (exceptions
> that push a stack frameon the control stack then try to find a
> handler), other languages use ``poping'' exceptions (exceptions pops
> stack frames directly to the next handler). Caml uses the second kind,
> which is considered more efficient. So there is no way in Caml to
> start a new top-loop where the exception occurred.
> 
> However, you've got a nice replay debugger that allows you to step
> back anywhere in the past of the computation of your (bte-code)
> compiled program. So, you just have to go back to the point where the
> exception is raised and then use the usual top-level of the debugger.
> 
> Hope this helps,
> 
> Pierre Weis
> 
> INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/
> 
> 
> 



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Where did the exception occur?
  2000-10-29  9:59 Mattias Waldau
@ 2000-10-30  7:36 ` Pierre Weis
  2000-10-30  7:57   ` Ohad Rodeh
  2000-10-30 12:12   ` David Mentré
  0 siblings, 2 replies; 16+ messages in thread
From: Pierre Weis @ 2000-10-30  7:36 UTC (permalink / raw)
  To: Mattias Waldau; +Cc: caml-list

> I am running my program from the top-level, and the programs aborts to the
> toplevel ans says:
> 
> Uncaught exception: Not_found.
> 
> Is there a way to tell where the exception occured, for example program
> languages like SICStus Prolog, Lisp, Visual C++, Visual Basic normally stops
> in a top-loop at the stack frame of the error. Is there a similar feature in
> OCaml?
> 
> ----
> Mattias Waldau

Some programming languages use ``pushing'' exceptions (exceptions
that push a stack frame on the control stack then try to find a
handler), other languages use ``poping'' exceptions (exceptions pops
stack frames directly to the next handler). Caml uses the second kind,
which is considered more efficient. So there is no way in Caml to
start a new top-loop where the exception occurred.

However, you've got a nice replay debugger that allows you to step
back anywhere in the past of the computation of your (bte-code)
compiled program. So, you just have to go back to the point where the
exception is raised and then use the usual top-level of the debugger.

Hope this helps,

Pierre Weis

INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Where did the exception occur?
@ 2000-10-29  9:59 Mattias Waldau
  2000-10-30  7:36 ` Pierre Weis
  0 siblings, 1 reply; 16+ messages in thread
From: Mattias Waldau @ 2000-10-29  9:59 UTC (permalink / raw)
  To: Caml-List

I am running my program from the top-level, and the programs aborts to the
toplevel ans says:

Uncaught exception: Not_found.

Is there a way to tell where the exception occured, for example program
languages like SICStus Prolog, Lisp, Visual C++, Visual Basic normally stops
in a top-loop at the stack frame of the error. Is there a similar feature in
OCaml?

----
Mattias Waldau







^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2000-11-02 18:28 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-10-30 15:09 Where did the exception occur? Greg Morrisett
  -- strict thread matches above, loose matches on Subject: below --
2000-10-31 10:14 Damien Doligez
2000-10-31 12:09 ` Mattias Waldau
2000-10-31 16:52   ` Pierre Weis
2000-10-31 15:27 ` CREGUT Pierre FTRD/DTL/LAN
2000-10-30 15:21 David McClain
2000-10-30 15:19 David McClain
2000-10-30 14:39 Greg Morrisett
2000-10-30 11:20 Dave Berry
2000-10-29  9:59 Mattias Waldau
2000-10-30  7:36 ` Pierre Weis
2000-10-30  7:57   ` Ohad Rodeh
2000-10-30 11:02     ` Pierre Weis
2000-10-30 11:33       ` Stephan Houben
2000-10-30 12:12   ` David Mentré
2000-11-02 17:29     ` Pierre Weis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).