Skip to content

bpo-31746: Fixed Segfaults in the sqlite module when uninitialized. #3946

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from

Conversation

lielfr
Copy link

@lielfr lielfr commented Oct 10, 2017

@the-knights-who-say-ni
Copy link

Hello, and thanks for your contribution!

I'm a bot set up to make sure that the project can legally accept your contribution by verifying you have signed the PSF contributor agreement (CLA).

Unfortunately we couldn't find an account corresponding to your GitHub username on bugs.python.org (b.p.o) to verify you have signed the CLA (this might be simply due to a missing "GitHub Name" entry in your b.p.o account settings). This is necessary for legal reasons before we can look at your contribution. Please follow the steps outlined in the CPython devguide to rectify this issue.

Thanks again to your contribution and we look forward to looking at it!

@orenmn
Copy link
Contributor

orenmn commented Oct 11, 2017

Oh, i was in the middle of writing my patch, but i guess you beat me to it :)

Anyway, IMHO we should add tests to verify that the crashes we know about don't happen anymore. (i am not sure, but Lib/sqlite3/test/regression.py looks like the right place.)

Also, i think that setting self->initialized to 1 in the beginning of pysqlite_connection_init() is something that could causes more problems when pysqlite_connection_init() fails in the middle, and leaves the Connection object partially initialized but marked as initialized.

BTW, i applied your patch, and calling close() on an uninitialized Connection object still crashes on my Windows 10.

def CheckUninitializedIsolationLevel(self):
"""
Previously trying to get the isolation level of an uninitialized Connection
caused a segfault, now it should just return None.
Copy link
Contributor

Choose a reason for hiding this comment

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

Other getters raise a ProgrammingError when they are called on an uninitialized Connection object.
IMHO this should be the same here.

@brettcannon brettcannon added the type-bug An unexpected behavior, bug, or error label Mar 29, 2019
@brettcannon brettcannon reopened this Mar 29, 2019
@csabella
Copy link
Contributor

@lielfr, please fix the merge conflicts and, if you've addressed all the review comments, please mark them with the 'Resolve conversation' button. Thanks!

@lielfr
Copy link
Author

lielfr commented Jun 3, 2019

Hi @csabella, thanks for letting me know. I just thought the issue was fixed by @orenmn.

@csabella
Copy link
Contributor

csabella commented Jun 3, 2019

@lielfr, I don't see where @orenmn worked on this issue. Since this pull request had had some activity, I was trying to move it forward by making sure the reviews had been addressed. Can you point out where @orenmn's changes are? Thanks!

@lielfr
Copy link
Author

lielfr commented Jun 3, 2019

Well, PRs #3958 and #3968 seem to fix some of the issues. The testing code still crashes for some reason, so I'm going to fix that.

@csabella
Copy link
Contributor

csabella commented Jun 3, 2019

@lielfr - thank you for pointing those out. They were different issues on the bug tracker, so I didn't think the fix to one fixed the other (one was for cursors and one was for connections). Anyway, that would be great if you could take a look to see if this connection issue still happens and to fix those test issues you mentioned. Thank you for working on this! :-)

@lielfr
Copy link
Author

lielfr commented Jul 2, 2019

Hi @csabella, It seems that this pr doesn't receive any attention from the maintainers. Should it just be left like that, or would you recommend reaching out to someone? Thanks again

@csabella csabella requested a review from berkerpeksag July 2, 2019 14:28
Copy link
Contributor

@erlend-aasland erlend-aasland left a comment

Choose a reason for hiding this comment

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

Please fix the PEP 7 issues. Also, the tests are now missing. Could you rebase onto master and add them again?

@lielfr
Copy link
Author

lielfr commented Apr 28, 2021

Sorry for the delay. Will fix this now.

@erlend-aasland
Copy link
Contributor

Sorry for the delay. Will fix this now.

Great, there's no hurry :) Thank you!

@lielfr
Copy link
Author

lielfr commented Apr 28, 2021

Should be done. I'll be happy to fix other issues if there are any.

Comment on lines +299 to +303
if (self == NULL) {
return NULL;
}

static char *kwlist[] = {"factory", NULL};
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not needed if self->initialized is only set if pysqlite_connection_init was successful. Also, it looks like the rebase left some artifacts :)

Comment on lines +346 to +351

if (!self->statements) {
PyErr_SetString(pysqlite_ProgrammingError,
"Base Connection.__init__ not called.");
return NULL;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't it be better to handle this in pysqlite_do_all_statements, as it has multiple callers? Perhaps pysqlite_do_all_statements could be split in two: do_all_statements and do_all_cursors. Each of them would do a pointer sanity check before looping.

Copy link
Author

Choose a reason for hiding this comment

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

Are you sure about splitting pysqlite_do_all_statements into two functions? It seems like it always performs the statements part, but optionally also performs the cursors part.

Copy link
Contributor

Choose a reason for hiding this comment

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

No, I'm not sure :) Let's leave it as it is; both pysqlite_do_all_statements and this particular change.

Nit: if (self->statements == NULL) is more explicit, and I believe more consistent with the rest of the code base.

Comment on lines +1254 to +1258
if (!self || !self->isolation_level) {
PyErr_Format(pysqlite_ProgrammingError,
"Object is null or isolation_level is uninitialized.");
return 0;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

If self->initialized is only set if pysqlite_connection_init was successful, this can be reduced to:

Suggested change
if (!self || !self->isolation_level) {
PyErr_Format(pysqlite_ProgrammingError,
"Object is null or isolation_level is uninitialized.");
return 0;
}
if (!pysqlite_check_connection(self)) {
return NULL;
}

@erlend-aasland
Copy link
Contributor

Closing, since #27431 is now merged. Thank you for your PR, and interest in improving CPython!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting core review skip news type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants