public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Fix C++ cast of derived class to base class
@ 2022-04-02 16:15 Tom Tromey
  2022-04-18 15:34 ` Tom Tromey
  0 siblings, 1 reply; 4+ messages in thread
From: Tom Tromey @ 2022-04-02 16:15 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

PR c++/28907 points out that casting from a derived class to a base
class fails in some situations.  The problem turned out to be a
missing use of value_embedded_offset.  One peculiarity here is that,
if you managed to construct a pointer-to-derived with an embedded
offset of 0, the cast would work -- for example, one of the two new
tests here passes without the patch.

This embedded offset stuff is an endless source of bugs.  I wonder if
it's possible to get rid of it somehow.

Regression tested on x86-64 Fedora 34.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28907
---
 gdb/testsuite/gdb.cp/casts.cc  | 20 ++++++++++++++++++++
 gdb/testsuite/gdb.cp/casts.exp |  6 ++++++
 gdb/valops.c                   |  2 +-
 3 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/gdb/testsuite/gdb.cp/casts.cc b/gdb/testsuite/gdb.cp/casts.cc
index 543db896d3d..ea4dc961793 100644
--- a/gdb/testsuite/gdb.cp/casts.cc
+++ b/gdb/testsuite/gdb.cp/casts.cc
@@ -34,6 +34,20 @@ struct DoublyDerived : public VirtuallyDerived,
 {
 };
 
+struct Left
+{
+  int left;
+};
+
+struct Right
+{
+  int right;
+};
+
+struct LeftRight : public Left, public Right
+{
+};
+
 int
 main (int argc, char **argv)
 {
@@ -48,5 +62,11 @@ main (int argc, char **argv)
   Alpha *ad = &derived;
   Alpha *add = &doublyderived;
 
+  LeftRight gd;
+  gd.left = 23;
+  gd.right = 27;
+  unsigned long long gd_value = (unsigned long long) &gd;
+  unsigned long long r_value = (unsigned long long) (Right *) &gd;
+
   return 0;  /* breakpoint spot: casts.exp: 1 */
 }
diff --git a/gdb/testsuite/gdb.cp/casts.exp b/gdb/testsuite/gdb.cp/casts.exp
index cda870f77a4..5d0a52401a8 100644
--- a/gdb/testsuite/gdb.cp/casts.exp
+++ b/gdb/testsuite/gdb.cp/casts.exp
@@ -174,6 +174,12 @@ gdb_test "print dynamic_cast<Gamma *> (add)" \
     " = \\(Gamma \\*\\) $nonzero_hex" \
     "dynamic_cast to sibling"
 
+gdb_test "print (unsigned long long) &gd == gd_value" " = true"
+gdb_test "print (unsigned long long) (LeftRight *) (Right *) &gd == gd_value" \
+    " = true"
+gdb_test "print (unsigned long long) (LeftRight *) (Right *) r_value == gd_value" \
+    " = true"
+
 if {[prepare_for_testing "failed to prepare" ${testfile}03 $srcfile2 \
 			 {debug c++ additional_flags=-std=c++03}]} {
     return -1
diff --git a/gdb/valops.c b/gdb/valops.c
index 75d52b495be..9a3a9b9567c 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -274,7 +274,7 @@ value_cast_structs (struct type *type, struct value *v2)
       if (v)
 	{
 	  /* Downcasting is possible (t1 is superclass of v2).  */
-	  CORE_ADDR addr2 = value_address (v2);
+	  CORE_ADDR addr2 = value_address (v2) + value_embedded_offset (v2);
 
 	  addr2 -= value_address (v) + value_embedded_offset (v);
 	  return value_at (type, addr2);
-- 
2.34.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Fix C++ cast of derived class to base class
  2022-04-02 16:15 [PATCH] Fix C++ cast of derived class to base class Tom Tromey
@ 2022-04-18 15:34 ` Tom Tromey
  2022-05-04 17:27   ` Tom de Vries
  0 siblings, 1 reply; 4+ messages in thread
From: Tom Tromey @ 2022-04-18 15:34 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

>>>>> "Tom" == Tom Tromey <tom@tromey.com> writes:

Tom> PR c++/28907 points out that casting from a derived class to a base
Tom> class fails in some situations.  The problem turned out to be a
Tom> missing use of value_embedded_offset.  One peculiarity here is that,
Tom> if you managed to construct a pointer-to-derived with an embedded
Tom> offset of 0, the cast would work -- for example, one of the two new
Tom> tests here passes without the patch.

I'm checking this in now.

Tom

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Fix C++ cast of derived class to base class
  2022-04-18 15:34 ` Tom Tromey
