diff --git a/.gitignore b/.gitignore index ebeacb3..82a83d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ obj/ *.pyc idapyswitch* +fuzzer/ diff --git a/api_contents2.txt b/api_contents2.txt index 8fc6237..617967e 100644 --- a/api_contents2.txt +++ b/api_contents2.txt @@ -2099,7 +2099,6 @@ 'citem_t_swap', 'cleanup_appcall', 'cleanup_name', - 'clear_bits', 'clear_cached_cfuncs', 'clear_refresh_request', 'clear_requests_queue', @@ -9260,7 +9259,6 @@ 'py_load_custom_icon_data', 'py_load_custom_icon_fn', 'py_register_compiled_form', - 'py_ss_restore_callback', 'py_unregister_compiled_form', 'pycim_get_widget', 'pycim_view_close', @@ -10390,7 +10388,6 @@ 'set_asm_inc_file', 'set_auto_state', 'set_bblk_trace_options', - 'set_bits', 'set_bmask_cmt', 'set_bmask_name', 'set_bpt_group', diff --git a/api_contents3.txt b/api_contents3.txt index b20fc34..dd20e6e 100644 --- a/api_contents3.txt +++ b/api_contents3.txt @@ -2099,7 +2099,6 @@ 'citem_t_swap', 'cleanup_appcall', 'cleanup_name', - 'clear_bits', 'clear_cached_cfuncs', 'clear_refresh_request', 'clear_requests_queue', @@ -9264,7 +9263,6 @@ 'py_load_custom_icon_data', 'py_load_custom_icon_fn', 'py_register_compiled_form', - 'py_ss_restore_callback', 'py_unregister_compiled_form', 'pycim_get_widget', 'pycim_view_close', @@ -10394,7 +10392,6 @@ 'set_asm_inc_file', 'set_auto_state', 'set_bblk_trace_options', - 'set_bits', 'set_bmask_cmt', 'set_bmask_name', 'set_bpt_group', diff --git a/idapython.cpp b/idapython.cpp index db6ecb3..47e856e 100644 --- a/idapython.cpp +++ b/idapython.cpp @@ -1492,7 +1492,7 @@ bool idapython_plugin_t::_extlang_eval_snippet( { PYW_GIL_GET; #ifdef TESTABLE_BUILD - QASSERT(0, PyErr_Occurred() == nullptr); + QASSERT(30639, PyErr_Occurred() == nullptr); #endif PyObject *globals = _get_module_globals(); bool ok; diff --git a/out_of_tree/parsed_notifications.zip b/out_of_tree/parsed_notifications.zip index c300071..01a3a6e 100644 Binary files a/out_of_tree/parsed_notifications.zip and b/out_of_tree/parsed_notifications.zip differ diff --git a/pydoc_injections2.txt b/pydoc_injections2.txt index 6ae8fef..8a0ba1e 100644 --- a/pydoc_injections2.txt +++ b/pydoc_injections2.txt @@ -50411,7 +50411,7 @@ has_insn_feature(*args) has_insn_feature(icode, bit) -> bool Does the specified instruction have the specified feature? - @param icode: (C++: int) + @param icode: (C++: uint16) @param bit: (C++: uint32) Help on function is_align_insn in module ida_idp: @@ -58097,14 +58097,6 @@ py_register_compiled_form(*args) @param py_form: PyObject * -Help on function py_ss_restore_callback in module ida_kernwin: - -py_ss_restore_callback(*args) - py_ss_restore_callback(err_msg, userdata) - - @param err_msg: char const * - @param userdata: void * - Help on function py_unregister_compiled_form in module ida_kernwin: py_unregister_compiled_form(*args) @@ -71436,16 +71428,6 @@ check_process_exit(*args) @retval 1: process has not exited yet @retval -1: error happened, see error code for winerr() in *exit_code -Help on function clear_bits in module ida_pro: - -clear_bits(*args) - clear_bits(bitmap, low, high) - Clear bits between [low, high) in 'bitmap'. - - @param bitmap: (C++: uchar *) - @param low: (C++: size_t) - @param high: (C++: size_t) - Help on class ea_array in module ida_pro: class ea_array(__builtin__.object) @@ -72464,16 +72446,6 @@ sel_pointer_frompointer(*args) @param t: sel_t * -Help on function set_bits in module ida_pro: - -set_bits(*args) - set_bits(bitmap, low, high) - Set bits between [low, high) in 'bitmap'. - - @param bitmap: (C++: uchar *) - @param low: (C++: size_t) - @param high: (C++: size_t) - Help on class sizevec_t in module ida_pro: class sizevec_t(__builtin__.object) diff --git a/pydoc_injections3.txt b/pydoc_injections3.txt index 5c68acd..abbccd3 100644 --- a/pydoc_injections3.txt +++ b/pydoc_injections3.txt @@ -50547,7 +50547,7 @@ has_insn_feature(*args) -> 'bool' has_insn_feature(icode, bit) -> bool Does the specified instruction have the specified feature? - @param icode: (C++: int) + @param icode: (C++: uint16) @param bit: (C++: uint32) Help on function is_align_insn in module ida_idp: @@ -58731,14 +58731,6 @@ py_register_compiled_form(*args) -> 'void' @param py_form: PyObject * -Help on function py_ss_restore_callback in module ida_kernwin: - -py_ss_restore_callback(*args) -> 'void' - py_ss_restore_callback(err_msg, userdata) - - @param err_msg: char const * - @param userdata: void * - Help on function py_unregister_compiled_form in module ida_kernwin: py_unregister_compiled_form(*args) -> 'void' @@ -71911,16 +71903,6 @@ check_process_exit(*args) -> 'int' @retval 1: process has not exited yet @retval -1: error happened, see error code for winerr() in *exit_code -Help on function clear_bits in module ida_pro: - -clear_bits(*args) -> 'void' - clear_bits(bitmap, low, high) - Clear bits between [low, high) in 'bitmap'. - - @param bitmap: (C++: uchar *) - @param low: (C++: size_t) - @param high: (C++: size_t) - Help on class ea_array in module ida_pro: class ea_array(builtins.object) @@ -72920,16 +72902,6 @@ sel_pointer_frompointer(*args) -> 'sel_pointer *' @param t: sel_t * -Help on function set_bits in module ida_pro: - -set_bits(*args) -> 'void' - set_bits(bitmap, low, high) - Set bits between [low, high) in 'bitmap'. - - @param bitmap: (C++: uchar *) - @param low: (C++: size_t) - @param high: (C++: size_t) - Help on class sizevec_t in module ida_pro: class sizevec_t(builtins.object) diff --git a/pywraps/py_expr.hpp b/pywraps/py_expr.hpp index ddde571..e38a3e5 100644 --- a/pywraps/py_expr.hpp +++ b/pywraps/py_expr.hpp @@ -107,7 +107,7 @@ typedef qvector idc_values_t; //------------------------------------------------------------------------- static bool pyw_convert_defvals(idc_values_t *out, PyObject *py_seq) { - if ( !PySequence_Check(py_seq) ) + if ( out == nullptr || !PySequence_Check(py_seq) ) return false; for ( Py_ssize_t i = 0, n = PySequence_Size(py_seq); i < n; ++i ) { diff --git a/pywraps/py_idd.hpp b/pywraps/py_idd.hpp index 556e663..2ceef8f 100644 --- a/pywraps/py_idd.hpp +++ b/pywraps/py_idd.hpp @@ -358,50 +358,56 @@ PyObject *py_appcall( char get_event_module_name(const debug_event_t *ev, char *buf, size_t bufsize) { + if ( ev == nullptr ) + return false; qstrncpy(buf, ev->modinfo().name.c_str(), bufsize); return true; } ea_t get_event_module_base(const debug_event_t *ev) { - return ev->modinfo().base; + return ev != nullptr ? ev->modinfo().base : BADADDR; } asize_t get_event_module_size(const debug_event_t *ev) { - return ev->modinfo().size; + return ev != nullptr ? ev->modinfo().size : 0; } char get_event_exc_info(const debug_event_t *ev, char *buf, size_t bufsize) { + if ( ev == nullptr ) + return false; qstrncpy(buf, ev->exc().info.c_str(), bufsize); return true; } char get_event_info(const debug_event_t *ev, char *buf, size_t bufsize) { + if ( ev == nullptr ) + return false; qstrncpy(buf, ev->info().c_str(), bufsize); return true; } ea_t get_event_bpt_hea(const debug_event_t *ev) { - return ev->bpt().hea; + return ev != nullptr ? ev->bpt().hea : BADADDR; } uint get_event_exc_code(const debug_event_t *ev) { - return ev->exc().code; + return ev != nullptr ? ev->exc().code : 0; } ea_t get_event_exc_ea(const debug_event_t *ev) { - return ev->exc().ea; + return ev != nullptr ? ev->exc().ea : BADADDR; } bool can_exc_continue(const debug_event_t *ev) { - return ev->exc().can_cont; + return ev != nullptr && ev->exc().can_cont; } // diff --git a/pywraps/py_kernwin.hpp b/pywraps/py_kernwin.hpp index 0368076..fc54e25 100644 --- a/pywraps/py_kernwin.hpp +++ b/pywraps/py_kernwin.hpp @@ -22,6 +22,8 @@ struct py_idchotkey_ctx_t static ref_t py_colorizer; +static void py_ss_restore_callback(const char *err_msg, void *userdata); + //------------------------------------------------------------------------ // //------------------------------------------------------------------------ @@ -494,36 +496,6 @@ static PyObject *py_take_database_snapshot(snapshot_t *ss) return Py_BuildValue("(Ns)", PyBool_FromLong(b), err_msg.empty() ? nullptr : err_msg.c_str()); } -//------------------------------------------------------------------------ -static void idaapi py_ss_restore_callback(const char *err_msg, void *userdata) -{ - PYW_GIL_GET; - - // userdata is a tuple of ( func, args ) - // func and args are borrowed references from userdata - - PyObject *o = (PyObject *) userdata; - if ( !PyTuple_Check(o) ) - return; - - PyObject *func = PyTuple_GetItem(o, 0); - PyObject *args = PyTuple_GetItem(o, 1); - - // Create arguments tuple for python function - PyObject *cb_args = Py_BuildValue("(sO)", err_msg, args); - - // Call the python function - newref_t result(PyEval_CallObject(func, cb_args)); - - // Free cb_args and userdata - Py_DECREF(cb_args); - Py_DECREF(o); - - // We cannot raise an exception in the callback, just print it. - if ( result == nullptr ) - PyErr_Print(); -} - //------------------------------------------------------------------------- static PyObject *py_restore_database_snapshot( const snapshot_t *ss, @@ -958,14 +930,18 @@ private: //------------------------------------------------------------------------- bool py_register_action(action_desc_t *desc) { - desc->flags |= ADF_OWN_HANDLER; - bool ok = register_action(*desc); + bool ok = desc != nullptr; if ( ok ) { - // Let's set this to nullptr, so when the wrapping Python action_desc_t - // instance is deleted, it doesn't try to delete the handler (See - // kernwin.i's action_desc_t::~action_desc_t()). - desc->handler = nullptr; + desc->flags |= ADF_OWN_HANDLER; + ok = register_action(*desc); + if ( ok ) + { + // Let's set this to nullptr, so when the wrapping Python action_desc_t + // instance is deleted, it doesn't try to delete the handler (See + // kernwin.i's action_desc_t::~action_desc_t()). + desc->handler = nullptr; + } } return ok; } @@ -1053,6 +1029,11 @@ static PyObject *py_chooser_base_t_get_row( const chooser_base_t *chobj, size_t n) { + if ( chobj == nullptr ) + { + PyErr_SetString(PyExc_ValueError, "A valid chooser_base_t pointer is expected as first argument"); + return nullptr; + } qstrvec_t fields; fields.resize(chobj->columns); chooser_item_attrs_t *attrs = new chooser_item_attrs_t; @@ -1266,14 +1247,23 @@ static TWidget *TWidget__from_ptrval__(size_t ptrval) return (TWidget *) ptrval; } +// we limit the the number of spaces that can be added to 512k +#define MAX_SPACES_ADDED 524288 //------------------------------------------------------------------------- static PyObject *py_add_spaces(const char *s, size_t len) { qstring qbuf(s); const size_t slen = tag_strlen(qbuf.c_str()); - const size_t delta = qbuf.length() - slen; - if ( len > slen ) - qbuf.resize(len + delta); + const size_t nlen = qbuf.length() - slen + len; + if ( len > slen && nlen < MAX_SPACES_ADDED ) + { + qbuf.resize(nlen); + } + else + { + if ( s == nullptr ) + qbuf.resize(1); + } // we use the actual 'size' because we know that // 'add_spaces()' will add a terminating zero anyway add_spaces(qbuf.begin(), qbuf.size(), len); @@ -1345,6 +1335,36 @@ static void ida_kernwin_term(void) //------------------------------------------------------------------------- static void ida_kernwin_closebase(void) {} +//------------------------------------------------------------------------ +static void py_ss_restore_callback(const char *err_msg, void *userdata) +{ + PYW_GIL_GET; + + // userdata is a tuple of ( func, args ) + // func and args are borrowed references from userdata + + PyObject *o = (PyObject *) userdata; + if ( o == nullptr || !PyTuple_Check(o) ) + return; + + PyObject *func = PyTuple_GetItem(o, 0); + PyObject *args = PyTuple_GetItem(o, 1); + + // Create arguments tuple for python function + PyObject *cb_args = Py_BuildValue("(sO)", err_msg, args); + + // Call the python function + newref_t result(PyEval_CallObject(func, cb_args)); + + // Free cb_args and userdata + Py_DECREF(cb_args); + Py_DECREF(o); + + // We cannot raise an exception in the callback, just print it. + if ( result == nullptr ) + PyErr_Print(); +} + /* # def get_navband_pixel(ea): diff --git a/pywraps/py_loader.hpp b/pywraps/py_loader.hpp index 6eddeac..275cb52 100644 --- a/pywraps/py_loader.hpp +++ b/pywraps/py_loader.hpp @@ -103,14 +103,18 @@ static bool py_load_and_run_plugin(const char *name, size_t arg) //------------------------------------------------------------------------- static PyObject *py_extract_module_from_archive(const char *fname, bool is_remote=false) { + bool ok = fname != nullptr; char *temp_file_ptr = nullptr; char fname_buf[QMAXPATH]; - qstrncpy(fname_buf, fname, sizeof(fname_buf)); - bool ok = extract_module_from_archive( - fname_buf, - sizeof(fname_buf), - &temp_file_ptr, - is_remote); + if ( ok ) + { + qstrncpy(fname_buf, fname, sizeof(fname_buf)); + ok = extract_module_from_archive( + fname_buf, + sizeof(fname_buf), + &temp_file_ptr, + is_remote); + } return Py_BuildValue("(ss)", ok ? fname_buf : nullptr, ok ? temp_file_ptr : nullptr); } diff --git a/release_api_contents2.txt b/release_api_contents2.txt index 91e8c7d..ed7aa9b 100644 --- a/release_api_contents2.txt +++ b/release_api_contents2.txt @@ -2096,7 +2096,6 @@ 'citem_t_swap', 'cleanup_appcall', 'cleanup_name', - 'clear_bits', 'clear_cached_cfuncs', 'clear_refresh_request', 'clear_requests_queue', @@ -8671,7 +8670,6 @@ 'py_load_custom_icon_data', 'py_load_custom_icon_fn', 'py_register_compiled_form', - 'py_ss_restore_callback', 'py_unregister_compiled_form', 'pycim_get_widget', 'pycim_view_close', @@ -9795,7 +9793,6 @@ 'set_asm_inc_file', 'set_auto_state', 'set_bblk_trace_options', - 'set_bits', 'set_bmask_cmt', 'set_bmask_name', 'set_bpt_group', diff --git a/release_api_contents3.txt b/release_api_contents3.txt index c676c77..8140785 100644 --- a/release_api_contents3.txt +++ b/release_api_contents3.txt @@ -2096,7 +2096,6 @@ 'citem_t_swap', 'cleanup_appcall', 'cleanup_name', - 'clear_bits', 'clear_cached_cfuncs', 'clear_refresh_request', 'clear_requests_queue', @@ -8675,7 +8674,6 @@ 'py_load_custom_icon_data', 'py_load_custom_icon_fn', 'py_register_compiled_form', - 'py_ss_restore_callback', 'py_unregister_compiled_form', 'pycim_get_widget', 'pycim_view_close', @@ -9799,7 +9797,6 @@ 'set_asm_inc_file', 'set_auto_state', 'set_bblk_trace_options', - 'set_bits', 'set_bmask_cmt', 'set_bmask_name', 'set_bpt_group', diff --git a/release_pydoc_injections2.txt b/release_pydoc_injections2.txt index 20c3c7f..fc1104d 100644 --- a/release_pydoc_injections2.txt +++ b/release_pydoc_injections2.txt @@ -50372,7 +50372,7 @@ has_insn_feature(*args) has_insn_feature(icode, bit) -> bool Does the specified instruction have the specified feature? - @param icode: (C++: int) + @param icode: (C++: uint16) @param bit: (C++: uint32) Help on function is_align_insn in module ida_idp: @@ -58033,14 +58033,6 @@ py_register_compiled_form(*args) @param py_form: PyObject * -Help on function py_ss_restore_callback in module ida_kernwin: - -py_ss_restore_callback(*args) - py_ss_restore_callback(err_msg, userdata) - - @param err_msg: char const * - @param userdata: void * - Help on function py_unregister_compiled_form in module ida_kernwin: py_unregister_compiled_form(*args) @@ -67701,16 +67693,6 @@ check_process_exit(*args) @retval 1: process has not exited yet @retval -1: error happened, see error code for winerr() in *exit_code -Help on function clear_bits in module ida_pro: - -clear_bits(*args) - clear_bits(bitmap, low, high) - Clear bits between [low, high) in 'bitmap'. - - @param bitmap: (C++: uchar *) - @param low: (C++: size_t) - @param high: (C++: size_t) - Help on class ea_array in module ida_pro: class ea_array(__builtin__.object) @@ -68729,16 +68711,6 @@ sel_pointer_frompointer(*args) @param t: sel_t * -Help on function set_bits in module ida_pro: - -set_bits(*args) - set_bits(bitmap, low, high) - Set bits between [low, high) in 'bitmap'. - - @param bitmap: (C++: uchar *) - @param low: (C++: size_t) - @param high: (C++: size_t) - Help on class sizevec_t in module ida_pro: class sizevec_t(__builtin__.object) diff --git a/release_pydoc_injections3.txt b/release_pydoc_injections3.txt index faae0cd..9b641e3 100644 --- a/release_pydoc_injections3.txt +++ b/release_pydoc_injections3.txt @@ -50508,7 +50508,7 @@ has_insn_feature(*args) -> 'bool' has_insn_feature(icode, bit) -> bool Does the specified instruction have the specified feature? - @param icode: (C++: int) + @param icode: (C++: uint16) @param bit: (C++: uint32) Help on function is_align_insn in module ida_idp: @@ -58667,14 +58667,6 @@ py_register_compiled_form(*args) -> 'void' @param py_form: PyObject * -Help on function py_ss_restore_callback in module ida_kernwin: - -py_ss_restore_callback(*args) -> 'void' - py_ss_restore_callback(err_msg, userdata) - - @param err_msg: char const * - @param userdata: void * - Help on function py_unregister_compiled_form in module ida_kernwin: py_unregister_compiled_form(*args) -> 'void' @@ -68303,16 +68295,6 @@ check_process_exit(*args) -> 'int' @retval 1: process has not exited yet @retval -1: error happened, see error code for winerr() in *exit_code -Help on function clear_bits in module ida_pro: - -clear_bits(*args) -> 'void' - clear_bits(bitmap, low, high) - Clear bits between [low, high) in 'bitmap'. - - @param bitmap: (C++: uchar *) - @param low: (C++: size_t) - @param high: (C++: size_t) - Help on class ea_array in module ida_pro: class ea_array(builtins.object) @@ -69312,16 +69294,6 @@ sel_pointer_frompointer(*args) -> 'sel_pointer *' @param t: sel_t * -Help on function set_bits in module ida_pro: - -set_bits(*args) -> 'void' - set_bits(bitmap, low, high) - Set bits between [low, high) in 'bitmap'. - - @param bitmap: (C++: uchar *) - @param low: (C++: size_t) - @param high: (C++: size_t) - Help on class sizevec_t in module ida_pro: class sizevec_t(builtins.object) diff --git a/swig/pro.i b/swig/pro.i index 599be6d..10c4c1d 100644 --- a/swig/pro.i +++ b/swig/pro.i @@ -39,6 +39,13 @@ %ignore unpack_memory; %ignore cliopt_t; %ignore cliopts_t; +%ignore test_bit; +%ignore set_bit; +%ignore set_bits; +%ignore clear_bit; +%ignore clear_bits; +%ignore set_all_bits; +%ignore clear_all_bits; %extend qrefcnt_t { size_t __ptrval__() const diff --git a/tools/deploy/header.i.in b/tools/deploy/header.i.in index 5bf964e..601934c 100644 --- a/tools/deploy/header.i.in +++ b/tools/deploy/header.i.in @@ -167,11 +167,6 @@ extern plugin_t PLUGIN; %ignore set_codepages; %ignore get_codepages; %ignore convert_codepage; -%ignore test_bit; -%ignore set_bit; -%ignore clear_bit; -%ignore set_all_bits; -%ignore clear_all_bits; %ignore interval::last; %ignore interval::overlap; %ignore interval::includes; @@ -374,6 +369,7 @@ class QLIST_TYPE##_iterator {}; %exception { try { + set_interr_throws_t sit; $action } catch ( const std::bad_alloc &ba ) { __raise_ba(ba); SWIG_fail; } @@ -1748,6 +1744,16 @@ SWIGINTERN void __raise_e(const std::exception &e) } } +// a setter for the 'interr_should_throw' flag. Since that flag has to be set, +// or reset possibly in the context of stack unwinding, let's leave it up to +// the compiler to make sure that it's reset as it should be using RAII. +struct set_interr_throws_t +{ + bool was; + set_interr_throws_t() { was = interr_should_throw; interr_should_throw = true; } + ~set_interr_throws_t() { interr_should_throw = was; } +}; + SWIGINTERN void __raise_ie(const interr_exc_t &ie) { qstring emsg;