Fix gdb.base/whatis-ptype-typedefs.exp on 32-bit archs

The gdb.base/whatis-ptype-typedefs.exp testcase has several tests that
fail on 32-bit architectures.  E.g., on 'x86-64 -m32', I see:

 ...
 FAIL: gdb.base/whatis-ptype-typedefs.exp: lang=c: cast: whatis (float_typedef) v_uchar_array_t_struct_typedef (invalid)
 FAIL: gdb.base/whatis-ptype-typedefs.exp: lang=c: cast: ptype (float_typedef) v_uchar_array_t_struct_typedef (invalid)
 ...

gdb.log:

 (gdb) whatis (float_typedef) v_uchar_array_t_struct_typedef
 type = float_typedef
 (gdb) FAIL: gdb.base/whatis-ptype-typedefs.exp: lang=c: cast: whatis (float_typedef) v_uchar_array_t_struct_typedef (invalid)

As Simon explained [1], the issue boils down to the fact that on
64-bit, this is an invalid cast:

 (gdb) p (float_typedef) v_uchar_array_t_struct_typedef
 Invalid cast.

while on 32 bits it is valid:

 (gdb) p (float_typedef) v_uchar_array_t_struct_typedef
 $1 = 1.16251721e-41

The expression basically tries to cast an array (which decays to a
pointer) to a float.  The cast works on 32 bits because a float and a
pointer are of the same size, and value_cast works in that case:

~~~
   More general than a C cast: accepts any two types of the same length,
   and if ARG2 is an lvalue it can be cast into anything at all.  */
~~~

On 64 bits, they are not the same size, so it ends throwing the
"Invalid cast" error.

The testcase is expecting the invalid cast behavior, thus the FAILs.

A point of these tests was to cover as many code paths in value_cast
as possible, as a sort of documentation of the current behavior:

    # The main idea here is testing all the different paths in the
    # value casting code in GDB (value_cast), making sure typedefs are
    # preserved.
...
    # We try all combinations, even those that don't parse, or are
    # invalid, to catch the case of a regression making them
    # inadvertently valid.  For example, these convertions are
    # invalid:
...

In that spirit, this commit makes the testcase adjust itself depending
on size of floats and pointers, and also test floats of different
sizes.

Passes cleanly on x86-64 GNU/Linux both -m64/-m32.

[1] - https://sourceware.org/ml/gdb-patches/2017-11/msg00382.html

gdb/ChangeLog:
2017-11-20  Pedro Alves  <palves@redhat.com>

	* gdb.base/whatis-ptype-typedefs.c (double_typedef)
	(long_double_typedef): New typedefs.
	Use DEF on double and long double.
	* gdb.base/whatis-ptype-typedefs.exp: Add double and long double
	cases.
	(run_tests): New 'float_ptr_same_size', 'double_ptr_same_size',
	and 'long_double_ptr_same_size' locals.  Use them to decide
	whether cast from array/function to float is valid/invalid.
This commit is contained in:
Pedro Alves 2017-11-20 23:03:17 +00:00
parent b77db948f4
commit 73fcf6418d
3 changed files with 57 additions and 3 deletions

View file

@ -1,3 +1,14 @@
2017-11-20 Pedro Alves <palves@redhat.com>
* gdb.base/whatis-ptype-typedefs.c (double_typedef)
(long_double_typedef): New typedefs.
Use DEF on double and long double.
* gdb.base/whatis-ptype-typedefs.exp: Add double and long double
cases.
(run_tests): New 'float_ptr_same_size', 'double_ptr_same_size',
and 'long_double_ptr_same_size' locals. Use them to decide
whether cast from array/function to float is valid/invalid.
2017-11-17 Tom Tromey <tom@tromey.com>
* gdb.rust/traits.rs: New file.

View file

@ -56,6 +56,16 @@ DEF (int);
typedef float float_typedef;
DEF (float);
/* Double floats. */
typedef double double_typedef;
DEF (double);
/* Long doubles. */
typedef long double long_double_typedef;
DEF (long_double);
/* Enums. */
typedef enum colors {red, green, blue} colors_typedef;

View file

@ -92,6 +92,16 @@ set table {
{"v_float_typedef" "float_typedef" "float"}
{"v_float_typedef2" "float_typedef2" "float"}
{"double_typedef" "double" "double"}
{"double_typedef2" "double_typedef" "double"}
{"v_double_typedef" "double_typedef" "double"}
{"v_double_typedef2" "double_typedef2" "double"}
{"long_double_typedef" "long double" "long double"}
{"long_double_typedef2" "long_double_typedef" "long double"}
{"v_long_double_typedef" "long_double_typedef" "long double"}
{"v_long_double_typedef2" "long_double_typedef2" "long double"}
{"colors_typedef" "(enum )?colors" "enum colors( : unsigned int)? {red, green, blue}"}
{"colors_typedef2" "colors_typedef" "enum colors( : unsigned int)? {red, green, blue}"}
{"v_colors_typedef" "colors_typedef" "enum colors( : unsigned int)? {red, green, blue}"}
@ -199,6 +209,22 @@ proc run_tests {lang} {
}
}
# If floats and pointers have the same size on this architecture,
# then casting from array/function to float works, because
# arrays/functions first decay to pointers, and then GDB's cast is
# more general than a C cast and accepts any two types of the same
# length.
set float_ptr_same_size \
[get_integer_valueof "sizeof (float) == sizeof (void *)" -1]
# Ditto double.
set double_ptr_same_size \
[get_integer_valueof "sizeof (double) == sizeof (void *)" -1]
# Ditto long double.
set long_double_ptr_same_size \
[get_integer_valueof "sizeof (long double) == sizeof (void *)" -1]
# Test converting/casting all variables in the first column of the
# table to all types (found in the first column of the table).
# The aggregates are all defined to be the same size so that
@ -230,7 +256,7 @@ proc run_tests {lang} {
# regression making them inadvertently valid. For
# example, these convertions are invalid:
#
# float <-> array
# float <-> array [iff sizeof pointer != sizeof float]
# array -> function (not function pointer)
# array -> member_ptr
#
@ -247,8 +273,15 @@ proc run_tests {lang} {
gdb_test "whatis ($to) $from" "syntax error.*" "whatis ($to) $from (syntax)"
gdb_test "ptype ($to) $from" "syntax error.*" "ptype ($to) $from (syntax)"
} elseif {([string match "*float*" $from] && [string match "*array*" $to])
|| ([string match "float*" $to] && [string match "*array*" $from])
|| ([string match "float*" $to] && [string match "*method" $from])
|| (!$float_ptr_same_size
&& ([string match "float*" $to] && [string match "*array*" $from]
|| [string match "float*" $to] && [string match "*method" $from]))
|| (!$double_ptr_same_size
&& ([string match "double*" $to] && [string match "*array*" $from]
|| [string match "double*" $to] && [string match "*method" $from]))
|| (!$long_double_ptr_same_size
&& ([string match "long_double*" $to] && [string match "*array*" $from]
|| [string match "long_double*" $to] && [string match "*method" $from]))
|| ([string match "*ftype" $to] && [string match "*array*" $from])
|| ([string match "*ftype2" $to] && [string match "*array*" $from])
|| ([string match "*ftype" $to] && [string match "*method" $from])