Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segfault with installed custom printer in ocamldebug #9214

Closed
Rehan-MALAK opened this issue Dec 27, 2019 · 11 comments · Fixed by #10709
Closed

Segfault with installed custom printer in ocamldebug #9214

Rehan-MALAK opened this issue Dec 27, 2019 · 11 comments · Fixed by #10709

Comments

@Rehan-MALAK
Copy link

Rehan-MALAK commented Dec 27, 2019

Dear all,
I am currently unable to use a custom installed printer with ocamldebug in my project because of this segfault.

mytype.ml

type mytype = unit -> unit

a.ml

let () =
  let f : Mytype.mytype = fun _ -> () in
  ()

p.ml

let print_mytype fmt (f : Mytype.mytype) =
  let _ = f () in (* let _ = f () makes ocamldebug segfault ? *)
  Format.fprintf fmt "(installed printer) !"

Ocamldebug script

set program a
br @ a 3
run
print f
load_printer p.cmo
install_printer P.print_mytype
print f

Commands

ocamlc -g -bin-annot -o mytype.cmo -c mytype.ml
ocamlc -g -bin-annot -o a.cmo -c a.ml
ocamlc -g -bin-annot -o p.cmo -c p.ml
ocamlc -g -bin-annot -o a mytype.cmo a.cmo
ocamldebug ./a << EOF
so script
EOF

Wanted behaviour (if you remove let _ = f () for example) :

(ocd) Loading program... done.
Breakpoint 1 at 0:10532: file a.ml, line 3, characters 3-5
Time: 12 - pc: 0:10532 - module A
Breakpoint: 1
3   <|b|>()
f: Mytype.mytype = <fun>
File p.cmo loaded
f: Mytype.mytype = (installed printer) !
(ocd) Removed breakpoint 1 at 0:10532: file a.ml, line 3, characters 3-5

Actual behaviour with trunk c5e875d or 4.09.0

(ocd) Loading program... done.
Breakpoint 1 at 0:10532: file a.ml, line 3, characters 3-5
Time: 12 - pc: 0:10532 - module A
Breakpoint: 1
3   <|b|>()
f: Mytype.mytype = <fun>
File p.cmo loaded
Fatal error: exception End_of_file
Segmentation fault

Any idea ?

@Rehan-MALAK
Copy link
Author

As far I understand :

  • ''load_printer'' is essentially just a call to Dynlink.load_file
  • ''install_printer'' a call to Dynlink.unsafe_get_global_value + some Obj magic cast to a function

but inside ocamldebug memory, not in the target program.

I got confused because :

  1. With ocaml toplevel, one can do :

a.ml

let f = function () -> 4

p.ml

let print_mytype (f : unit -> int) =
  let n = f () in (* in ocaml toplevel, this is not problematic *)
  Format.printf "installed printer : this is the constant function to %d" n
$ ocamlc -c p.ml
$ ocaml
        OCaml version 4.09.0

Cannot find file topfind.
# #use "a.ml";;	
val f : unit -> int = <fun>
# f;;
- : unit -> int = <fun>
# #load "p.cmo";;
# #install_printer P.print_mytype;;
# f;;
- : unit -> int = installed printer : this is the constant function to 4
  1. I am used to gdb where one can call C functions of the target program but this turns out to be a nice non-trivial feature explained for example here https://jvns.ca/blog/2018/01/04/how-does-gdb-call-functions/
  • Stop the process
  • Create a new stack frame (far away from the actual stack)
  • Save all the registers
  • Set the registers to the arguments you want to call your function with
  • Set the stack pointer to the new stack frame
  • Put a trap instruction somewhere in memory
  • Set the return address to that trap instruction
  • Set the instruction pointer register to the address of the function you want to call
  • Start the process again!

@jahierwan
Copy link

I've been bitten by this one too...

@Rehan-MALAK
Copy link
Author

I don't know what one should do here. Maybe this should be tagged as "feature-wish" : ability to run code from ocamldebug. It would provide best of both worlds :
-toplevel : run code
-ocamdebug : breakpoint in a big project
I remember reading somewhere that it was impossible (maybe because of the GC), but I can't say what he/she meant by impossible (not possible or too much work ?).

Comments from runtime experts welcome !

