Ida_loader.save_database() is broken as it is right now

According to The official Python docs

The prototype for save_database is:

def save_database(outfile: str=None, flags: int=-1, root: 'snapshot_t'=None,
    attr: 'snapshot_t'=None) ->bool:
    """Save current database using a new file name. 
        
:param outfile: output database file name; nullptr means the current path
:param flags: Database flags; -1 means the current flags
:param root: optional: snapshot tree root.
:param attr: optional: snapshot attributes
:returns: success"""
    return _ida_loader.save_database(outfile, flags, root, attr)

However, one cannot call it:

TypeError                                 Traceback (most recent call last)
Cell In[7], line 1
----> 1 ida_loader.save_database()

File <retracted>\ida_loader.py:715, in save_database(outfile, flags, root, attr)
    706 def save_database(outfile: str=None, flags: int=-1, root: 'snapshot_t'=None,
    707     attr: 'snapshot_t'=None) ->bool:
    708     """Save current database using a new file name. 
    709         
    710 :param outfile: output database file name; nullptr means the current path
   (...)
    713 :param attr: optional: snapshot attributes
    714 :returns: success"""
--> 715     return _ida_loader.save_database(outfile, flags, root, attr)

TypeError: Wrong number or type of arguments for overloaded function 'save_database'.
  Possible C/C++ prototypes are:
    save_database(char const *,uint32,snapshot_t const *,snapshot_t const *)
    save_database(char const *,uint32,snapshot_t const *)
    save_database(char const *,uint32)
    save_database(char const *)
    save_database()

The second argument is not int, it is uint32

Hi, thanks for the report! We’ll check why these calls aren’t working and follow up once we have more updates.

Hi @Harding,

Indeed, the save_database() and save_database(char const *) are both unusable due to negative default value. One of these C++ vs Python inconsistencies that fell through the cracks.

Let me fix this upstream and make it available with the next release.

Until then, if you need the equivalent of idaapi.save_database(), you can use the following line:

idaapi.save_database(idaapi.get_path(idaapi.PATH_TYPE_IDB), 0)

Good you get it fixed. I have already made a “fix” for it by using ida_idaapi.as_uint32 as you can see here:

1 Like

Nice, I see!

My fix changes the default to 0 instead of -1, but the functionality stays the same. Glad you found a way to work around.

1 Like

Sorry to necro this thread but the save_database still works kinda wonkly.

If calling it with an empty string

ida_loader.save_database("")

I get the following unreadable popup:

And if I click the X in the top right corner the function returns True and I get the log line:

Leaving database unpacked and packed copy in .$$$ and there is a file created named .$$$ in the working dir.

Hi @Harding,

Reports are always welcome, there’s no such thing as “necro-ing” the thread here.

The first parameter of save_database() is outfile, which can represent the name of the new database file, or the current database in case outfile is None (or nullptr in C++). Passing an empty string fails because "” will be interpreted as a file name.

We could catch that earlier and show a better error explanation. Would that work for you as the expected outcome, or do you have a particular reason for passing an empty string?

The short answer is that I have a wrapper around it and I have the type str and used the empty string to signal the same as you do with a nullptr. That’s how I found the error and even if I can change it (I added a check as you can see here: community_base/community_base.py at b5f727c122b1b520c68e01bd8f6793d2c7ce5064 · Harding-Stardust/community_base · GitHub ) but I wanted to let the empty string fall through.

So the bug is minor and it was just a strange error message that also created an unwanted file that I wanted to report. You can use None or empty string as the signal to “use the normal IDB path”, it doesn’t really matter.

1 Like