From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 4C5533858D37 for ; Thu, 2 Nov 2023 13:19:39 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4C5533858D37 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 4C5533858D37 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1698931190; cv=none; b=xmYJKJhRwm3FF5hNc4r5bogLYr3PWagv0YPpZItyM7xQJSGws8jPNLEIhXLYA7cfSTHjYSVlgPPfmIc7A0l+AzyRrX1NGp7iNcD+PEnMsh2TkbgswBQGFSHJB4/6EKiqs6I654hn+7bZu6/0E+Q0vqA/oCPndBFunTSgVuMtuRg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1698931190; c=relaxed/simple; bh=HlHjzMsxUQER/H/MxjoYbsHRkbu/YT5Fsm9qzOyOc0w=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=QyaO9KgmQaIFS/BpT7a4pEX8zMykm/AV/LlOlNoqLwjvZZxzKrnpUi4PQcwYc+31VKS+C6Tjo7iv2oWbwXm1Z7ke+kdXbvLF5UFwm7g7bPACxjha6qw6jJHJ4nyNAlHreRMUECERcoWoHVjpccXBvXfuYkwdQ8iPPFyp7DKsbD8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1698931178; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4430r8dKyKQGF1u5Glr35UAtcGMZrM20VB4OosoA8dU=; b=EnjHTlGladyLQ8ZFJiChpBpm7C507USqGfmNXMyTyFsUi4ggNAJ5GLODZKCtuvHYFdEm4L mBxe5S5rb6o4ZTTCinwy/mBnq2zYBl86LEerrFkxJHuQEQxGlYd1rID0oQPhQZ0XQTvMuo 83NnSxsuQAQaFVr/QqzgC5RQSxZcQnQ= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-131-Qvv3cnzbNPGUL5BoYwvHBQ-1; Thu, 02 Nov 2023 09:19:37 -0400 X-MC-Unique: Qvv3cnzbNPGUL5BoYwvHBQ-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 0FAC585A58A for ; Thu, 2 Nov 2023 13:19:37 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.22.8.62]) by smtp.corp.redhat.com (Postfix) with ESMTP id D393B1C060BA; Thu, 2 Nov 2023 13:19:36 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [PATCH 2/4] c: add #pragma GCC show_layout Date: Thu, 2 Nov 2023 09:19:31 -0400 Message-Id: <20231102131933.2161191-3-dmalcolm@redhat.com> In-Reply-To: <20231102131933.2161191-1-dmalcolm@redhat.com> References: <20231102131933.2161191-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.7 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-8.6 required=5.0 tests=BAYES_00,BODY_8BITS,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_SHORT,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,SCC_10_SHORT_WORD_LINES,SCC_20_SHORT_WORD_LINES,SCC_5_SHORT_WORD_LINES,SPF_HELO_NONE,SPF_NONE,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: 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 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 . */ #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 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 (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 (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 (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, "% == %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 + +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 + +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 "" } */ -- 2.26.3