Bug 84502 - [8 Regression] Argument corruption when passing empty templated struct
Summary: [8 Regression] Argument corruption when passing empty templated struct
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 8.0.1
: P1 normal
Target Milestone: 8.0
Assignee: Not yet assigned to anyone
URL:
Keywords: ABI, wrong-code
Depends on:
Blocks:
 
Reported: 2018-02-21 16:13 UTC by patrick.schlangen
Modified: 2018-02-22 08:39 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work: 7.3.0
Known to fail: 8.0.1
Last reconfirmed: 2018-02-21 00:00:00


Attachments
Minimal example (239 bytes, text/x-csrc)
2018-02-21 16:13 UTC, patrick.schlangen
Details

Note You need to log in before you can comment on or make changes to this bug.
Description patrick.schlangen 2018-02-21 16:13:58 UTC
Created attachment 43483 [details]
Minimal example

Hi,

we've discovered a strange problem when passing many function arguments where one argument is an alias (using = ...) for a templated struct which has no members (e.g. std::integer_sequence).

When building in non-optimized mode or with -O1/-O2, all arguments starting from argument #7 seem to be corrupt. Building with -O3 seems to solve the issue.

I've attached a small example program.

Correct output:
---------------

$ ~/gcc-8/bin/g++ -O3 -o repro repro.cpp && ./repro
0, 1, 2, 3, 4, 5, 6, 7


Wrong outputs:
--------------

$ ~/gcc-8/bin/g++ -O2 -o repro repro.cpp && ./repro
0, 1, 2, 3, 4, 5, 7, 0

$ ~/gcc-8/bin/g++ -O1 -o repro repro.cpp && ./repro
0, 1, 2, 3, 4, 5, 7, 0

$ ~/gcc-8/bin/g++ -O0 -o repro repro.cpp && ./repro
0, 1, 2, 3, 4, 5, 7, 2088590376


gcc version (freshly built):
----------------------------

$ ~/gcc-8/bin/g++ -v
Using built-in specs.
COLLECT_GCC=/home/patrick/gcc-8/bin/g++
COLLECT_LTO_WRAPPER=/home/patrick/gcc-8/libexec/gcc/x86_64-pc-linux-gnu/8.0.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ./configure --prefix=/home/patrick/gcc-8 --disable-multilib
Thread model: posix
gcc version 8.0.1 20180218 (experimental) (GCC) 

Best Regards

Patrick
Comment 1 patrick.schlangen 2018-02-21 16:33:33 UTC
Note: This problem does not happen with gcc 7.2.1.

The problem can also be reproduced with -O3 when the empty struct object passed to the function is actually used in the function. (So it is not optimized out.)
Comment 2 Jonathan Wakely 2018-02-21 17:09:38 UTC
This is caused by -fabi-version=12 (which is the default for GCC 8). You can get the old handling of empty structs with -fabi-version=11

The bug only seems to happen when the empty struct is a class template.

Reduced, this fails at -O0 but not any other optimization level, or with -fabi-version=11:

template<typename T>
struct EmptyTemplatedStruct { };

using X = EmptyTemplatedStruct<int>;

void func(X, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8)
{
  if (a1 != 0)
    __builtin_abort();
  if (a2 != 1)
    __builtin_abort();
  if (a3 != 2)
    __builtin_abort();
  if (a4 != 3)
    __builtin_abort();
  if (a5 != 4)
    __builtin_abort();
  if (a6 != 5)
    __builtin_abort();
  if (a7 != 6)
    __builtin_abort();
  if (a8 != 7)
    __builtin_abort();
}

int main()
{
  func(X{}, 0, 1, 2, 3, 4, 5, 6, 7);
}
Comment 3 Marek Polacek 2018-02-21 17:35:21 UTC
This might be the reason why building Chromium gn fails (I hope).  Related: PR84286
Comment 4 Jonathan Wakely 2018-02-21 18:17:39 UTC
Regressed with r255066
Comment 5 Jakub Jelinek 2018-02-21 20:47:00 UTC
Completely untested fix:

--- gcc/stor-layout.c.jj	2018-02-13 21:23:29.187981310 +0100
+++ gcc/stor-layout.c	2018-02-21 21:43:24.783522853 +0100
@@ -1883,6 +1883,9 @@ finalize_type_size (tree type)
       && TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
     TYPE_SIZE_UNIT (type) = variable_size (TYPE_SIZE_UNIT (type));
 
+  /* Handle empty records as per the x86-64 psABI.  */
+  TYPE_EMPTY_P (type) = targetm.calls.empty_record_p (type);
+
   /* Also layout any other variants of the type.  */
   if (TYPE_NEXT_VARIANT (type)
       || type != TYPE_MAIN_VARIANT (type))
@@ -1895,6 +1898,7 @@ finalize_type_size (tree type)
       unsigned int precision = TYPE_PRECISION (type);
       unsigned int user_align = TYPE_USER_ALIGN (type);
       machine_mode mode = TYPE_MODE (type);
+      bool empty_p = TYPE_EMPTY_P (type);
 
       /* Copy it into all variants.  */
       for (variant = TYPE_MAIN_VARIANT (type);
@@ -1911,11 +1915,9 @@ finalize_type_size (tree type)
 	  SET_TYPE_ALIGN (variant, valign);
 	  TYPE_PRECISION (variant) = precision;
 	  SET_TYPE_MODE (variant, mode);
+	  TYPE_EMPTY_P (variant) = empty_p;
 	}
     }
-
-  /* Handle empty records as per the x86-64 psABI.  */
-  TYPE_EMPTY_P (type) = targetm.calls.empty_record_p (type);
 }
 
 /* Return a new underlying object for a bitfield started with FIELD.  */
Comment 6 patrick.schlangen 2018-02-21 21:45:47 UTC
(In reply to Jakub Jelinek from comment #5)
> Completely untested fix:

I've applied the patch and it seems to resolve the issue.
Thanks a lot!
Comment 7 Jakub Jelinek 2018-02-22 08:30:28 UTC
Author: jakub
Date: Thu Feb 22 08:29:56 2018
New Revision: 257892

URL: https://gcc.gnu.org/viewcvs?rev=257892&root=gcc&view=rev
Log:
	PR target/84502
	* stor-layout.c (finalize_type_size): Propagate TYPE_EMPTY_P flag
	to all type variants.

	* g++.dg/torture/pr84502.C: New test.

Added:
    trunk/gcc/testsuite/g++.dg/torture/pr84502.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/stor-layout.c
    trunk/gcc/testsuite/ChangeLog
Comment 8 Jakub Jelinek 2018-02-22 08:39:24 UTC
Fixed.