Allow conversion of 128-bit integers to Python

Currently, trying to convert a 128-bit integer from a gdb.Value to a
Python integer will fail.  This is surprising because Python uses
bigints internally.

The bug here is that valpy_long uses value_as_long, which fails for
anything wider than LONGEST.  This patch fixes the problem by using
the recommended Python API.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33366
Approved-By: Simon Marchi <simon.marchi@efficios.com>
This commit is contained in:
Tom Tromey
2025-09-05 05:31:34 -06:00
parent aaad5a3254
commit 2769710301
2 changed files with 58 additions and 6 deletions

View File

@@ -1866,7 +1866,7 @@ valpy_long (PyObject *self)
{
struct value *value = ((value_object *) self)->value;
struct type *type = value->type ();
LONGEST l = 0;
PyObject *result;
try
{
@@ -1882,17 +1882,57 @@ valpy_long (PyObject *self)
&& type->code () != TYPE_CODE_PTR)
error (_("Cannot convert value to long."));
l = value_as_long (value);
gdb::array_view<const gdb_byte> contents = value->contents ();
#if PY_VERSION_HEX >= 0x030d0000
int flags = (type_byte_order (type) == BFD_ENDIAN_BIG
? Py_ASNATIVEBYTES_BIG_ENDIAN
: Py_ASNATIVEBYTES_LITTLE_ENDIAN);
if (type->is_unsigned ())
flags |= Py_ASNATIVEBYTES_UNSIGNED_BUFFER;
result = PyLong_FromNativeBytes (contents.data (), contents.size (),
flags);
#else
/* Here we construct a call to "int.from_bytes", passing in the
appropriate arguments. We need a somewhat roundabout
approach because int.from_bytes requires "signed" to be a
keyword arg. */
/* PyObject_Call requires a tuple argument. */
gdbpy_ref<> empty_tuple (PyTuple_New (0));
if (empty_tuple == nullptr)
return nullptr;
/* Since we need a dictionary anyway, we pass all arguments as
keywords, building the dictionary here. */
gdbpy_ref<> args
(Py_BuildValue ("{sy#sssO}",
"bytes", contents.data (),
(Py_ssize_t) contents.size (),
"byteorder",
(type_byte_order (type) == BFD_ENDIAN_BIG
? "big" : "little"),
"signed",
type->is_unsigned ()
? Py_False : Py_True));
if (args == nullptr)
return nullptr;
/* Find the "int.from_bytes" callable. */
gdbpy_ref<> callable (PyObject_GetAttrString ((PyObject *) &PyLong_Type,
"from_bytes"));
if (callable == nullptr)
return nullptr;
result = PyObject_Call (callable.get (), empty_tuple.get (),
args.get ());
#endif
}
catch (const gdb_exception &except)
{
return gdbpy_handle_gdb_exception (nullptr, except);
}
if (type->is_unsigned ())
return gdb_py_object_from_ulongest (l).release ();
else
return gdb_py_object_from_longest (l).release ();
return result;
}
/* Implements conversion to float. */

View File

@@ -844,3 +844,15 @@ if {[allow_cplus_tests]} {
test_subscript_regression "${binfile}-cxx" "c++"
}
}
if {[allow_rust_tests]} {
gdb_test "set lang rust"
set cst 0x80000000000000000000000000000000
gdb_test "python print(int(gdb.parse_and_eval('${cst}u128')))" \
"170141183460469231731687303715884105728" \
"convert 128 bit unsigned constant to python int"
gdb_test "python print(int(gdb.parse_and_eval('${cst}i128')))" \
"-170141183460469231731687303715884105728" \
"convert 128 bit signed constant to python int"
}