Hi!

When I've tried to backport recent LTO changes of mine, I've ran into
FAIL: g++.dg/ubsan/align-3.C   -O2 -flto -fno-use-linker-plugin 
-flto-partition=none  output pattern test
FAIL: g++.dg/ubsan/align-3.C   -O2 -flto -fuse-linker-plugin 
-fno-fat-lto-objects  output pattern test
regressions that don't for some reason show up on the trunk.

I've tracked it down to input_location_and_block being called recursively,
first on some UBSAN_NULL ifn call's location which needs to stream a BLOCK
that hasn't been streamed yet, which in turn needs to stream some locations
for the decls in the BLOCK.

Now, the problem is that both lto_output_location_1 and
input_location_and_block use static variables and/or class members to track
what the "current" location is (so that we don't stream everything all the
time), but on the writer side, lto_output_tree is pretty much the last thing
the function does, so it doesn't matter if the recursion updates those,
but on the reader side, the code relies on the stream_* static vars
and current_* class members not to change across the stream_read_tree call.

I believe we shouldn't be streaming any BLOCKs in the recursive calls,
as we only stream blocks for gimple_location, PHI locations and goto_locus.

Anyway, the following patch fixes it by forcing all those values that might
change across the call into automatic variables, so the code handles
recursion well.  The lto-streamer-out.c change is actually not strictly
necessary because BLOCKs shouldn't be streamed out, and if they would be,
it is unclear how it could be handled, because on stream in we can't set
the "current" block until it is streamed in.  So, maybe it is more correct
to leave that hunk out.

Tested so far with make check RUNTESTFLAGS=lto.exp, lto bootstrap in
progress, ok for trunk if it succeeds?  With or without the
lto-streamer-out.c change?

2020-09-10  Jakub Jelinek  <ja...@redhat.com>

        * lto-streamer-in.c (lto_location_cache::input_location_and_block):
        Don't use static variables nor class members across the
        stream_read_tree call, as it might recurse into the
        input_location_and_block method.
        * lto-streamer-out.c (lto_output_location_1): Write ob->current_block
        before calling lto_output_tree, as it might recurse into
        lto_output_location_1.

--- gcc/lto-streamer-in.c.jj    2020-09-10 14:29:17.925466837 +0200
+++ gcc/lto-streamer-in.c       2020-09-10 15:09:57.408311917 +0200
@@ -298,7 +298,29 @@ lto_location_cache::input_location_and_b
   if (column_change)
     stream_col = bp_unpack_var_len_unsigned (bp);
 
+  /* stream_read_tree below might recurse into input_location_and_block,
+     e.g. when streaming locations of the decls in the BLOCK, although it
+     shouldn't recurse with ib non-NULL.  So, avoid using the static
+     variables as well as class members across it.  */
+  const char *file = stream_file;
+  int line = stream_line;
+  int col = stream_col;
+  bool sysp = stream_sysp;
   tree block = NULL_TREE;
+  bool use_current_loc = false;
+
+  /* This optimization saves location cache operations during gimple
+     streaming.  */
+
+  if (current_file == file
+      && current_line == line
+      && current_col == col
+      && current_sysp == sysp)
+    {
+      use_current_loc = true;
+      *loc = current_loc;
+    }
+
   if (ib)
     {
       bool block_change = bp_unpack_value (bp, 1);
@@ -307,25 +329,19 @@ lto_location_cache::input_location_and_b
       block = stream_block;
     }
 
-  /* This optimization saves location cache operations during gimple
-     streaming.  */
-     
-  if (current_file == stream_file
-      && current_line == stream_line
-      && current_col == stream_col
-      && current_sysp == stream_sysp)
+  if (use_current_loc)
     {
-      if (current_block == block)
-       *loc = current_loc;
-      else if (block)
-       *loc = set_block (current_loc, block);
-      else
-       *loc = LOCATION_LOCUS (current_loc);
+      if (LOCATION_BLOCK (*loc) != block)
+       {
+         if (block)
+           *loc = set_block (*loc, block);
+         else
+           *loc = LOCATION_LOCUS (*loc);
+       }
       return;
     }
 
-  struct cached_location entry
-    = {stream_file, loc, stream_line, stream_col, stream_sysp, block};
+  struct cached_location entry = { file, loc, line, col, sysp, block };
   loc_cache.safe_push (entry);
 }
 
--- gcc/lto-streamer-out.c.jj   2020-09-10 14:29:17.939466635 +0200
+++ gcc/lto-streamer-out.c      2020-09-10 15:12:00.948535171 +0200
@@ -231,8 +231,12 @@ lto_output_location_1 (struct output_blo
       bp_pack_value (bp, ob->current_block != block, 1);
       streamer_write_bitpack (bp);
       if (ob->current_block != block)
-       lto_output_tree (ob, block, true, true);
-      ob->current_block = block;
+       {
+         ob->current_block = block;
+         /* lto_output_tree might recurse into lto_output_location_1,
+            so update ob->current_block before calling it.  */
+         lto_output_tree (ob, block, true, true);
+       }
     }
 }
 


        Jakub

Reply via email to