RFA: fix PR 9164

Tom Tromey
2009-01-03T21:20:41Z

This patch fixes PR 9164.

The bug is that the result of sizeof has signed type, not unsigned.
The C and C++ standards require an unsigned type here.

This fix defers the choice of type to the language, using the existing
language-arch machinery. I fixed the C language family, including
ObjC, but I left the other languages unchanged. I think the language
maintainers will have to make a change here, if one is needed or
desired. (FWIW I don't think Java needs a change, since I don't think
it is possible to invoke sizeof when Java is the selected language.)

Built and regtested on x86-64 (compile farm).
New test case included.

Please review.

thanks,
Tom

2009-01-03 Tom Tromey <tromey@redhat.com>

PR gdb/9164:
* p-lang.c (pascal_language_arch_info): Initialize
lai->size_type_default.
* objc-exp.y (exp): Call language_size_type.
* m2-lang.c (m2_language_arch_info): Initialize
lai->size_type_default.
* language.h (language_size_type): Declare.
(struct language_arch_info) <size_type_symbol, size_type_default>:
New fields.
* language.c (unknown_language_arch_info): Initialize
lai->size_type_default.
(language_size_type): New function.
* jv-lang.c (java_language_arch_info): Initialize
lai->size_type_default.
* f-lang.c (f_language_arch_info): Initialize
lai->size_type_default.
* eval.c (evaluate_subexp_for_sizeof): Call language_size_type.
* c-lang.c (find_size_type): New function.
(c_language_arch_info): Call it.
(cplus_language_arch_info): Likewise.
* c-exp.y (exp): Use language_size_type.
* ada-lang.c (ada_language_arch_info): Initialize
lai->size_type_default.

2009-01-03 Tom Tromey <tromey@redhat.com>

* gdb.base/sizeof.exp (check_sizeof): Verify that sizeof returns
unsigned type.

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index bcbd709..8571eda 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -11000,6 +11000,8 @@ ada_language_arch_info (struct gdbarch *gdbarch,

lai->bool_type_symbol = "boolean";
lai->bool_type_default = builtin->builtin_bool;
+
+ lai->size_type_default = builtin->builtin_int;
}
\f
/* Language vector */
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 0db8c0b..212d7b5 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -558,7 +558,8 @@ exp : VARIABLE

