[2/4] c: add #pragma GCC show_layout

Message ID 20231102131933.2161191-3-dmalcolm@redhat.com
State Unresolved
Headers
Series C/C++/diagnostics: various UX improvements |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

David Malcolm Nov. 2, 2023, 1:19 p.m. UTC
  This patch adds a new pragma to the C frontend that will
make it emit a human-readable diagram of a struct's layout.

For example, given this contrived usage:

struct example {
  char foo : 7;
  char bar;
  char visible : 1;
  char active  : 1;
};

the compiler will emit output similar to the following:

note: 'sizeof(struct example)' == 3; layout:

  ┌───────┬────┬───────────────┬─────────────────────┬─────────────────────────┬───────────────────────┐
  │Offsets│Byte│       0       │          1          │            2            │           3           │
  ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼───┬───┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
  │ Byte  │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16 │17 │18│19│20│21│22│23│24│25│26│27│28│29│30│31│
  ├───────┼────┼─┴─┴─┴─┴─┴─┴─┼─┼─┴─┴──┴──┴──┴──┴──┴──┼───┼───┼──┴──┴──┴──┴──┴──┼──┴──┴──┴──┴──┴──┴──┴──┘
  │   0   │ 0  │    'foo'    │*│        'bar'        │(1)│(2)│     padding     │
  └───────┴────┴─────────────┴─┴─────────────────────┴───┴───┴─────────────────┘
  *: padding
  (1): 'visible'
  (2): 'active'

The output is intended for humans, rather than scripts, and is
subject to change.

One wart is that it uses some analyzer internals, and thus requires
GCC to have been configured without disabling the analyzer.

Caveat: only tested on x86_64, and probably has some endianness and
packing assumptions in the testcases.

Thoughts?

gcc/analyzer/ChangeLog:
	* record-layout.cc: Define INCLUDE_ALGORITHM and
	INCLUDE_VECTOR.  Include "intl.h", "text-art/table.h",
	"text-art/widget.h", and "diagnostic-diagram.h".
	(class layout_diagram): New.
	(layout_diagram::layout_diagram): New.
	(layout_diagram::bit_to_table_coord): New.
	(layout_diagram::ensure_table_rows): New.
	(layout_diagram::get_string_for_item): New.
	(impl_show_record_layout): New.
	(show_record_layout): New.
	* record-layout.h (class layout_diagram): New forward decl.
	(class record_layout): Add friend class layout_diagram.

gcc/c-family/ChangeLog:
	* c-pragma.cc: Include "stor-layout.h".
	(class pragma_parser_show_layout): New.
	(handle_pragma_show_layout): New.
	(init_pragma): Register it.

gcc/ChangeLog:
	* doc/extend.texi (Other Pragmas): New subsection,
	with '#pragma GCC show_layout'.
	* stor-layout.h (show_record_layout): New decl.

gcc/testsuite/ChangeLog:
	* gcc.dg/parsing-pragma-show_layout.c: New test.
	* gcc.dg/pragma-show_layout-1.c: New test.
	* gcc.dg/pragma-show_layout-2.c: New test.
	* gcc.dg/pragma-show_layout-infoleak-CVE-2017-18550.c: New test.
---
 gcc/analyzer/record-layout.cc                 | 235 ++++++++++++++++++
 gcc/analyzer/record-layout.h                  |   4 +
 gcc/c-family/c-pragma.cc                      |  95 +++++++
 gcc/doc/extend.texi                           |  49 ++++
 gcc/stor-layout.h                             |   3 +
 .../gcc.dg/parsing-pragma-show_layout.c       |  15 ++
 gcc/testsuite/gcc.dg/pragma-show_layout-1.c   |  12 +
 gcc/testsuite/gcc.dg/pragma-show_layout-2.c   | 184 ++++++++++++++
 ...agma-show_layout-infoleak-CVE-2017-18550.c | 175 +++++++++++++
 9 files changed, 772 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/parsing-pragma-show_layout.c
 create mode 100644 gcc/testsuite/gcc.dg/pragma-show_layout-1.c
 create mode 100644 gcc/testsuite/gcc.dg/pragma-show_layout-2.c
 create mode 100644 gcc/testsuite/gcc.dg/pragma-show_layout-infoleak-CVE-2017-18550.c
  

Patch

diff --git a/gcc/analyzer/record-layout.cc b/gcc/analyzer/record-layout.cc
index 1369bfb5eff..242a9895309 100644
--- a/gcc/analyzer/record-layout.cc
+++ b/gcc/analyzer/record-layout.cc
@@ -19,7 +19,9 @@  along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
+#define INCLUDE_ALGORITHM
 #define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
 #include "system.h"
 #include "coretypes.h"
 #include "tree.h"
