Fix various python lazy string bugs.

gdb/ChangeLog:

	PR python/17728, python/18439, python/18779
	* python/py-lazy-string.c (lazy_string_object): Clarify use of LENGTH
	member.  Change type of TYPE member to PyObject *.  All uses updated.
	(stpy_convert_to_value): Fix handling of TYPE_CODE_PTR.
	(gdbpy_create_lazy_string_object): Flag bad length values.
	Handle TYPE_CODE_ARRAY with possibly different user-provided length.
	Handle typedefs in incoming type.
	(stpy_lazy_string_elt_type): New function.
	(gdbpy_extract_lazy_string): Call it.
	* python/py-value.c (valpy_lazy_string): Flag bad length values.
	Fix handling of TYPE_CODE_PTR.  Handle TYPE_CODE_ARRAY.  Handle
	typedefs in incoming type.

gdb/testsuite/ChangeLog:

	PR python/17728, python/18439, python/18779
	* gdb.python/py-value.c (main) Delete locals sptr, sn.
	* gdb.python/py-lazy-string.c (pointer): New typedef.
	(main): New locals ptr, array, typedef_ptr.
	* gdb.python/py-value.exp: Move lazy string tests to ...
	* gdb.python/py-lazy-string.exp: ... here.  Add more tests for pointer,
	array, typedef lazy strings.
This commit is contained in:
Doug Evans
2017-03-15 15:35:13 -07:00
parent a3a5feccd2
commit 34b433203b
8 changed files with 240 additions and 51 deletions

View File

@ -26,6 +26,7 @@
typedef struct {
PyObject_HEAD
/* Holds the address of the lazy string. */
CORE_ADDR address;
@ -35,14 +36,21 @@ typedef struct {
encoding when the sting is printed. */
char *encoding;
/* Holds the length of the string in characters. If the
length is -1, then the string will be fetched and encoded up to
the first null of appropriate width. */
/* If TYPE is an array: If the length is known, then this value is the
array's length, otherwise it is -1.
If TYPE is not an array: Then this value represents the string's length.
In either case, if the value is -1 then the string will be fetched and
encoded up to the first null of appropriate width. */
long length;
/* This attribute holds the type that is represented by the lazy
string's type. */
struct type *type;
/* This attribute holds the type of the string.
For example if the lazy string was created from a C "char*" then TYPE
represents a C "char*".
To get the type of the character in the string call
stpy_lazy_string_elt_type.
This is recorded as a PyObject so that we take advantage of support for
preserving the type should its owning objfile go away. */
PyObject *type;
} lazy_string_object;
extern PyTypeObject lazy_string_object_type
@ -88,11 +96,12 @@ stpy_get_type (PyObject *self, void *closure)
{
lazy_string_object *str_obj = (lazy_string_object *) self;
return type_to_type_object (str_obj->type);
Py_INCREF (str_obj->type);
return str_obj->type;
}
static PyObject *
stpy_convert_to_value (PyObject *self, PyObject *args)
stpy_convert_to_value (PyObject *self, PyObject *args)
{
lazy_string_object *self_string = (lazy_string_object *) self;
struct value *val = NULL;
@ -106,7 +115,32 @@ stpy_convert_to_value (PyObject *self, PyObject *args)
TRY
{
val = value_at_lazy (self_string->type, self_string->address);
struct type *type = type_object_to_type (self_string->type);
struct type *realtype;
gdb_assert (type != NULL);
realtype = check_typedef (type);
switch (TYPE_CODE (realtype))
{
case TYPE_CODE_PTR:
/* If a length is specified we need to convert this to an array
of the specified size. */
if (self_string->length != -1)
{
/* PR 20786: There's no way to specify an array of length zero.
Record a length of [0,-1] which is how Ada does it. Anything
we do is broken, but this is one possible solution. */
type = lookup_array_range_type (TYPE_TARGET_TYPE (realtype),
0, self_string->length - 1);
val = value_at_lazy (type, self_string->address);
}
else
val = value_from_pointer (type, self_string->address);
break;
default:
val = value_at_lazy (type, self_string->address);
break;
}
}
CATCH (except, RETURN_MASK_ALL)
{
@ -125,11 +159,24 @@ stpy_dealloc (PyObject *self)
xfree (self_string->encoding);
}
/* Low level routine to create a <gdb.LazyString> object.
Note: If TYPE is an array, LENGTH either must be -1 (meaning to use the
size of the array, which may itself be unknown in which case a length of
-1 is still used) or must be the length of the array. */
PyObject *
gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
const char *encoding, struct type *type)
const char *encoding, struct type *type)
{
lazy_string_object *str_obj = NULL;
struct type *realtype;
if (length < -1)
{
PyErr_SetString (PyExc_ValueError, _("Invalid length."));
return NULL;
}
if (address == 0 && length != 0)
{
@ -146,6 +193,27 @@ gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
return NULL;
}
realtype = check_typedef (type);
switch (TYPE_CODE (realtype))
{
case TYPE_CODE_ARRAY:
{
LONGEST array_length = -1;
LONGEST low_bound, high_bound;
if (get_array_bounds (realtype, &low_bound, &high_bound))
array_length = high_bound - low_bound + 1;
if (length == -1)
length = array_length;
else if (length != array_length)
{
PyErr_SetString (PyExc_ValueError, _("Invalid length."));
return NULL;
}
break;
}
}
str_obj = PyObject_New (lazy_string_object, &lazy_string_object_type);
if (!str_obj)
return NULL;
@ -156,7 +224,7 @@ gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
str_obj->encoding = NULL;
else
str_obj->encoding = xstrdup (encoding);
str_obj->type = type;
str_obj->type = type_to_type_object (type);
return (PyObject *) str_obj;
}
@ -179,12 +247,35 @@ gdbpy_is_lazy_string (PyObject *result)
return PyObject_TypeCheck (result, &lazy_string_object_type);
}
/* Return the type of a character in lazy string LAZY. */
static struct type *
stpy_lazy_string_elt_type (lazy_string_object *lazy)
{
struct type *type = type_object_to_type (lazy->type);
struct type *realtype;
gdb_assert (type != NULL);
realtype = check_typedef (type);
switch (TYPE_CODE (realtype))
{
case TYPE_CODE_PTR:
case TYPE_CODE_ARRAY:
return TYPE_TARGET_TYPE (realtype);
default:
/* This is done to preserve existing behaviour. PR 20769.
E.g., gdb.parse_and_eval("my_int_variable").lazy_string().type. */
return realtype;
}
}
/* Extract the parameters from the lazy string object STRING.
ENCODING may be set to NULL, if no encoding is found. */
void
gdbpy_extract_lazy_string (PyObject *string, CORE_ADDR *addr,
struct type **str_type,
struct type **str_elt_type,
long *length,
gdb::unique_xmalloc_ptr<char> *encoding)
{
@ -195,7 +286,7 @@ gdbpy_extract_lazy_string (PyObject *string, CORE_ADDR *addr,
lazy = (lazy_string_object *) string;
*addr = lazy->address;
*str_type = lazy->type;
*str_elt_type = stpy_lazy_string_elt_type (lazy);
*length = lazy->length;
encoding->reset (lazy->encoding ? xstrdup (lazy->encoding) : NULL);
}

View File

@ -400,9 +400,19 @@ valpy_get_dynamic_type (PyObject *self, void *closure)
A lazy string is a pointer to a string with an optional encoding and
length. If ENCODING is not given, encoding is set to None. If an
ENCODING is provided the encoding parameter is set to ENCODING, but
the string is not encoded. If LENGTH is provided then the length
parameter is set to LENGTH, otherwise length will be set to -1 (first
null of appropriate with). */
the string is not encoded.
If LENGTH is provided then the length parameter is set to LENGTH.
Otherwise if the value is an array of known length then the array's length
is used. Otherwise the length will be set to -1 (meaning first null of
appropriate with).
Note: In order to not break any existing uses this allows creating
lazy strings from anything. PR 20769. E.g.,
gdb.parse_and_eval("my_int_variable").lazy_string().
"It's easier to relax restrictions than it is to impose them after the
fact." So we should be flagging any unintended uses as errors, but it's
perhaps too late for that. */
static PyObject *
valpy_lazy_string (PyObject *self, PyObject *args, PyObject *kw)
{
@ -416,16 +426,66 @@ valpy_lazy_string (PyObject *self, PyObject *args, PyObject *kw)
&user_encoding, &length))
return NULL;
if (length < -1)
{
PyErr_SetString (PyExc_ValueError, _("Invalid length."));
return NULL;
}
TRY
{
scoped_value_mark free_values;
struct type *type, *realtype;
CORE_ADDR addr;
if (TYPE_CODE (value_type (value)) == TYPE_CODE_PTR)
value = value_ind (value);
type = value_type (value);
realtype = check_typedef (type);
str_obj = gdbpy_create_lazy_string_object (value_address (value), length,
user_encoding,
value_type (value));
switch (TYPE_CODE (realtype))
{
case TYPE_CODE_ARRAY:
{
LONGEST array_length = -1;
LONGEST low_bound, high_bound;
/* PR 20786: There's no way to specify an array of length zero.
Record a length of [0,-1] which is how Ada does it. Anything
we do is broken, but this one possible solution. */
if (get_array_bounds (realtype, &low_bound, &high_bound))
array_length = high_bound - low_bound + 1;
if (length == -1)
length = array_length;
else if (array_length == -1)
{
type = lookup_array_range_type (TYPE_TARGET_TYPE (realtype),
0, length - 1);
}
else if (length != array_length)
{
/* We need to create a new array type with the
specified length. */
if (length > array_length)
error (_("Length is larger than array size."));
type = lookup_array_range_type (TYPE_TARGET_TYPE (realtype),
low_bound,
low_bound + length - 1);
}
addr = value_address (value);
break;
}
case TYPE_CODE_PTR:
/* If a length is specified we defer creating an array of the
specified width until we need to. */
addr = value_as_address (value);
break;
default:
/* Should flag an error here. PR 20769. */
addr = value_address (value);
break;
}
str_obj = gdbpy_create_lazy_string_object (addr, length, user_encoding,
type);
}
CATCH (except, RETURN_MASK_ALL)
{