exp : SIZEOF '(' type ')' %prec UNARY
{ write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type (parse_type->builtin_int);
+ write_exp_elt_type (language_size_type (parse_language,
+ parse_gdbarch));
CHECK_TYPEDEF ($3);
write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3));
write_exp_elt_opcode (OP_LONG); }
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index dc7b059..f3020f6 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -223,6 +223,25 @@ const struct op_print c_op_print_tab[] =
{NULL, 0, 0, 0}
};
\f
+/* A helper function to compute the default size type for C-like
+ languages. */
+static void
+find_size_type (const struct builtin_type *builtin,
+ struct language_arch_info *lai)
+{
+ lai->size_type_symbol = "size_t";
+
+ /* For the default, pick an unsigned integral type the same width as
+ a data pointer, if possible. If none match, use unsigned int. */
+ if (TYPE_LENGTH (builtin->builtin_unsigned_long)
+ == TYPE_LENGTH (builtin->builtin_data_ptr))
+ lai->size_type_default = builtin->builtin_unsigned_long;
+ else if (TYPE_LENGTH (builtin->builtin_unsigned_long_long))
+ lai->size_type_default = builtin->builtin_unsigned_long_long;
+ else
+ lai->size_type_default = builtin->builtin_unsigned_int;
+}
+
enum c_primitive_types {
c_primitive_type_int,
c_primitive_type_long,
@@ -278,6 +297,8 @@ c_language_arch_info (struct gdbarch *gdbarch,
lai->primitive_type_vector [c_primitive_type_declong] = builtin->builtin_declong;

lai->bool_type_default = builtin->builtin_int;
+
+ find_size_type (builtin, lai);
}

const struct language_defn c_language_defn =
@@ -396,6 +417,8 @@ cplus_language_arch_info (struct gdbarch *gdbarch,

lai->bool_type_symbol = "bool";
lai->bool_type_default = builtin->builtin_bool;
+
+ find_size_type (builtin, lai);
}

const struct language_defn cplus_language_defn =
diff --git a/gdb/eval.c b/gdb/eval.c
index ccb6b74..026795b 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2652,8 +2652,8 @@ evaluate_subexp_with_coercion (struct expression *exp,
static struct value *
evaluate_subexp_for_sizeof (struct expression *exp, int *pos)
{
- /* FIXME: This should be size_t. */
- struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
+ struct type *size_type = language_size_type (exp->language_defn,
+ exp->gdbarch);
enum exp_opcode op;
int pc;
struct type *type;
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 4d4d4d7..bf4dac5 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -302,6 +302,8 @@ f_language_arch_info (struct gdbarch *gdbarch,

lai->bool_type_symbol = "logical";
lai->bool_type_default = builtin->builtin_logical_s2;
+
+ lai->size_type_default = builtin_type (gdbarch)->builtin_int;
}

/* This is declared in c-lang.h but it is silly to import that file for what
diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c
index 0470eef..4f75f7b 100644
--- a/gdb/jv-lang.c
+++ b/gdb/jv-lang.c
@@ -1083,6 +1083,8 @@ java_language_arch_info (struct gdbarch *gdbarch,

lai->bool_type_symbol = "boolean";
lai->bool_type_default = java_boolean_type;
+
+ lai->size_type_default = builtin_type (gdbarch)->builtin_int;
}

const struct exp_descriptor exp_descriptor_java =
diff --git a/gdb/language.c b/gdb/language.c
index 46e238d..c6eec0a 100644
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -1127,6 +1127,7 @@ unknown_language_arch_info (struct gdbarch *gdbarch,
{
lai->string_char_type = builtin_type (gdbarch)->builtin_char;
lai->bool_type_default = builtin_type (gdbarch)->builtin_int;
+ lai->size_type_default = builtin_type (gdbarch)->builtin_int;
lai->primitive_type_vector = GDBARCH_OBSTACK_CALLOC (gdbarch, 1,
struct type *);
}
@@ -1303,6 +1304,33 @@ language_bool_type (const struct language_defn *la,
return ld->arch_info[la->la_language].bool_type_default;
}

+/* Return the size type for the given language and architecture. The
+ size type is the type used to represent the size of an object, for
+ instance the result of the C `sizeof' operator. */
+
+struct type *
+language_size_type (const struct language_defn *la,
+ struct gdbarch *gdbarch)
+{
+ struct language_gdbarch *ld = gdbarch_data (gdbarch,
+ language_gdbarch_data);
+
+ if (ld->arch_info[la->la_language].size_type_symbol)
+ {
+ struct symbol *sym;
+ sym = lookup_symbol (ld->arch_info[la->la_language].size_type_symbol,
+ NULL, VAR_DOMAIN, NULL);
+ if (sym)
+ {
+ struct type *type = SYMBOL_TYPE (sym);
+ if (type && TYPE_CODE (type) == TYPE_CODE_INT)
+ return type;
+ }
+ }
+
+ return ld->arch_info[la->la_language].size_type_default;
+}
+
struct type *
language_lookup_primitive_type_by_name (const struct language_defn *la,
struct gdbarch *gdbarch,
diff --git a/gdb/language.h b/gdb/language.h
index c92c57c..f09c029 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -134,6 +134,11 @@ struct language_arch_info
const char *bool_type_symbol;
/* Otherwise, this is the default boolean builtin type. */
struct type *bool_type_default;
+
+ /* Symbol name of type to use as size type, if defined. */
+ const char *size_type_symbol;
+ /* Otherwise, this is the default builtin size type. */
+ struct type *size_type_default;
};

/* Structure tying together assorted information about a language. */
@@ -331,6 +336,9 @@ struct type *language_bool_type (const struct language_defn *l,
struct type *language_string_char_type (const struct language_defn *l,
struct gdbarch *gdbarch);

+struct type *language_size_type (const struct language_defn *l,
+ struct gdbarch *gdbarch);
+
struct type *language_lookup_primitive_type_by_name (const struct language_defn *l,
struct gdbarch *gdbarch,
const char *name);
diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index e09b64b..fa6fcaf 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -349,6 +349,8 @@ m2_language_arch_info (struct gdbarch *gdbarch,

lai->bool_type_symbol = "BOOLEAN";
lai->bool_type_default = builtin->builtin_bool;
+
+ lai->size_type_default = builtin->builtin_int;
}

const struct exp_descriptor exp_descriptor_modula2 =
diff --git a/gdb/objc-exp.y b/gdb/objc-exp.y
index 1527a04..aa4f738 100644
--- a/gdb/objc-exp.y
+++ b/gdb/objc-exp.y
@@ -577,7 +577,8 @@ exp : SELECTOR

exp : SIZEOF '(' type ')' %prec UNARY
{ write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type (parse_type->builtin_int);
+ write_exp_elt_type (language_size_type (parse_language,
+ parse_gdbarch));
CHECK_TYPEDEF ($3);
write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3));
write_exp_elt_opcode (OP_LONG); }
diff --git a/gdb/p-lang.c b/gdb/p-lang.c
index cd4285d..bd82c48 100644
--- a/gdb/p-lang.c
+++ b/gdb/p-lang.c
@@ -397,6 +397,8 @@ pascal_language_arch_info (struct gdbarch *gdbarch,

lai->bool_type_symbol = "boolean";
lai->bool_type_default = builtin->builtin_bool;
+
+ lai->size_type_default = builtin->builtin_int;
}

const struct language_defn pascal_language_defn =
diff --git a/gdb/testsuite/gdb.base/sizeof.exp b/gdb/testsuite/gdb.base/sizeof.exp
index c6432bf..421d3ea 100644
--- a/gdb/testsuite/gdb.base/sizeof.exp
+++ b/gdb/testsuite/gdb.base/sizeof.exp
@@ -118,6 +118,10 @@ check_sizeof "float" ${sizeof_float}
check_sizeof "double" ${sizeof_double}
check_sizeof "long double" ${sizeof_long_double}

+# Check that sizeof has unsigned type.
+gdb_test "print -sizeof(int)" \
+ "\\$\[0-9\]* = (\[0-9\]*)"
+
proc check_valueof { exp val } {
global gdb_prompt