@@ -28,8 +30,13 @@  along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "diagnostic.h"
 #include "tree-diagnostic.h"
+#include "intl.h"
+#include "make-unique.h"
 #include "analyzer/analyzer.h"
 #include "analyzer/record-layout.h"
+#include "text-art/table.h"
+#include "text-art/widget.h"
+#include "diagnostic-diagram.h"
 
 #if ENABLE_ANALYZER
 
@@ -120,6 +127,234 @@  record_layout::maybe_pad_to (bit_offset_t next_offset)
     }
 }
 
+class layout_diagram : public text_art::vbox_widget
+{
+public:
+  layout_diagram (const ana::record_layout &layout,
+		  text_art::style_manager &sm,
+		  const text_art::theme &theme);
+
+private:
+  text_art::table::coord_t bit_to_table_coord (ana::bit_offset_t bit);
+
+  void ensure_table_rows (text_art::style_manager &sm,
+			  text_art::table &table,
+			  int table_y);
+
+  text_art::styled_string
+  get_string_for_item (const ana::record_layout::item &item,
+		       text_art::style_manager &sm);
+
+  std::vector<tree> m_footnote_fields;
+  bool m_has_short_padding;
+};
+
+layout_diagram::layout_diagram (const ana::record_layout &layout,
+				text_art::style_manager &sm,
+				const text_art::theme &theme)
+: m_has_short_padding (false)
+{
+  using namespace text_art;
+
+  table table (table::size_t (34, 2));
+  table.set_cell (table::coord_t (0, 0), styled_string (sm, _("Offsets")));
+  table.set_cell (table::coord_t (1, 0), styled_string (sm, _("Byte")));
+  table.set_cell (table::coord_t (0, 1), styled_string (sm, _("Byte")));
+  for (int octet = 0; octet < 4; octet++)
+    table.set_cell_span (table::rect_t (table::coord_t (2 + (octet * 8), 0),
+					table::size_t (8, 1)),
+			 styled_string::from_fmt (sm, nullptr, "%i", octet));
+  table.set_cell (table::coord_t (1, 1), styled_string (sm, _("Bit")));
+  for (int bit = 0; bit < 32; bit++)
+    table.set_cell (table::coord_t (bit + 2, 1),
+		    styled_string::from_fmt (sm, nullptr, "%i", bit));
+
+  for (auto &item : layout.m_items)
+    {
+      table::coord_t start_coord
+	= bit_to_table_coord (item.get_start_bit_offset ());
+      table::coord_t max_coord
+	= bit_to_table_coord (item.get_next_bit_offset () - 1);
+      gcc_assert (start_coord.y <= max_coord.y);
+      ensure_table_rows (sm, table, max_coord.y);
+      styled_string content (get_string_for_item (item, sm));
+      if (start_coord.y == max_coord.y)
+	{
+	  table.set_cell_span
+	    (table::rect_t (start_coord,
+			    table::size_t (max_coord.x + 1 - start_coord.x,
+					   1)),
+	     std::move (content));
+	}
+      else
+	{
+	  /* Item is split between multiple rows.  */
+	  table::range_t full_rows (start_coord.y, max_coord.y + 1);
+	  // Initial row
+	  if (start_coord.x > 2)
+	    {
+	      table.set_cell_span
+		(table::rect_t (start_coord,
+				table::size_t (34 - start_coord.x, 1)),
+		 get_string_for_item (item, sm));
+	      full_rows.start++;
+	    }
+
+	  // Final row
+	  if (max_coord.x < 33)
+	    {
+	      table.set_cell_span
+		(table::rect_t (table::coord_t (2, max_coord.y),
+				table::size_t (33 - max_coord.x, 1)),
+		 get_string_for_item (item, sm));
+	      full_rows.next--;
+	    }
+
+	  // Middle rows
+	  if (full_rows.get_size () > 0)
+	    table.set_cell_span
+	      (table::rect_t (table::range_t (2, 34),
+			      full_rows),
+	       std::move (content));
+	}
+    }
+
+  /* Add a child widget for the table.  */
+  text_art::canvas canvas (table.to_canvas (theme, sm));
+  add_child (::make_unique <canvas_widget> (std::move (canvas)));
+
+  /* Add text child widgets for any lines with showing footnotes.  */
+  if (m_has_short_padding)
+    {
+      styled_string s
+	(styled_string::from_fmt (sm, default_tree_printer,
+				  "*: %s", _("padding")));
+      add_child (::make_unique <text_widget> (std::move (s)));
+    }
+  for (int i = 0; i < (int)m_footnote_fields.size (); i++)
+    {
+      tree field = m_footnote_fields[i];
+      styled_string s (styled_string::from_fmt (sm, default_tree_printer,
+						"(%i): %qE",
+						i + 1, field));
+      add_child (::make_unique <text_widget> (std::move (s)));
+    }
+}
+
+text_art::table::coord_t
+layout_diagram::bit_to_table_coord (bit_offset_t bit)
+{
+  return text_art::table::coord_t ((bit % 32).to_shwi () + 2,
+				   (bit / 32).to_shwi () + 2);
+}
+
+void
+layout_diagram::ensure_table_rows (text_art::style_manager &sm,
+				   text_art::table &table,
+				   int table_y)
+{
+  using namespace text_art;
+
+  while (table_y >= table.get_size ().h)
+    {
+      const int word = table.get_size ().h - 2;
+      table.add_row ();
+      table.set_cell (table::coord_t (0, word + 2),
+		      styled_string::from_fmt (sm, nullptr,
+					       "%i", word * 4));
+      table.set_cell (table::coord_t (1, word + 2),
+		      styled_string::from_fmt (sm, nullptr,
+					       "%i", word * 32));
+    }
+}
+
+text_art::styled_string
+layout_diagram::get_string_for_item (const ana::record_layout::item &item,
+				     text_art::style_manager &sm)
+{
+  if (item.m_bit_range.m_size_in_bits > 1)
+    {
+      if (item.m_is_padding)
+	return text_art::styled_string (sm, _("padding"));
+      else
+	return text_art::styled_string::from_fmt
+	  (sm, default_tree_printer,
+	   "%qE", item.m_field);
+    }
+  else
+    {
+      /* To avoid bloating the table, for 1-bit items, add footnotes of the
+	 form "(1)", "(2)", ... for fields, and "*" for padding.  */
+      if (item.m_is_padding)
+	{
+	  m_has_short_padding = true;
+	  return text_art::styled_string ('*');
+	}
+      else
+	{
+	  m_footnote_fields.push_back (item.m_field);
+	  return text_art::styled_string::from_fmt
+	    (sm, nullptr, "(%i)",
+	     (int)m_footnote_fields.size ());
+	}
+    }
+}
+
+static void
+impl_show_record_layout (location_t loc,
+			 tree type,
+			 tree size)
+{
+  gcc_assert (TREE_CODE (type) == RECORD_TYPE);
+  gcc_assert (size == error_mark_node
+	      || TREE_CODE (size) == INTEGER_CST);
+
+  const text_art::theme *theme = global_dc->m_diagrams.m_theme;
+  if (!theme)
+    {
+      inform (loc, "not showing layout of %qT; %qs is %qs",
+	      type,
+	      "-fdiagnostics-text-art-charset", "none");
+      return;
+    }
+
+  /* Generate canvas.  */
+  ana::record_layout layout (type);
+  text_art::style_manager sm;
+  ana::layout_diagram diagram (layout, sm, *theme);
+  text_art::canvas canvas (diagram.to_canvas (sm));
+
+  /* Generate alt-text.  */
+  pretty_printer pp;
+  pp_format_decoder (&pp) = default_tree_printer;
+  pp_show_color (&pp) = pp_show_color (global_dc->printer);
+  pp_printf (&pp, "Diagram showing layout of %qT", type);
+
+  auto_diagnostic_group d;
+  if (size != error_mark_node)
+    inform (loc, "%<sizeof(%T)%> == %E; layout:",
+	    type, size);
+  else
+    inform (loc, "layout of %qT", type);
+  diagnostic_emit_diagram (global_dc,
+			   diagnostic_diagram (canvas,
+					       pp_formatted_text (&pp)));
+}
+
 } // namespace ana
 
 #endif /* #if ENABLE_ANALYZER  */
