diff --git a/CHANGELOG.md b/CHANGELOG.md index c08b867..6053c48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `CHANGELOG.md` - Add markdown linter to CI +### Fixed + +- Fix passing `None` to `RegistersTracker.processLui` + ## [1.7.9] - 2023-09-18 ### Changed diff --git a/docs/usage_c_api.md b/docs/usage_c_api.md index 3cfcb03..33c2151 100644 --- a/docs/usage_c_api.md +++ b/docs/usage_c_api.md @@ -73,11 +73,11 @@ Let's break up the example and explain each part: To initialize our `instr` we need to call the pair `RabbitizerInstruction_init` and `RabbitizerInstruction_processUniqueId`. `RabbitizerInstruction_init` initialises all the members of the struct so it doesn't contain garbage data - anymore, while `RabbitizerInstruction_processUniqueId` does the heavy lifting of - identifying the actual instruction id out of the `word` we passed. + anymore, while `RabbitizerInstruction_processUniqueId` does the heavy lifting + of identifying the actual instruction id out of the `word` we passed. - A `RabbitizerInstruction` variable is not considered fully initialized until it - has been passed to this pair of functions. + A `RabbitizerInstruction` variable is not considered fully initialized until + it has been passed to this pair of functions. ```c RabbitizerInstruction_init(&instr, word, vram); diff --git a/rabbitizer/rabbitizer_module.h b/rabbitizer/rabbitizer_module.h index 2800ff5..d11b8bd 100644 --- a/rabbitizer/rabbitizer_module.h +++ b/rabbitizer/rabbitizer_module.h @@ -44,6 +44,11 @@ extern PyTypeObject rabbitizer_type_LoPairingInfo_TypeObject; extern PyTypeObject rabbitizer_type_TrackedRegisterState_TypeObject; extern PyTypeObject rabbitizer_type_RegistersTracker_TypeObject; +int rabbitizer_type_Instruction_TypeObject_Check(PyObject *o); + +int rabbitizer_converter_InstructionOrNone(PyObject *object, PyRabbitizerInstruction **address); + + DECL_ENUM(Abi) DECL_ENUM(InstrCategory) DECL_ENUM(InstrId) diff --git a/rabbitizer/rabbitizer_type_Instruction.c b/rabbitizer/rabbitizer_type_Instruction.c index 967cc16..c324875 100644 --- a/rabbitizer/rabbitizer_type_Instruction.c +++ b/rabbitizer/rabbitizer_type_Instruction.c @@ -671,6 +671,57 @@ static PyObject *rabbitizer_type_Instruction_str(PyRabbitizerInstruction *self) return rabbitizer_type_Instruction_disassemble(self, Py_BuildValue("()"), Py_BuildValue("{}")); } +/** + * Returns: + * - 1 if `o` is an RabbitizerInstruction + * - 0 if not an instance of RabbitizerInstruction + * - -1 if an error occurred + */ +int rabbitizer_type_Instruction_TypeObject_Check(PyObject *o) { + int isInstance = PyObject_IsInstance(o, (PyObject*)&rabbitizer_type_Instruction_TypeObject); + + if (isInstance < 0) { + /* An error happened */ + /* PyObject_IsInstance already sets an exception, so nothing else to do here */ + return -1; + } + + if (isInstance == 0) { + /* `o` isn't an instance of RabbitizerInstruction */ + return 0; + } + + return 1; +} + + +int rabbitizer_converter_InstructionOrNone(PyObject *object, PyRabbitizerInstruction **address) { + int instanceCheck; + + if ((object == NULL) || (address == NULL)) { + PyErr_Format(PyExc_RuntimeError, "%s: Internal error", __func__); + return 0; // fail + } + + if (object == Py_None) { + *address = NULL; + return 1; // successful + } + + instanceCheck = rabbitizer_type_Instruction_TypeObject_Check(object); + if (instanceCheck < 0) { + return 0; // fail + } + if (instanceCheck > 0) { + *address = (PyRabbitizerInstruction*)object; + return 1; // successful + } + + // TypeError: argument 3 must be rabbitizer.Instruction, not None + PyErr_Format(PyExc_TypeError, "argument must be %s or None, not %s", rabbitizer_type_Instruction_TypeObject.tp_name, object->ob_type->tp_name); + return 0; // fail +} + PyTypeObject rabbitizer_type_Instruction_TypeObject = { PyVarObject_HEAD_INIT(NULL, 0) diff --git a/rabbitizer/rabbitizer_type_RegistersTracker.c b/rabbitizer/rabbitizer_type_RegistersTracker.c index 485ef05..539259e 100644 --- a/rabbitizer/rabbitizer_type_RegistersTracker.c +++ b/rabbitizer/rabbitizer_type_RegistersTracker.c @@ -11,7 +11,6 @@ typedef struct PyRabbitizerRegistersTracker { RabbitizerRegistersTracker tracker; } PyRabbitizerRegistersTracker; - static void rabbitizer_type_RegistersTracker_dealloc(PyRabbitizerRegistersTracker *self) { RabbitizerRegistersTracker_destroy(&self->tracker); Py_TYPE(self)->tp_free((PyObject *) self); @@ -119,7 +118,7 @@ static PyObject *rabbitizer_type_RegistersTracker_processLui(PyRabbitizerRegiste PyRabbitizerInstruction *pyPrevInstr = NULL; RabbitizerInstruction *prevInstr = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!i|O!", kwlist, &rabbitizer_type_Instruction_TypeObject, &instr, &instrOffset, &rabbitizer_type_Instruction_TypeObject, &pyPrevInstr)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!i|O&", kwlist, &rabbitizer_type_Instruction_TypeObject, &instr, &instrOffset, rabbitizer_converter_InstructionOrNone, &pyPrevInstr)) { return NULL; }