RFC: fix `gdb -write' case

Tom Tromey
2011-05-06T17:12:29Z

I'd appreciate comments on this. In the absence of comments I will
check it in. I plan to put it on the 7.3 branch as well.

This comes from:

https://bugzilla.redhat.com/show_bug.cgi?id=696148

The bug is that you cannot change a string in an executable with `gdb
-write'. Jan tracked this down to the wide string change; the bug is
that evaluate_subexp_c did not examine `expect_type', leading to an
attempt to coerce the string to memory.

Built and regtested by our internal buildbot.

Tom

2011-05-06 Tom Tromey <tromey@redhat.com>

* c-lang.c (evaluate_subexp_c): Use expect_type if it is not
NULL.

diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index ad770bf..64c4d79 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -1061,9 +1061,39 @@ evaluate_subexp_c (struct type *expect_type, struct expression *exp,
/* Write the terminating character. */
for (i = 0; i < TYPE_LENGTH (type); ++i)
obstack_1grow (&output, 0);
- result = value_cstring (obstack_base (&output),
- obstack_object_size (&output),
- type);
+
+ if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_ARRAY)
+ {
+ LONGEST low_bound, high_bound;
+ struct type *element_type
+ = check_typedef (TYPE_TARGET_TYPE (expect_type));
+ int element_size = TYPE_LENGTH (element_type);
+
+ if (TYPE_CODE (element_type) != TYPE_CODE_INT
+ && (TYPE_CODE (element_type) != TYPE_CODE_CHAR))
+ error (_("wrong expected type for string constant"));
+ if (TYPE_LENGTH (element_type) != TYPE_LENGTH (type))
+ error (_("expected type of string constant has wrong "
+ "character width"));
+
+ if (get_discrete_bounds (TYPE_INDEX_TYPE (expect_type),
+ &low_bound, &high_bound) < 0)
+ {
+ low_bound = 0;
+ high_bound = (TYPE_LENGTH (expect_type) / element_size) - 1;
+ }
+ if (obstack_object_size (&output) / TYPE_LENGTH (type)
+ > (high_bound - low_bound + 1))
+ error (_("Too many array elements"));
+
+ result = allocate_value (expect_type);
+ memcpy (value_contents_raw (result), obstack_base (&output),
+ obstack_object_size (&output));
+ }
+ else
+ result = value_cstring (obstack_base (&output),
+ obstack_object_size (&output),
+ type);
}
do_cleanups (cleanup);
return result;