+
+void
+show_record_layout (location_t loc ATTRIBUTE_UNUSED,
+		    tree type ATTRIBUTE_UNUSED,
+		    tree size ATTRIBUTE_UNUSED)
+{
+  gcc_assert (TREE_CODE (type) == RECORD_TYPE);
+
+#if ENABLE_ANALYZER
+  ana::impl_show_record_layout (loc, type, size);
+#else
+  sorry_no_analyzer ();
+#endif /* #if ENABLE_ANALYZER  */
+}
diff --git a/gcc/analyzer/record-layout.h b/gcc/analyzer/record-layout.h
index b63e7b00e48..de5426dd23c 100644
--- a/gcc/analyzer/record-layout.h
+++ b/gcc/analyzer/record-layout.h
@@ -25,12 +25,16 @@  along with GCC; see the file COPYING3.  If not see
 
 namespace ana {
 
+class layout_diagram;
+
 /* Information of the layout of a RECORD_TYPE, capturing it as a vector
    of items, where each item is either a field or padding.  */
 
 class record_layout
 {
 public:
+  friend class layout_diagram;
+
   /* An item within a record; either a field, or padding after a field.  */
   struct item
   {
diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc
index 6df8683af77..904a1fcd55d 100644
--- a/gcc/c-family/c-pragma.cc
+++ b/gcc/c-family/c-pragma.cc
@@ -34,6 +34,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "opts.h"
 #include "plugin.h"
 #include "opt-suggestions.h"
+#include "stor-layout.h"
 
 label_text
 get_doc_url (const char *doc_url_suffix)
@@ -1688,6 +1689,98 @@  handle_pragma_message (cpp_reader *)
 	    TREE_STRING_POINTER (message));
 }
 
+/* Subclass of pragma_parser for use when parsing '#pragma GCC show_layout'.  */
+
+class pragma_parser_show_layout : public pragma_parser
+{
+public:
+  pragma_parser_show_layout ()
+  : pragma_parser ("GCC", "show_layout", nullptr)
+  {
+  }
+
+  bool require_id (const char *str)
+  {
+    location_t loc = UNKNOWN_LOCATION;
+    tree x = NULL_TREE;
+
+    enum cpp_ttype ttype = pragma_lex (&x, &loc);
+    if (ttype != CPP_NAME
+	|| strcmp (IDENTIFIER_POINTER (x), str))
+      {
+	warning_at (loc, OPT_Wpragmas,
+		    "ignoring malformed %<#pragma GCC show_layout%>:"
+		    " expected %qs", str);
+	return false;
+      }
+    return true;
+  }
+
+  tree require_struct_tag ()
+  {
+    location_t loc = UNKNOWN_LOCATION;
+    tree tag = NULL_TREE;
+
+    enum cpp_ttype ttype = pragma_lex (&tag, &loc);
+    if (ttype != CPP_NAME)
+      {
+	warning_at (loc, OPT_Wpragmas,
+		    "ignoring malformed %<#pragma GCC show_layout%>:"
+		    " expected struct tag");
+	return NULL_TREE;
+      }
+
+    tree type = identifier_global_tag (tag);
+    if (type == NULL_TREE)
+      {
+	warning_at (loc, OPT_Wpragmas,
+		    "ignoring malformed %<#pragma GCC show_layout%>:"
+		    " unknown struct tag %qs",
+		    IDENTIFIER_POINTER (tag));
+	return NULL_TREE;
+      }
+    if (TREE_CODE (type) != RECORD_TYPE)
+      {
+	warning_at (loc, OPT_Wpragmas,
+		    "ignoring malformed %<#pragma GCC show_layout%>:"
+		    " expected struct tag");
+	return NULL_TREE;
+      }
+
+    return type;
+  }
+};
+
+/* Handler for '#pragma GCC show_layout'.  */
+
+static void
+handle_pragma_show_layout (cpp_reader *)
+{
+  pragma_parser_show_layout p;
+
+  if (c_dialect_cxx ())
+    {
+      if (warn_unknown_pragmas > in_system_header_at (input_location))
+	warning (OPT_Wunknown_pragmas,
+		 "%<#pragma GCC show_layout%> is not supported for C++");
+      return;
+    }
+
+  if (!p.require_open_paren ())
+    return;
+  if (!p.require_id ("struct"))
+    return;
+  tree type = p.require_struct_tag ();
+  if (!type)
+    return;
+  if (!p.require_close_paren ())
+    return;
+  gcc_assert (TREE_CODE (type) == RECORD_TYPE);
+
+  tree size = c_sizeof_or_alignof_type (input_location, type, true, false, 0);
+  show_record_layout (input_location, type, size);
+}
+
 /* Ignore a no-op pragma that GCC recognizes, but which has no effect.  */
 static void
 handle_pragma_ignore (cpp_reader *)
@@ -2201,6 +2294,8 @@  init_pragma (void)
   c_register_pragma (0, "scalar_storage_order", 
 		     handle_pragma_scalar_storage_order);
 
+  c_register_pragma ("GCC", "show_layout", handle_pragma_show_layout);
+
   /* Allow plugins to register their own pragmas. */
   invoke_plugin_callbacks (PLUGIN_PRAGMAS, NULL);
 }
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index cf0d0c63cce..ea499951caf 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -24376,6 +24376,7 @@  information.
 * Push/Pop Macro Pragmas::
 * Function Specific Option Pragmas::
 * Loop-Specific Pragmas::