@jahierwan
Copy link

jahierwan commented Feb 7, 2020

My wish is more modest. I just want to able to print, in ocamldebug, structures that have at least a field that is a function, event if this function is not used by the loaded and installed printer (which causes the core dump as your example illustrates).

I other words, even if the printer does not try to use the function (as you'd like to do if I understand correctly), I have no way to print the structure using the other fields.

Hence I don't see it as a "feature-wish", but as a "ocamldebug-bug".

@Rehan-MALAK
Copy link
Author

Hi ! I up this question :
"calling code from ocamldebug in the target debugged program memory" is impossible (because of the GC or something else?) or too-much work to implement ?
If it was possible, it would enable the possibility to run the pretty-printers of the targeted programs during an ocamldebug session
(I have in mind the type terms of an assistant prover).

@github-actions
Copy link

This issue has been open one year with no activity. Consequently, it is being marked with the "stale" label. What this means is that the issue will be automatically closed in 30 days unless more comments are added or the "stale" label is removed. Comments that provide new information on the issue are especially welcome: is it still reproducible? did it appear in other contexts? how critical is it? etc.

@github-actions github-actions bot added the Stale label Oct 18, 2021
xavierleroy added a commit to xavierleroy/ocaml that referenced this issue Oct 18, 2021
In debugger mode, closures sent by the debuggee have their code pointer
modified so that it points to the `function_placeholder` code in
debugger/main.ml.

This modification was performed incorrectly: the whole closure for
`function_placeholder` was used as the code pointer for the
unmarshalled closure.

This commit implements the correct operation: the code pointer from
`function_placeholder` is used as code pointer for the unmarshaled
closure.

Fixes: ocaml#9214
xavierleroy added a commit to xavierleroy/ocaml that referenced this issue Oct 18, 2021
In debugger mode, closures sent by the debuggee have their code pointer
modified so that it points to the `function_placeholder` code in
debugger/main.ml.

This modification was performed incorrectly: the whole closure for
`function_placeholder` was used as the code pointer for the
unmarshalled closure.

This commit implements the correct operation: the code pointer from
`function_placeholder` is used as code pointer for the unmarshaled
closure.

Fixes: ocaml#9214
@xavierleroy
Copy link
Contributor

Plausible fix in #10709.

@xavierleroy xavierleroy added bug and removed Stale labels Oct 18, 2021
@jahierwan
Copy link

Excellent! Thanks Xavier.

@Rehan-MALAK
Copy link
Author

With xavierleroy@ab9588c patch, one gets

$ ocamldebug ./a
        OCaml Debugger version 4.14.0+dev0-2021-06-03

(ocd) so script
Loading program... done.
Breakpoint 1 at 0:11240: file a.ml, line 3, characters 3-5
Time: 16 - pc: 0:11240 - module A
Breakpoint: 1
3   <|b|>()
f: Mytype.mytype = <fun>
File p.cmo loaded
f: Mytype.mytype =
  <printer P.print_mytype raised an exception: Failure("custom printer tried to invoke a function from the debuggee")>
(ocd) 

without quitting the ocamldebug session.

Thanks @xavierleroy

@Rehan-MALAK
Copy link
Author

Hi ! I up this question : "calling code from ocamldebug in the target debugged program memory" is impossible (because of the GC or something else?) or too-much work to implement ? If it was possible, it would enable the possibility to run the pretty-printers of the targeted programs during an ocamldebug session (I have in mind the type terms of an assistant prover).

😄

xavierleroy added a commit that referenced this issue Oct 19, 2021
In debugger mode, closures sent by the debuggee have their code pointer
modified so that it points to the `function_placeholder` code in
debugger/main.ml.

This modification was performed incorrectly: the whole closure for
`function_placeholder` was used as the code pointer for the
unmarshalled closure.

This commit implements the correct operation: the code pointer from
`function_placeholder` is used as code pointer for the unmarshaled
closure.

Also: raise a more informative exception when custom printer invokes
closure from debuggee.

Fixes: #9214
@xavierleroy
Copy link
Contributor

Hi ! I up this question : "calling code from ocamldebug in the target debugged program memory" is impossible (because of the GC or something else?) or too-much work to implement ?

Not impossible but a lot of work to implement, as far as I can see.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants