Skip to content

Conversation

@picnixz
Copy link
Member

@picnixz picnixz commented Dec 27, 2025

FTR, the reason why execute is actually not affected is that the iterator we are taking is built from a list we create ourselves so it's not possible to have "bad" side effects.

@picnixz picnixz added needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes labels Dec 27, 2025
@picnixz picnixz changed the title gh-143198: fix SIGSEGV in sqlite3.execute[many] with re-entrant parameter iterator gh-143198: fix SIGSEGV in sqlite3.execute[many] with concurrent mutations Dec 27, 2025
@picnixz picnixz marked this pull request as draft December 27, 2025 15:19
@picnixz picnixz changed the title gh-143198: fix SIGSEGV in sqlite3.execute[many] with concurrent mutations gh-143198: fix SIGSEGV in sqlite3.executemany with concurrent mutations Dec 27, 2025
@picnixz picnixz marked this pull request as ready for review December 27, 2025 16:42
@picnixz
Copy link
Member Author

picnixz commented Dec 29, 2025

There were more UAFs that I could find...

@picnixz picnixz changed the title gh-143198: fix SIGSEGV in sqlite3.executemany with concurrent mutations gh-143198: fix some crashes in sqlite3.executemany with concurrent mutations Dec 29, 2025

// PyObject_GetIter() may have a side-effect on the connection's state.
// See: https://github.com/python/cpython/issues/143198.
if (!pysqlite_check_connection(self->connection)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of checking after functions which can allow closing the connection, why not test immediately before the code that implies the connection is alive and would crash otherwise? For example, setting self->description looks safe, but reading self->connection->state is not.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I had in mind but that forces me to pass the connection around. I'm fine with this approach though. I expect the diff to also be larger. And I think it's also time to split the implementation of execute and executemany because execute doesn't need a loop, and does not always need some checks. OTOH, executemany() don't need part of the execute() logic.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I planned to split them long time ago, but it had very low priority.

There is a risk that we will introduce other point that executes an arbitrary Python code or releases the GIL between the last check and the use which can crash. So we should keep them as close one to other as possible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am currently splitting them actually. It's just about extracting part of the functions into separate functions so there should not be any surprises.


// PyObject_GetIter() may have a side-effect on the connection's state.
// See: https://github.com/python/cpython/issues/143198.
if (!pysqlite_check_connection(self->connection)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I planned to split them long time ago, but it had very low priority.

There is a risk that we will introduce other point that executes an arbitrary Python code or releases the GIL between the last check and the use which can crash. So we should keep them as close one to other as possible.

return iter([(1,), (2,), (3,)])


class ParamsCxCloseInNext(CxWrapper):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cannot we simply use local generator functions?

def ParamsCxCloseInNext():
    for i in range(5):
        cx.close()
        yield (i,)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmh, it can be easier yes, let me check if I can do it that way.

@picnixz
Copy link
Member Author

picnixz commented Dec 29, 2025

@serhiy-storchaka So the split went well but... it's now a larger code =/ I also changed some variable names since we're talking about parameters everywhere but it's more arguments in this case or values. I can revert the change if you want (I'll make a commit for reverting and then we can decide whether to keep the revert or not) but I wanted to show you how it would be if the implementations are separate.

@picnixz
Copy link
Member Author

picnixz commented Dec 29, 2025

I feel that there are a lot of tests that are really looking-alike. It's kinda annoying to have redundancy... and it won't get any better with the other PRs for sqlite where we I need to test the callbacks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting merge needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants