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

@ -1,3 +1,18 @@
2017-03-16 Doug Evans <dje@google.com>
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.
2017-03-16 Doug Evans <dje@google.com>
* guile/guile-internal.h (tyscm_scm_to_type): Declare.

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)
{

View File

@ -1,7 +1,19 @@
<<<<<<< HEAD
2017-03-16 Thomas Preud'homme <thomas.preudhomme@arm.com>
* gdb.cp/m-static.exp: Fix expectation for prototype of
test5.single_constructor and single_constructor::single_constructor.
=======
2017-03-15 Doug Evans <dje@google.com>
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.
>>>>>>> Fix various python lazy string bugs.
2017-03-14 Anton Kolesov <anton.kolesov@synopsys.com>

View File

@ -18,6 +18,9 @@
int
main ()
{
const char *ptr = "pointer";
const char array[] = "array";
pointer typedef_ptr = "typedef pointer";
const char *null = 0;
return 0; /* break here */

View File

@ -34,9 +34,43 @@ if ![runto_main ] {
gdb_breakpoint [gdb_get_line_number "break here"]
gdb_continue_to_breakpoint "break here"
gdb_test_no_output "python null = gdb.parse_and_eval(\"null\")"
gdb_py_test_silent_cmd "python null = gdb.parse_and_eval(\"null\")" "get null value" 1
gdb_test "python print(null.lazy_string(length=0).value())" \
"gdb.MemoryError: Cannot create a value from NULL.*Error while executing Python code."
gdb_py_test_silent_cmd "python nullstr = null.lazy_string(length=0)" "create a null lazy string" 1
gdb_test "python print (nullstr.length)" "0" "null lazy string length"
gdb_test "python print (nullstr.address)" "0" "null lazy string address"
gdb_test "python print (nullstr.type)" "const char \\*" "null lazy string type"
gdb_test "python print(nullstr.value())" \
"gdb.MemoryError: Cannot create a value from NULL.*Error while executing Python code." \
"create value from NULL"
gdb_test "python print(null.lazy_string(length=3).value())" \
"gdb.MemoryError: Cannot create a lazy string with address 0x0, and a non-zero length.*Error while executing Python code."
"gdb.MemoryError: Cannot create a lazy string with address 0x0, and a non-zero length.*Error while executing Python code." \
"null lazy string with non-zero length"
gdb_test "python print(null.lazy_string(length=-2))" \
"ValueError: Invalid length.*Error while executing Python code." \
"bad length"
foreach var_spec { { "ptr" "pointer" "const char \\*" -1 } \
{ "array" "array" "const char \\[6\\]" 6 } \
{ "typedef_ptr" "typedef pointer" "pointer" -1 } } {
set var [lindex $var_spec 0]
set value [lindex $var_spec 1]
set type [lindex $var_spec 2]
set length [lindex $var_spec 3]
with_test_prefix $var {
gdb_test "print $var" "\"$value\""
gdb_py_test_silent_cmd "python $var = gdb.history (0)" "get value from history" 1
gdb_py_test_silent_cmd "python l$var = $var.lazy_string()" "acquire lazy string" 1
gdb_test "python print ($var.type)" "$type" "string type name equality"
gdb_test "python print (l$var.type)" "$type" "lazy-string type name equality"
gdb_test "python print (l$var.length)" "$length" "lazy string length"
gdb_test "python print (l$var.value())" "\"$value\"" "lazy string value"
gdb_py_test_silent_cmd "python l2$var = $var.lazy_string(length=2)" "acquire lazy string, length 2" 1
gdb_test "python print (l2$var.length)" "2" "lazy string length 2"
gdb_test "python print (l2$var.value())" "\"[string range $value 0 1]\"" "lazy string length 2 value"
# This test will have to wait until gdb can handle it. There's no way,
# currently, to internally specify an array of length zero in the C
# language support. PR 20786
#gdb_test "python print ($var.lazy_string(length=0).value())" "\"\"" "empty lazy string value"
}
}

View File

@ -90,13 +90,11 @@ main (int argc, char *argv[])
char nullst[17] = "divide\0et\0impera";
void (*fp1) (void) = &func1;
int (*fp2) (int, int) = &func2;
const char *sptr = "pointer";
const char *embed = "embedded x\201\202\203\204";
int a[3] = {1,2,3};
int *p = a;
int i = 2;
int *ptr_i = &i;
const char *sn = 0;
struct str *xstr;
/* Prevent gcc from optimizing argv[] out. */

View File

@ -317,29 +317,6 @@ proc test_value_in_inferior {} {
"read string beyond declared size"
}
proc test_lazy_strings {} {
global hex
gdb_test "print sptr" "\"pointer\""
gdb_py_test_silent_cmd "python sptr = gdb.history (0)" "Get value from history" 1
gdb_py_test_silent_cmd "python lstr = sptr.lazy_string()" "Aquire lazy string" 1
gdb_test "python print (lstr.type)" "const char \*." "test lazy-string type name equality"
gdb_test "python print (sptr.type)" "const char \*." "test string type name equality"
# Prevent symbol on address 0x0 being printed.
gdb_test_no_output "set print symbol off"
gdb_test "print sn" "0x0"
gdb_py_test_silent_cmd "python snptr = gdb.history (0)" "Get value from history" 1
gdb_test "python snstr = snptr.lazy_string(length=5)" ".*Cannot create a lazy string with address.*" "test lazy string"
gdb_py_test_silent_cmd "python snstr = snptr.lazy_string(length=0)" "Succesfully create a lazy string" 1
gdb_test "python print (snstr.length)" "0" "test lazy string length"
gdb_test "python print (snstr.address)" "0" "test lazy string address"
}
proc test_inferior_function_call {} {
global gdb_prompt hex decimal
@ -534,7 +511,6 @@ if ![runto_main] then {
test_value_in_inferior
test_inferior_function_call
test_lazy_strings
test_value_after_death
# Test either C or C++ values.