+* Other Pragmas::
 @end menu
 
 @node AArch64 Pragmas
@@ -25001,6 +25002,54 @@  The values of @math{0} and @math{1} block any unrolling of the loop.
 
 @end table
 
+@node Other Pragmas
+@subsection Other Pragmas
+
+@table @code
+@cindex pragma GCC show_layout
+@item #pragma GCC show_layout
+
+With this pragma, the compiler will emit a diagram showing the in-memory
+layout of a particular @code{struct}, with the relative locations and sizes
+of fields and of padding.
+
+For example, given this contrived usage:
+
+@smallexample
+struct example @{
+  char foo : 7;
+  char bar;
+  char visible : 1;
+  char active  : 1;
+@};
+#pragma GCC show_layout(struct example)
+@end smallexample
+
+the compiler will emit output similar to the following:
+
+@smallexample
+note: 'sizeof(struct example)' == 3; layout:
+
+  ┌───────┬────┬───────────────┬─────────────────────┬─────────────────────────┬───────────────────────┐
+  │Offsets│Byte│       0       │          1          │            2            │           3           │
+  ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼───┬───┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+  │ Byte  │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16 │17 │18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+  ├───────┼────┼─┴─┴─┴─┴─┴─┴─┼─┼─┴─┴──┴──┴──┴──┴──┴──┼───┼───┼──┴──┴──┴──┴──┴──┼──┴──┴──┴──┴──┴──┴──┴──┘
+  │   0   │ 0  │    'foo'    │*│        'bar'        │(1)│(2)│     padding     │
+  └───────┴────┴─────────────┴─┴─────────────────────┴───┴───┴─────────────────┘
+  *: padding
+  (1): 'visible'
+  (2): 'active'
+@end smallexample
+
+The output is intended for humans, rather than scripts, and is
+subject to change.
+
+This pragma is not available from C++.  It is also not available when GCC
+has been configured without support for the analyzer.
+
+@end table
+
 @node Unnamed Fields
 @section Unnamed Structure and Union Fields
 @cindex @code{struct}