@ 2022-05-04 17:27   ` Tom de Vries
  2022-05-08 17:40     ` [committed][gdb/testsuite] Fix gdb.cp/casts.exp with -m32 Tom de Vries
  0 siblings, 1 reply; 4+ messages in thread
From: Tom de Vries @ 2022-05-04 17:27 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 4/18/22 17:34, Tom Tromey wrote:
>>>>>> "Tom" == Tom Tromey <tom@tromey.com> writes:
> 
> Tom> PR c++/28907 points out that casting from a derived class to a base
> Tom> class fails in some situations.  The problem turned out to be a
> Tom> missing use of value_embedded_offset.  One peculiarity here is that,
> Tom> if you managed to construct a pointer-to-derived with an embedded
> Tom> offset of 0, the cast would work -- for example, one of the two new
> Tom> tests here passes without the patch.
> 
> I'm checking this in now.

The added tests fail with target board unix/-m32.

In more detail, with some additional printing:
...
(gdb) print /x &gd^M
$31 = 0xffffc5c8^M
(gdb) PASS: gdb.cp/casts.exp: print /x &gd
print /x (unsigned long long)&gd^M
$32 = 0xffffc5c8^M
(gdb) PASS: gdb.cp/casts.exp: print /x (unsigned long long)&gd
print /x gd_value^M
$33 = 0xffffffffffffc5c8^M
(gdb) PASS: gdb.cp/casts.exp: print /x gd_value
print (unsigned long long) &gd == gd_value^M
$34 = false^M
(gdb) FAIL: gdb.cp/casts.exp: print (unsigned long long) &gd == gd_value
...

This fixes it:
...
diff --git a/gdb/testsuite/gdb.cp/casts.cc b/gdb/testsuite/gdb.cp/casts.cc
index ea4dc961793..f64d13c26df 100644
--- a/gdb/testsuite/gdb.cp/casts.cc
+++ b/gdb/testsuite/gdb.cp/casts.cc
@@ -1,3 +1,5 @@
+#include <cstdint>
+
  struct A
  {
    int a;
@@ -65,7 +67,7 @@ main (int argc, char **argv)
    LeftRight gd;
    gd.left = 23;
    gd.right = 27;
-  unsigned long long gd_value = (unsigned long long) &gd;
+  unsigned long long gd_value = (unsigned long long) (std::uintptr_t)&gd;
    unsigned long long r_value = (unsigned long long) (Right *) &gd;

    return 0;  /* breakpoint spot: casts.exp: 1 */
...

WDYT?

Thanks,
- Tom

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [committed][gdb/testsuite] Fix gdb.cp/casts.exp with -m32
  2022-05-04 17:27   ` Tom de Vries
@ 2022-05-08 17:40     ` Tom de Vries
  0 siblings, 0 replies; 4+ messages in thread
From: Tom de Vries @ 2022-05-08 17:40 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1966 bytes --]

[ was: [PATCH] Fix C++ cast of derived class to base class ]

