Skip to content

Commit 21b470b

Browse files
author
Delphix Engineering
committed
Merge branch 'refs/heads/upstream-HEAD' into repo-HEAD
2 parents eff2868 + 971a2d3 commit 21b470b

File tree

3 files changed

+65
-81
lines changed

3 files changed

+65
-81
lines changed

_drgn.pyi

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -611,14 +611,14 @@ class Object:
611611
language. For example, adding two objects from a program written in C
612612
results in an object with a type and value according to the rules of C:
613613
614-
>>> Object(prog, 'unsigned long', value=2**64 - 1) + Object(prog, 'int', value=1)
614+
>>> Object(prog, 'unsigned long', 2**64 - 1) + Object(prog, 'int', 1)
615615
Object(prog, 'unsigned long', value=0)
616616
617617
If only one operand to a binary operator is an object, the other operand
618618
will be converted to an object according to the language's rules for
619619
literals:
620620
621-
>>> Object(prog, 'char', value=0) - 1
621+
>>> Object(prog, 'char', 0) - 1
622622
Object(prog, 'int', value=-1)
623623
624624
The standard :class:`int() <int>`, :class:`float() <float>`, and
@@ -640,9 +640,9 @@ class Object:
640640
:param prog: The program to create this object in.
641641
:param type: The type of the object. If omitted, this is deduced from
642642
*value* according to the language's rules for literals.
643+
:param value: The value of this object. See :meth:`value_()`.
643644
:param address: The address of this object in the program. Either this or
644645
*value* must be given, but not both.
645-
:param value: The value of this object. See :meth:`value_()`.
646646
:param byteorder: Byte order of the object. This should be ``'little'`` or
647647
``'big'``. The default is ``None``, which indicates the program byte
648648
order. This must be ``None`` for primitive values.
@@ -657,9 +657,9 @@ class Object:
657657
self,
658658
prog: Program,
659659
type: Union[str, Type, None] = None,
660+
value: Any = None,
660661
*,
661662
address: Optional[int] = None,
662-
value: Any = None,
663663
byteorder: Optional[str] = None,
664664
bit_offset: Optional[int] = None,
665665
bit_field_size: Optional[int] = None,
@@ -935,7 +935,7 @@ def NULL(prog: Program, type: Union[str, Type]) -> Object:
935935
"""
936936
Get an object representing ``NULL`` casted to the given type.
937937
938-
This is equivalent to ``Object(prog, type, value=0)``.
938+
This is equivalent to ``Object(prog, type, 0)``.
939939
940940
:param prog: The program.
941941
:param type: The type.

libdrgn/python/object.c

Lines changed: 48 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,6 @@
99
#include "../serialize.h"
1010
#include "../type.h"
1111

12-
static DrgnObject *DrgnObject_new(PyTypeObject *subtype, PyObject *args,
13-
PyObject *kwds)
14-
{
15-
PyObject *arg;
16-
17-
if (PyTuple_GET_SIZE(args) < 1) {
18-
PyErr_SetString(PyExc_TypeError,
19-
"Object() missing required argument 'prog' (pos 1)");
20-
return NULL;
21-
}
22-
arg = PyTuple_GET_ITEM(args, 0);
23-
if (!PyObject_TypeCheck(arg, &Program_type)) {
24-
PyErr_SetString(PyExc_TypeError,
25-
"Object() argument 1 must be Program");
26-
return NULL;
27-
}
28-
return DrgnObject_alloc((Program *)arg);
29-
}
30-
31-
static void DrgnObject_dealloc(DrgnObject *self)
32-
{
33-
Py_DECREF(DrgnObject_prog(self));
34-
drgn_object_deinit(&self->obj);
35-
Py_TYPE(self)->tp_free((PyObject *)self);
36-
}
37-
3812
static int DrgnObject_literal(struct drgn_object *res, PyObject *literal)
3913
{
4014
struct drgn_error *err;
@@ -393,7 +367,8 @@ static int buffer_object_from_value(struct drgn_object *res,
393367
return 0;
394368
}
395369

396-
static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds)
370+
static DrgnObject *DrgnObject_new(PyTypeObject *subtype, PyObject *args,
371+
PyObject *kwds)
397372
{
398373
static char *keywords[] = {
399374
"prog", "type", "value", "address", "byteorder",
@@ -411,44 +386,41 @@ static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds)
411386
struct index_arg bit_offset = { .allow_none = true, .is_none = true };
412387
struct index_arg bit_field_size = { .allow_none = true, .is_none = true };
413388
struct drgn_qualified_type qualified_type;
389+
DrgnObject *obj;
414390

415-
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|O$OO&O&O&O&:Object",
391+
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|OO$O&O&O&O&:Object",
416392
keywords, &Program_type, &prog,
417393
&type_obj, &value_obj, index_converter,
418394
&address, byteorder_converter,
419395
&byteorder, index_converter,
420396
&bit_offset, index_converter,
421397
&bit_field_size))
422-
return -1;
423-
424-
if (&prog->prog != self->obj.prog) {
425-
PyErr_SetString(PyExc_ValueError,
426-
"cannot change object program");
427-
return -1;
428-
}
398+
return NULL;
429399

430-
if (Program_type_arg(DrgnObject_prog(self), type_obj, true,
431-
&qualified_type) == -1)
432-
return -1;
400+
if (Program_type_arg(prog, type_obj, true, &qualified_type) == -1)
401+
return NULL;
433402

434403
if (!bit_field_size.is_none && bit_field_size.uvalue == 0) {
435404
PyErr_SetString(PyExc_ValueError,
436405
"bit field size cannot be zero");
437-
return -1;
406+
return NULL;
438407
}
439408

409+
obj = DrgnObject_alloc(prog);
410+
if (!obj)
411+
return NULL;
440412
if (!address.is_none && value_obj != Py_None) {
441413
PyErr_SetString(PyExc_ValueError,
442414
"object cannot have address and value");
443-
return -1;
415+
goto err;
444416
} else if (!address.is_none) {
445417
if (!qualified_type.type) {
446418
PyErr_SetString(PyExc_ValueError,
447419
"reference must have type");
448-
return -1;
420+
goto err;
449421
}
450422

451-
err = drgn_object_set_reference(&self->obj, qualified_type,
423+
err = drgn_object_set_reference(&obj->obj, qualified_type,
452424
address.uvalue,
453425
bit_offset.uvalue,
454426
bit_field_size.uvalue,
@@ -459,27 +431,27 @@ static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds)
459431
if (!byteorder.is_none) {
460432
PyErr_SetString(PyExc_ValueError,
461433
"literal cannot have byteorder");
462-
return -1;
434+
goto err;
463435
}
464436
if (!bit_offset.is_none) {
465437
PyErr_SetString(PyExc_ValueError,
466438
"literal cannot have bit offset");
467-
return -1;
439+
goto err;
468440
}
469441
if (!bit_field_size.is_none) {
470442
PyErr_SetString(PyExc_ValueError,
471443
"literal cannot be bit field");
472-
return -1;
444+
goto err;
473445
}
474446

475-
ret = DrgnObject_literal(&self->obj, value_obj);
447+
ret = DrgnObject_literal(&obj->obj, value_obj);
476448
if (ret == -1) {
477-
return -1;
449+
goto err;
478450
} else if (ret) {
479451
PyErr_Format(PyExc_TypeError,
480452
"cannot create %s literal",
481453
Py_TYPE(value_obj)->tp_name);
482-
return -1;
454+
goto err;
483455
}
484456
err = NULL;
485457
} else if (value_obj != Py_None) {
@@ -490,35 +462,35 @@ static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds)
490462
err = drgn_error_incomplete_type("cannot create object with %s type",
491463
qualified_type.type);
492464
set_drgn_error(err);
493-
return -1;
465+
goto err;
494466

495467
}
496468
if (!bit_field_size.is_none && kind != DRGN_OBJECT_SIGNED &&
497469
kind != DRGN_OBJECT_UNSIGNED) {
498470
PyErr_SetString(PyExc_ValueError,
499471
"bit field must be integer");
500-
return -1;
472+
goto err;
501473
}
502474
if (kind != DRGN_OBJECT_BUFFER) {
503475
if (!byteorder.is_none) {
504476
PyErr_SetString(PyExc_ValueError,
505477
"primitive value cannot have byteorder");
506-
return -1;
478+
goto err;
507479
}
508480
if (!bit_offset.is_none) {
509481
PyErr_SetString(PyExc_ValueError,
510482
"primitive value cannot have bit offset");
511-
return -1;
483+
goto err;
512484
}
513485
}
514486

515487
switch (kind) {
516488
case DRGN_OBJECT_BUFFER:
517-
if (buffer_object_from_value(&self->obj, qualified_type,
489+
if (buffer_object_from_value(&obj->obj, qualified_type,
518490
value_obj,
519491
bit_offset.uvalue,
520492
byteorder.value) == -1)
521-
return -1;
493+
goto err;
522494
err = NULL;
523495
break;
524496
case DRGN_OBJECT_SIGNED:
@@ -532,23 +504,23 @@ static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds)
532504
if (!PyNumber_Check(value_obj)) {
533505
set_error_type_name("'%s' value must be number",
534506
qualified_type);
535-
return -1;
507+
goto err;
536508
}
537509
long_obj = PyNumber_Long(value_obj);
538510
if (!long_obj)
539-
return -1;
511+
goto err;
540512
tmp.uvalue = PyLong_AsUnsignedLongLongMask(long_obj);
541513
Py_DECREF(long_obj);
542514
if (tmp.uvalue == (unsigned long long)-1 &&
543515
PyErr_Occurred())
544-
return -1;
516+
goto err;
545517
if (kind == DRGN_OBJECT_SIGNED) {
546-
err = drgn_object_set_signed(&self->obj,
518+
err = drgn_object_set_signed(&obj->obj,
547519
qualified_type,
548520
tmp.svalue,
549521
bit_field_size.uvalue);
550522
} else {
551-
err = drgn_object_set_unsigned(&self->obj,
523+
err = drgn_object_set_unsigned(&obj->obj,
552524
qualified_type,
553525
tmp.uvalue,
554526
bit_field_size.uvalue);
@@ -561,12 +533,12 @@ static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds)
561533
if (!PyNumber_Check(value_obj)) {
562534
set_error_type_name("'%s' value must be number",
563535
qualified_type);
564-
return -1;
536+
goto err;
565537
}
566538
fvalue = PyFloat_AsDouble(value_obj);
567539
if (fvalue == -1.0 && PyErr_Occurred())
568-
return -1;
569-
err = drgn_object_set_float(&self->obj, qualified_type,
540+
goto err;
541+
err = drgn_object_set_float(&obj->obj, qualified_type,
570542
fvalue);
571543
break;
572544
}
@@ -576,13 +548,24 @@ static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds)
576548
} else {
577549
PyErr_SetString(PyExc_ValueError,
578550
"object must have either address or value");
579-
return -1;
551+
goto err;
580552
}
581553
if (err) {
582554
set_drgn_error(err);
583-
return -1;
555+
goto err;
584556
}
585-
return 0;
557+
return obj;
558+
559+
err:
560+
Py_DECREF(obj);
561+
return NULL;
562+
}
563+
564+
static void DrgnObject_dealloc(DrgnObject *self)
565+
{
566+
Py_DECREF(DrgnObject_prog(self));
567+
drgn_object_deinit(&self->obj);
568+
Py_TYPE(self)->tp_free((PyObject *)self);
586569
}
587570

588571
static PyObject *DrgnObject_value_impl(struct drgn_object *obj);
@@ -1743,7 +1726,6 @@ PyTypeObject DrgnObject_type = {
17431726
.tp_iter = (getiterfunc)DrgnObject_iter,
17441727
.tp_methods = DrgnObject_methods,
17451728
.tp_getset = DrgnObject_getset,
1746-
.tp_init = (initproc)DrgnObject_init,
17471729
.tp_new = (newfunc)DrgnObject_new,
17481730
};
17491731

tests/test_object.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,6 @@
4242

4343

4444
class TestInit(ObjectTestCase):
45-
def test_reinit(self):
46-
obj = Object(self.prog, "int", value=1)
47-
self.assertEqual(obj.value_(), 1)
48-
obj.__init__(self.prog, value=2)
49-
self.assertEqual(obj.value_(), 2)
50-
prog = mock_program()
51-
self.assertRaisesRegex(
52-
ValueError, "cannot change object program", obj.__init__, prog, value=3
53-
)
54-
5545
def test_type_stays_alive(self):
5646
obj = Object(self.prog, int_type("int", 4, True), value=0)
5747
self.assertEqual(obj.type_, int_type("int", 4, True))
@@ -80,6 +70,15 @@ def test_address_xor_value(self):
8070
self.prog,
8171
"int",
8272
)
73+
self.assertRaisesRegex(
74+
ValueError,
75+
"object cannot have address and value",
76+
Object,
77+
self.prog,
78+
"int",
79+
0,
80+
address=0,
81+
)
8382
self.assertRaisesRegex(
8483
ValueError,
8584
"object cannot have address and value",
@@ -373,6 +372,9 @@ def test_incomplete(self):
373372

374373

375374
class TestValue(ObjectTestCase):
375+
def test_positional(self):
376+
self.assertEqual(Object(self.prog, "int", 1), Object(self.prog, "int", value=1))
377+
376378
def test_signed(self):
377379
obj = Object(self.prog, "int", value=-4)
378380
self.assertIs(obj.prog_, self.prog)

0 commit comments

Comments
 (0)