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 flambda -03, perhaps related to lazy values #7301

Closed
vicuna opened this issue Jul 21, 2016 · 4 comments

Comments

Projects
None yet
2 participants
@vicuna
Copy link

commented Jul 21, 2016

Original bug ID: 7301
Reporter: @alainfrisch
Assigned to: @mshinwell
Status: closed (set by @xavierleroy on 2017-09-24T15:33:14Z)
Resolution: fixed
Priority: normal
Severity: crash
Fixed in version: 4.04.0 +dev / +beta1 / +beta2
Category: back end (clambda to assembly)
Related to: #7292
Monitored by: braibant

Bug description

The following program compiled with flambda -O3 segfaults:

let foo () =
  (fun xs0 () -> Lazy.force (List.hd xs0) ())
    (List.map (fun g -> lazy g)
       [Lazy.force (  lazy ( let _ = () in fun () -> ()  ) )]
    )

let () =
  let gen = foo () in
  gen ();
  Gc.compact ();
  print_char 'A'; flush stdout;
  gen ()
@vicuna

This comment has been minimized.

Copy link
Author

commented Jul 22, 2016

Comment author: @alainfrisch

Looking at the cmm code (generated with "-O3 -inline 0", after wrapping the
code in include(struct ... end : sig end) to simplify a bit):

(function camlBug__entry ()
 (store val(init) "camlBug__gen_124"
   (let
     (Pmakeblock_227/1308
        (alloc{./bug.ml:9,12-18;./bug.ml:5,27-58}
          block-hdr(1270){./bug.ml:9,12-18;./bug.ml:5,27-58}
          "camlBug__anon-fn[./bug.ml:5,27--58]_11_closure")
      Pmakeblock_arg_231/1310
        (if (and Pmakeblock_227/1308 1) Pmakeblock_227/1308
          (catch
            (let
              switcher/1345 (load unsigned int8 (+a Pmakeblock_227/1308 -8))
              (if (!= switcher/1345 246)
                (if (!= switcher/1345 250) (exit 5)
                  (load val Pmakeblock_227/1308))
                (app{./bug.ml:9,12-18;./bug.ml:5,8-60}
                  "camlCamlinternalLazy__force_lazy_block_32"
                  Pmakeblock_227/1308 val)))
          with(5) Pmakeblock_227/1308))
      Pmakeblock_268/1313
        (alloc{./bug.ml:9,12-18;./bug.ml:4,4-99;list.ml:59,20-23;./bug.ml:4,29-30}
          block-hdr(1274){./bug.ml:9,12-18;./bug.ml:4,4-99;list.ml:59,20-23;./bug.ml:4,29-30}
          Pmakeblock_arg_231/1310)
      Pmakeblock_arg_265/1315
        (app{./bug.ml:9,12-18;./bug.ml:4,4-99;list.ml:59,32-39}
          "camlList__map_274" "camlBug__anon-fn[./bug.ml:4,14--31]_5_closure"
          1a val)
      Pmakeblock_266/1316
        (alloc{./bug.ml:9,12-18;./bug.ml:4,4-99;list.ml:59,27-39}
          block-hdr(2048){./bug.ml:9,12-18;./bug.ml:4,4-99;list.ml:59,27-39}
          Pmakeblock_268/1313 Pmakeblock_arg_265/1315)
      set_of_closures_240/1317
        (alloc block-hdr(3319)
          "camlBug__anon-fn[./bug.ml:3,2--45]_partial_fun_237" 3
          Pmakeblock_266/1316))
     set_of_closures_240/1317))
 (let
   fun/1344
     (load val (load val (load val (+a (load val "camlBug__gen_124") 16))))
   (app{./bug.ml:10,2-8;./bug.ml:3,2-145;./bug.ml:3,17-44}
     (load val fun/1344) 1a fun/1344 unit))
 (extcall "caml_gc_compaction"{./bug.ml:11,2-15} 1a unit)
 (extcall "caml_ml_output_char"{./bug.ml:12,2-16;pervasives.ml:447,19-39}
   (load val "camlPervasives__Pccall_1585") 131 unit)
 (extcall "caml_ml_flush"{./bug.ml:12,18-30;pervasives.ml:308,0-54}
   (load val (+a "camlPervasives" 184)) unit)
 (let
   fun/1343
     (load val (load val (load val (+a (load val "camlBug__gen_124") 16))))
   (app{./bug.ml:13,2-8;./bug.ml:3,2-145;./bug.ml:3,17-44}
     (load val fun/1343) 1a fun/1343 unit))
 1a)

[Pmakeblock_266/1316] points to the list containing a single element,
[Pmakeblock_268/1313], which is initially a forward block (header 1274
-> tag 250) pointing to [Pmakeblock_arg_231/1310]. This corresponds
to the result of [List.map] in the program.

The global symbol [camlBug__gen_124] then points to a closure with
this list in its environment.

Then, the code does:

 (let
   fun/1343
     (load val (load val (load val (+a (load val "camlBug__gen_124") 16))))

This value is obtained by extracting the value from the closure
(i.e. [Pmakeblock_266/1316]), projecting to its first field, which is
[Pmakeblock_268/1313], and then projecting again to its first field.
This is meant to traverse the forward block. But of course, once the
GC has done its shortcutting job, [Pmakeblock_268/1313] is no longer a
forward block.

This seems to be the result of inlining the first [Lazy.force], assuming
wrongly that the argument has an immutable tag.

Does flambda understand that the tag of lazy values can change?

@vicuna

This comment has been minimized.

Copy link
Author

commented Jul 22, 2016

Comment author: @alainfrisch

Does flambda understand that the tag of lazy values can change?

That might be the problem. The case for simplifying the Switch in inline_and_simplify.ml sees a Value_block approximation, but there does not seem any logic to prevent simplifying when the tag is a forward pointer.

@vicuna

This comment has been minimized.

Copy link
Author

commented Jul 25, 2016

Comment author: @mshinwell

I will look at this

@vicuna

This comment has been minimized.

Copy link
Author

commented Jul 25, 2016

Comment author: @mshinwell

Please see #713

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.