diff --git a/gcc/stor-layout.h b/gcc/stor-layout.h
index 589ce33c950..8d8e324409f 100644
--- a/gcc/stor-layout.h
+++ b/gcc/stor-layout.h
@@ -113,4 +113,7 @@  extern void relayout_decl (tree);
    belongs to a function parameter.  */
 extern tree variable_size (tree);
 
+/* Implemented in analyzer/record-layout.cc  */
+extern void show_record_layout (location_t loc, tree type, tree size);
+
 #endif  // GCC_STOR_LAYOUT_H
diff --git a/gcc/testsuite/gcc.dg/parsing-pragma-show_layout.c b/gcc/testsuite/gcc.dg/parsing-pragma-show_layout.c
new file mode 100644
index 00000000000..564cd8ed3f9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/parsing-pragma-show_layout.c
@@ -0,0 +1,15 @@ 
+/* Test that we provide good warnings for malformed '#pragma show_layout'.  */
+
+/* { dg-do compile } */
+
+#pragma GCC show_layout  /* { dg-warning "ignoring malformed '#pragma GCC show_layout': expected '\\('" } */
+
+#pragma GCC show_layout(  /* { dg-warning "ignoring malformed '#pragma GCC show_layout': expected 'struct'" } */
+
+#pragma GCC show_layout(struct  /* { dg-warning "ignoring malformed '#pragma GCC show_layout': expected struct tag" } */
+
+#pragma GCC show_layout(struct foo  /* { dg-warning "32: ignoring malformed '#pragma GCC show_layout': unknown struct tag 'foo'" } */
+
+union not_a_struct { int placeholder; };
+
+#pragma GCC show_layout(struct not_a_struct  /* { dg-warning "32: ignoring malformed '#pragma GCC show_layout': expected struct tag" } */
diff --git a/gcc/testsuite/gcc.dg/pragma-show_layout-1.c b/gcc/testsuite/gcc.dg/pragma-show_layout-1.c
new file mode 100644
index 00000000000..db161547e9b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pragma-show_layout-1.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile } */
+
+#include <stdint.h>
+
+struct foo
+{
+  int32_t i;
+  int16_t j;
+  int32_t k;
+};
+
+#pragma GCC show_layout(struct foo) /* { dg-message "not showing layout of 'struct foo'; '-fdiagnostics-text-art-charset' is 'none'" } */
diff --git a/gcc/testsuite/gcc.dg/pragma-show_layout-2.c b/gcc/testsuite/gcc.dg/pragma-show_layout-2.c
new file mode 100644
index 00000000000..d673d4a8f83
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pragma-show_layout-2.c
@@ -0,0 +1,184 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target analyzer } */
+/* { dg-options "-fdiagnostics-text-art-charset=unicode" } */
+
+#include <stdint.h>
+
+struct empty {};
+#pragma GCC show_layout(struct empty) /* { dg-message "sizeof\\(struct empty\\)' == 0; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+  ┌───────┬────┬───────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+  │Offsets│Byte│       0       │          1          │           2           │           3           │
+  ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+  │ Byte  │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+  └───────┴────┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
+
+    { dg-end-multiline-output "" } */
+
+
+struct st_1
+{
+  int32_t i;
+  int16_t j;
+  int32_t k;
+};
+#pragma GCC show_layout(struct st_1) /* { dg-message "sizeof\\(struct st_1\\)' == 12; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+  ┌───────┬────┬───────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+  │Offsets│Byte│       0       │          1          │           2           │           3           │
+  ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+  │ Byte  │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+  ├───────┼────┼─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┤
+  │   0   │ 0  │                                         'i'                                         │
+  ├───────┼────┼─────────────────────────────────────┬───────────────────────────────────────────────┤
+  │   4   │ 32 │                 'j'                 │                    padding                    │
+  ├───────┼────┼─────────────────────────────────────┴───────────────────────────────────────────────┤
+  │   8   │ 64 │                                         'k'                                         │
+  └───────┴────┴─────────────────────────────────────────────────────────────────────────────────────┘
+
+    { dg-end-multiline-output "" } */
+
+
+struct st_2
+{
+  int16_t a;
+  char buf[40];
+};
+#pragma GCC show_layout(struct st_2) /* { dg-message "sizeof\\(struct st_2\\)' == 42; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+  ┌───────┬────┬───────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+  │Offsets│Byte│       0       │          1          │           2           │           3           │
+  ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+  │ Byte  │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+  ├───────┼────┼─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴──┴──┴──┴──┴──┴──┼──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┤
+  │   0   │ 0  │                 'a'                 │                     'buf'                     │
+  ├───────┼────┼─────────────────────────────────────┴───────────────────────────────────────────────┤
+  │   4   │ 32 │                                                                                     │
+  ├───────┼────┤                                                                                     │
+  │   8   │ 64 │                                                                                     │
+  ├───────┼────┤                                                                                     │
+  │  12   │ 96 │                                                                                     │
+  ├───────┼────┤                                                                                     │
+  │  16   │128 │                                                                                     │
+  ├───────┼────┤                                                                                     │
+  │  20   │160 │                                        'buf'                                        │
+  ├───────┼────┤                                                                                     │
+  │  24   │192 │                                                                                     │
+  ├───────┼────┤                                                                                     │
+  │  28   │224 │                                                                                     │
+  ├───────┼────┤                                                                                     │
+  │  32   │256 │                                                                                     │
+  ├───────┼────┤                                                                                     │
+  │  36   │288 │                                                                                     │
+  ├───────┼────┼─────────────────────────────────────┬───────────────────────────────────────────────┘
+  │  40   │320 │                'buf'                │
+  └───────┴────┴─────────────────────────────────────┘
+
+    { dg-end-multiline-output "" } */
+
+
+struct st_3
+{
+  int foo : 1;
+  int bar : 2;
+};
+#pragma GCC show_layout(struct st_3) /* { dg-message "sizeof\\(struct st_3\\)' == 4; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+  ┌───────┬────┬───────────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+  │Offsets│Byte│         0         │          1          │           2           │           3           │
+  ├───────┼────┼───┬──┬──┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+  │ Byte  │Bit │ 0 │1 │2 │3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+  ├───────┼────┼───┼──┴──┼─┴─┴─┴─┴─┴─┴─┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┤
+  │   0   │ 0  │(1)│'bar'│                                    padding                                    │
+  └───────┴────┴───┴─────┴───────────────────────────────────────────────────────────────────────────────┘
+  (1): 'foo'
+
+    { dg-end-multiline-output "" } */
+
+
+struct st_4
+{
+  char ch;
+};
+#pragma GCC show_layout(struct st_4) /* { dg-message "sizeof\\(struct st_4\\)' == 1; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+  ┌───────┬────┬───────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+  │Offsets│Byte│       0       │          1          │           2           │           3           │
+  ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+  │ Byte  │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+  ├───────┼────┼─┴─┴─┴─┴─┴─┴─┴─┼─┴─┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
+  │   0   │ 0  │     'ch'      │
+  └───────┴────┴───────────────┘
+
+    { dg-end-multiline-output "" } */
+
+
+struct st_5
+{
+  int foo : 7;
+  char bar;
+};
+#pragma GCC show_layout(struct st_5) /* { dg-message "sizeof\\(struct st_5\\)' == 4; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+  ┌───────┬────┬───────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+  │Offsets│Byte│       0       │          1          │           2           │           3           │
+  ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+  │ Byte  │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+  ├───────┼────┼─┴─┴─┴─┴─┴─┴─┼─┼─┴─┴──┴──┴──┴──┴──┴──┼──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┤
+  │   0   │ 0  │    'foo'    │*│        'bar'        │                    padding                    │
+  └───────┴────┴─────────────┴─┴─────────────────────┴───────────────────────────────────────────────┘
+  *: padding
+
+    { dg-end-multiline-output "" } */
+
+
+struct st_5a
+{
+  char foo : 7;
+  char bar;
+};
+#pragma GCC show_layout(struct st_5a) /* { dg-message "sizeof\\(struct st_5a\\)' == 2; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+  ┌───────┬────┬───────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+  │Offsets│Byte│       0       │          1          │           2           │           3           │
+  ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+  │ Byte  │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+  ├───────┼────┼─┴─┴─┴─┴─┴─┴─┼─┼─┴─┴──┴──┴──┴──┴──┴──┼──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
+  │   0   │ 0  │    'foo'    │*│        'bar'        │
+  └───────┴────┴─────────────┴─┴─────────────────────┘
+  *: padding
+
+    { dg-end-multiline-output "" } */
+
+
+/* Example from docs.  */
+
+struct example
+{
+  char foo : 7;
+  char bar;
+  char visible : 1;
+  char active  : 1;
+};
+#pragma GCC show_layout(struct example) /* { dg-message "sizeof\\(struct example\\)' == 3; layout:" } */
+ /* { dg-begin-multiline-output "" }
+
+  ┌───────┬────┬───────────────┬─────────────────────┬─────────────────────────┬───────────────────────┐
+  │Offsets│Byte│       0       │          1          │            2            │           3           │
+  ├───────┼────┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬──┬──┬──┬──┬──┬──┼───┬───┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+  │ Byte  │Bit │0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│16 │17 │18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+  ├───────┼────┼─┴─┴─┴─┴─┴─┴─┼─┼─┴─┴──┴──┴──┴──┴──┴──┼───┼───┼──┴──┴──┴──┴──┴──┼──┴──┴──┴──┴──┴──┴──┴──┘
+  │   0   │ 0  │    'foo'    │*│        'bar'        │(1)│(2)│     padding     │
+  └───────┴────┴─────────────┴─┴─────────────────────┴───┴───┴─────────────────┘
+  *: padding
+  (1): 'visible'
+  (2): 'active'
+
+    { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/pragma-show_layout-infoleak-CVE-2017-18550.c b/gcc/testsuite/gcc.dg/pragma-show_layout-infoleak-CVE-2017-18550.c
new file mode 100644
index 00000000000..a8434ff2fce
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pragma-show_layout-infoleak-CVE-2017-18550.c
@@ -0,0 +1,175 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target analyzer } */
+/* { dg-options "-fdiagnostics-text-art-charset=unicode" } */
+
+typedef unsigned int __u32;
+typedef unsigned int u32;
+typedef unsigned char u8;
+
+/* Adapted from Linux: drivers/scsi/aacraid/aacraid.h  */
+
+struct aac_hba_info {
+
+	u8	driver_name[50];
+	u8	adapter_number;
+	u8	system_io_bus_number;
+	u8	device_number;
+	u32	function_number;
+	u32	vendor_id;
+	u32	device_id;
+	u32	sub_vendor_id;
+	u32	sub_system_id;
+	u32	mapped_base_address_size;
+	u32	base_physical_address_high_part;
+	u32	base_physical_address_low_part;
+
+	u32	max_command_size;
+	u32	max_fib_size;
+	u32	max_scatter_gather_from_os;
+	u32	max_scatter_gather_to_fw;
+	u32	max_outstanding_fibs;
+
+	u32	queue_start_threshold;
+	u32	queue_dump_threshold;
+	u32	max_io_size_queued;
+	u32	outstanding_io;
+
+	u32	firmware_build_number;
+	u32	bios_build_number;
+	u32	driver_build_number;
+	u32	serial_number_high_part;
+	u32	serial_number_low_part;
+	u32	supported_options;
+	u32	feature_bits;
+	u32	currentnumber_ports;
+
+	u8	new_comm_interface:1;
+	u8	new_commands_supported:1;
+	u8	disable_passthrough:1;
+	u8	expose_non_dasd:1;
+	u8	queue_allowed:1;
+	u8	bled_check_enabled:1;
+	u8	reserved1:1;
+	u8	reserted2:1;
+
+	u32	reserved3[10];
+};
+
+#pragma GCC show_layout(struct aac_hba_info)  /* { dg-message "sizeof\\(struct aac_hba_info\\)' == 200; layout:" }
+ /* { dg-begin-multiline-output "" }
+
+  ┌───────┬────┬───────────────────────────────┬─────────────────────┬───────────────────────┬───────────────────────┐
+  │Offsets│Byte│               0               │          1          │           2           │           3           │
+  ├───────┼────┼───┬───┬───┬───┬───┬───┬───┬───┼─┬─┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┼──┬──┬──┬──┬──┬──┬──┬──┤
+  │ Byte  │Bit │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │8│9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│24│25│26│27│28│29│30│31│
+  ├───────┼────┼───┴───┴───┴───┴───┴───┴───┴───┴─┴─┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┤
+  │   0   │ 0  │                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │   4   │ 32 │                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │   8   │ 64 │                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  12   │ 96 │                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  16   │128 │                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  20   │160 │                                                                                                     │
+  ├───────┼────┤                                            'driver_name'                                            │
+  │  24   │192 │                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  28   │224 │                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  32   │256 │                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  36   │288 │                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  40   │320 │                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  44   │352 │                                                                                                     │
+  ├───────┼────┼─────────────────────────────────────────────────────┬───────────────────────┬───────────────────────┤
+  │  48   │384 │                    'driver_name'                    │   'adapter_number'    │'system_io_bus_number' │
+  ├───────┼────┼───────────────────────────────┬─────────────────────┴───────────────────────┴───────────────────────┤
+  │  52   │416 │        'device_number'        │                               padding                               │
+  ├───────┼────┼───────────────────────────────┴─────────────────────────────────────────────────────────────────────┤
+  │  56   │448 │                                          'function_number'                                          │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  60   │480 │                                             'vendor_id'                                             │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  64   │512 │                                             'device_id'                                             │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  68   │544 │                                           'sub_vendor_id'                                           │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  72   │576 │                                           'sub_system_id'                                           │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  76   │608 │                                     'mapped_base_address_size'                                      │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  80   │640 │                                  'base_physical_address_high_part'                                  │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  84   │672 │                                  'base_physical_address_low_part'                                   │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  88   │704 │                                         'max_command_size'                                          │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  92   │736 │                                           'max_fib_size'                                            │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  96   │768 │                                    'max_scatter_gather_from_os'                                     │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  100  │800 │                                     'max_scatter_gather_to_fw'                                      │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  104  │832 │                                       'max_outstanding_fibs'                                        │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  108  │864 │                                       'queue_start_threshold'                                       │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  112  │896 │                                       'queue_dump_threshold'                                        │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  116  │928 │                                        'max_io_size_queued'                                         │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  120  │960 │                                          'outstanding_io'                                           │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  124  │992 │                                       'firmware_build_number'                                       │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  128  │1024│                                         'bios_build_number'                                         │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  132  │1056│                                        'driver_build_number'                                        │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  136  │1088│                                      'serial_number_high_part'                                      │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  140  │1120│                                      'serial_number_low_part'                                       │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  144  │1152│                                         'supported_options'                                         │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  148  │1184│                                           'feature_bits'                                            │
+  ├───────┼────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+  │  152  │1216│                                        'currentnumber_ports'                                        │
+  ├───────┼────┼───┬───┬───┬───┬───┬───┬───┬───┬─────────────────────────────────────────────────────────────────────┤
+  │  156  │1248│(1)│(2)│(3)│(4)│(5)│(6)│(7)│(8)│                               padding                               │
+  ├───────┼────┼───┴───┴───┴───┴───┴───┴───┴───┴─────────────────────────────────────────────────────────────────────┤
+  │  160  │1280│                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  164  │1312│                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  168  │1344│                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  172  │1376│                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  176  │1408│                                                                                                     │
+  ├───────┼────┤                                             'reserved3'                                             │
+  │  180  │1440│                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  184  │1472│                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  188  │1504│                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  192  │1536│                                                                                                     │
+  ├───────┼────┤                                                                                                     │
+  │  196  │1568│                                                                                                     │
+  └───────┴────┴─────────────────────────────────────────────────────────────────────────────────────────────────────┘
+  (1): 'new_comm_interface'
+  (2): 'new_commands_supported'
+  (3): 'disable_passthrough'
+  (4): 'expose_non_dasd'
+  (5): 'queue_allowed'
+  (6): 'bled_check_enabled'
+  (7): 'reserved1'
+  (8): 'reserted2'
+
+    { dg-end-multiline-output "" } */