On 5/4/22 19:27, Tom de Vries via Gdb-patches wrote:
> On 4/18/22 17:34, Tom Tromey wrote:
>>>>>>> "Tom" == Tom Tromey <tom@tromey.com> writes:
>>
>> Tom> PR c++/28907 points out that casting from a derived class to a base
>> Tom> class fails in some situations.  The problem turned out to be a
>> Tom> missing use of value_embedded_offset.  One peculiarity here is that,
>> Tom> if you managed to construct a pointer-to-derived with an embedded
>> Tom> offset of 0, the cast would work -- for example, one of the two new
>> Tom> tests here passes without the patch.
>>
>> I'm checking this in now.
> 
> The added tests fail with target board unix/-m32.
> 
> In more detail, with some additional printing:
> ...
> (gdb) print /x &gd^M
> $31 = 0xffffc5c8^M
> (gdb) PASS: gdb.cp/casts.exp: print /x &gd
> print /x (unsigned long long)&gd^M
> $32 = 0xffffc5c8^M
> (gdb) PASS: gdb.cp/casts.exp: print /x (unsigned long long)&gd
> print /x gd_value^M
> $33 = 0xffffffffffffc5c8^M
> (gdb) PASS: gdb.cp/casts.exp: print /x gd_value
> print (unsigned long long) &gd == gd_value^M
> $34 = false^M
> (gdb) FAIL: gdb.cp/casts.exp: print (unsigned long long) &gd == gd_value
> ...
> 
> This fixes it:
> ...
> diff --git a/gdb/testsuite/gdb.cp/casts.cc b/gdb/testsuite/gdb.cp/casts.cc
> index ea4dc961793..f64d13c26df 100644
> --- a/gdb/testsuite/gdb.cp/casts.cc
> +++ b/gdb/testsuite/gdb.cp/casts.cc
> @@ -1,3 +1,5 @@
> +#include <cstdint>
> +
>   struct A
>   {
>     int a;
> @@ -65,7 +67,7 @@ main (int argc, char **argv)
>     LeftRight gd;
>     gd.left = 23;
>     gd.right = 27;
> -  unsigned long long gd_value = (unsigned long long) &gd;
> +  unsigned long long gd_value = (unsigned long long) (std::uintptr_t)&gd;
>     unsigned long long r_value = (unsigned long long) (Right *) &gd;
> 
>     return 0;  /* breakpoint spot: casts.exp: 1 */
> ...
> 
> WDYT?
> 

Committed.

Thanks,
- Tom

[-- Attachment #2: 0001-gdb-testsuite-Fix-gdb.cp-casts.exp-with-m32.patch --]
[-- Type: text/x-patch, Size: 1803 bytes --]

[gdb/testsuite] Fix gdb.cp/casts.exp with -m32

When running test-case gdb.cp/casts.exp with target board unix/-m32, I run
into:
...
(gdb) print (unsigned long long) &gd == gd_value^M
$31 = false^M
(gdb) FAIL: gdb.cp/casts.exp: print (unsigned long long) &gd == gd_value
...

With some additional printing, we can see in more detail why the comparison
fails:
...
(gdb) print /x &gd^M
$31 = 0xffffc5c8^M
(gdb) PASS: gdb.cp/casts.exp: print /x &gd
print /x (unsigned long long)&gd^M
$32 = 0xffffc5c8^M
(gdb) PASS: gdb.cp/casts.exp: print /x (unsigned long long)&gd
print /x gd_value^M
$33 = 0xffffffffffffc5c8^M
(gdb) PASS: gdb.cp/casts.exp: print /x gd_value
print (unsigned long long) &gd == gd_value^M
$34 = false^M
(gdb) FAIL: gdb.cp/casts.exp: print (unsigned long long) &gd == gd_value
...

The gd_value is set by this assignment:
...
  unsigned long long gd_value = (unsigned long long) &gd;
...

The problem here is directly casting from a pointer to a non-pointer-sized
integer.

Fix this by adding an intermediate cast to std::uintptr_t.

Tested on x86_64-linux with native and target board unix/-m32.

---
 gdb/testsuite/gdb.cp/casts.cc | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gdb/testsuite/gdb.cp/casts.cc b/gdb/testsuite/gdb.cp/casts.cc
index ea4dc961793..f64d13c26df 100644
--- a/gdb/testsuite/gdb.cp/casts.cc
+++ b/gdb/testsuite/gdb.cp/casts.cc
@@ -1,3 +1,5 @@
+#include <cstdint>
+
 struct A
 {
   int a;
@@ -65,7 +67,7 @@ main (int argc, char **argv)
   LeftRight gd;
   gd.left = 23;
   gd.right = 27;
-  unsigned long long gd_value = (unsigned long long) &gd;
+  unsigned long long gd_value = (unsigned long long) (std::uintptr_t)&gd;
   unsigned long long r_value = (unsigned long long) (Right *) &gd;
 
   return 0;  /* breakpoint spot: casts.exp: 1 */

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-05-08 17:40 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-02 16:15 [PATCH] Fix C++ cast of derived class to base class Tom Tromey
2022-04-18 15:34 ` Tom Tromey
2022-05-04 17:27   ` Tom de Vries
2022-05-08 17:40     ` [committed][gdb/testsuite] Fix gdb.cp/casts.exp with -m32 Tom de Vries

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).