From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-f52.google.com (mail-wr1-f52.google.com [209.85.221.52]) by sourceware.org (Postfix) with ESMTPS id 26FC5384B124 for ; Fri, 24 Jun 2022 18:15:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 26FC5384B124 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=palves.net Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-wr1-f52.google.com with SMTP id v14so4166586wra.5 for ; Fri, 24 Jun 2022 11:15:07 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:date:mime-version:user-agent:subject :content-language:to:references:from:in-reply-to :content-transfer-encoding; bh=vNJWLmuhKWX+frjOVrIo4kJlvshm1G8pyzEvmLXC7SA=; b=hqUUT4WUw/K6cRZXR5kee+hYqq+pjWICtQF5SdcOQ0+4LvzpsRIbtCwo1Fbi21Vvpx C1BPC00SS4/UMhCFwmLoFbuksxiaRkZxY6p3Ypp3s1NUCu/1VfuC2YfL7F8JbDZ0g7us hqkQyf19OfnVeUF/YIrHFH/+d3mDZBYjKo8mtkhY6KILiA2uHZikGwet/2A580Yt2iOk W+ApLCyRPfJIJ6zA2t91bNU8gktLf6WIp4/068cfpbidHBRPqB50rCNC411/k4wzI3zm qPpY2XJwxXlg4kRx4E3X91+Rx6luT2yv5ggkbMWvkJeTwF4/j0HlKF4pQr3ryx69pCXT 93pA== X-Gm-Message-State: AJIora8ggKlWqIjPuslZl/44yrj+aJcrm2azZuk59FxV+YAsoNqtLCsL 0FpPGbVH2mXxpUz96gtfdvqG4LYugXg= X-Google-Smtp-Source: AGRyM1tizLaNppx0pn9j7NbVeJNz/46PDCSgQjtrIyYr2duygKBoMhDr2IyqZJs7e21tSE04JPSj2Q== X-Received: by 2002:adf:f503:0:b0:21a:3d9c:b355 with SMTP id q3-20020adff503000000b0021a3d9cb355mr362147wro.623.1656094505966; Fri, 24 Jun 2022 11:15:05 -0700 (PDT) Received: from ?IPV6:2001:8a0:f924:2600:209d:85e2:409e:8726? ([2001:8a0:f924:2600:209d:85e2:409e:8726]) by smtp.gmail.com with ESMTPSA id a17-20020adffb91000000b0020c5253d907sm2995208wrr.83.2022.06.24.11.15.04 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 24 Jun 2022 11:15:05 -0700 (PDT) Message-ID: Date: Fri, 24 Jun 2022 19:15:04 +0100 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.10.0 Subject: Re: [PATCHv3 5/6] gdb: ensure the cast in gdbarch_tdep is valid Content-Language: en-US To: Andrew Burgess , gdb-patches@sourceware.org References: From: Pedro Alves In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 24 Jun 2022 18:15:09 -0000 On 2022-06-13 17:15, Andrew Burgess via Gdb-patches wrote: > This commit builds on the previous commit and modifies the > gdbarch_tdep function to ensure that the cast being performed is > valid. > > To do this I make use of dynamic_cast to ensure that the generic > gdbarch_tdep pointer that we have is of the correct type. > > The only problem with this approach is that, in order to use > dynamic_cast, we need RTTI information, which requires the class to > have a vtable, which currently, is not something the various tdep > classes have. > > And so, in this commit, I add a virtual destructor to the gdbarch_tdep > class. > > With this change I can now add an assert in the gdbarch_tdep function. > > Obviously, this change comes at a cost, creation of the tdep classes > is now slightly more expensive (due to vtable initialisation), > however, this only happens when a new gdbarch is created, which is not > that frequent, so I don't see that as a huge concern. > ... > Then, there is an increased cost each time the tdep is accessed. This > is much more frequent, but I don't believe the cost is excessive (a > vtable pointer comparison), at least, no worse than many of our other > asserts. I don't think that's true. dynamic_cast does not really do a vtable pointer comparison. It does pointer arithmetic/adjustment, walks the vtables to find the type info for each type in the hierarchy, and compares the type's type info objects, which usually mean string-comparing the class names. Only some systems can do pointer comparisons to compare types. See e.g.: https://github.com/gcc-mirror/gcc/blob/bb8e93eb1acae30a5fbe7e13149493ce4ccd301a/libstdc%2B%2B-v3/libsupc%2B%2B/typeinfo#L52 See the benchmark I posted in this previous response to Tromey: https://sourceware.org/pipermail/gdb-patches/2022-April/188102.html Maybe we should revisit Tromey's idea of a new cast "operator", but make it static_cast in release mode? This patch that I posted today adds a DEVELOPMENT macro symbol to common-config.h, we can make use of that: https://sourceware.org/pipermail/gdb-patches/2022-June/190301.html Also, dynamic_cast lets you try to cast to completely unrelated types (undefined behavior instead of compile error), while to me is seems better to make it fail to compile. Like: template T * checked_dyn_cast (V *v) { /* dynamic_cast compiles even if V and T are completely unrelated. This assert prevent that, only letting you do downcasts, and casts to same type. */ static_assert (std::is_base_of::value || std::is_base_of::value, "types must be related"); /* Check for polymorphism explicitly in case we're in release mode. */ static_assert (std::is_polymorphic::value, "types must be polymorphic"); #ifdef DEVELOPMENT T *result = dynamic_cast (v); assert (result != nullptr); #else T *result = static_cast (v); #endif return result; } With that, this compiles & works as expected: struct A { virtual ~A() {} }; struct B : A {}; struct C {}; void func () { A *a = new A(); B *b = new B(); C *c = new C(); // these work checked_dyn_cast (a); checked_dyn_cast (a); checked_dyn_cast (b); checked_dyn_cast (a); // while these fail the static assertions. // checked_dyn_cast (a); // checked_dyn_cast (c); // checked_dyn_cast (123); } Anyhow, this can always be done after your patch, I don't mean to suggest we should do this before. Other than the nit in the commit log, the patch LGTM.