Skip to content

Add some gc safety around _mysql__fetch_row #348

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

Merged
merged 3 commits into from
Feb 5, 2020
Merged

Conversation

fried
Copy link
Contributor

@fried fried commented Mar 21, 2019

Users of gc.get_referrers() could cause a SystemError to be raised if this function is running in a different python thread.

We ended up doing this at Facebook just to be safe, because it was really hard figuring out that it was not a _mysql issue but usage of gc.get_referrers() in a multi-threaded environment. but I understand if you don't feel its needed.

Users of gc.get_referrers() could cause a SystemError to be raised if this function is running in a different python thread.
@codecov
Copy link

codecov bot commented Mar 21, 2019

Codecov Report

❗ No coverage uploaded for pull request base (master@e04c597). Click here to learn what that means.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff            @@
##             master     #348   +/-   ##
=========================================
  Coverage          ?   86.59%           
=========================================
  Files             ?       12           
  Lines             ?     1537           
  Branches          ?        0           
=========================================
  Hits              ?     1331           
  Misses            ?      206           
  Partials          ?        0           
Impacted Files Coverage Δ
MySQLdb/constants/ER.py 97.05% <0.00%> (ø)
MySQLdb/constants/FIELD_TYPE.py 100.00% <0.00%> (ø)
MySQLdb/converters.py 82.35% <0.00%> (ø)
MySQLdb/__init__.py 81.81% <0.00%> (ø)
MySQLdb/constants/__init__.py 100.00% <0.00%> (ø)
MySQLdb/times.py 100.00% <0.00%> (ø)
MySQLdb/_exceptions.py 100.00% <0.00%> (ø)
MySQLdb/constants/FLAG.py 100.00% <0.00%> (ø)
MySQLdb/cursors.py 80.93% <0.00%> (ø)
MySQLdb/constants/CR.py 0.00% <0.00%> (ø)
... and 2 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e04c597...1ec1aa7. Read the comment docs.

@fried fried closed this Mar 22, 2019
@fried fried deleted the patch-1 branch March 22, 2019 23:16
@fried fried restored the patch-1 branch March 22, 2019 23:28
@fried fried reopened this Mar 22, 2019
@methane
Copy link
Member

methane commented Mar 23, 2019

Please detailed information about why and how gc.get_referrers() is broken.

@fried
Copy link
Contributor Author

fried commented Mar 25, 2019

gc.get_referrers is not broken per say, its just not safe in a multi threaded environment when c-api is used.

We added this deflect concerns that _mysql.c was broken or python itself had a bug, when the behavior of gc module is well known and not considered a bug by the python core devs.

@methane
Copy link
Member

methane commented Mar 25, 2019

I said "detailed information"!

I don't understand the problem you're saying yet. Only information I got is it's SystemError.
You don't provide error message, etc.

I don't want merge such code without understanding.

@methane
Copy link
Member

methane commented Mar 25, 2019

and not considered a bug by the python core devs.

Link to bugs.python.org issue.

@fried
Copy link
Contributor Author

fried commented Mar 26, 2019

  File "MySQLdb/cursors.py", line 203, in execute

SystemError: Objects/tupleobject.c:854: bad argument to internal function

Not that its very useful

@methane
Copy link
Member

methane commented Mar 26, 2019

Not that its very useful

It's very important information. What is your exact Python version?

@methane
Copy link
Member

methane commented Mar 26, 2019

OK, I understand the error is from _PyTuple_Resize().

It is a dirty part of MySQLdb I dislike.
Rows should be list instead of tuple, but I couldn't change it for Django compatibility...

Anyway, thank you for reporting the issue, while I don't like this change.

MySQLdb/_mysql.c Outdated
// This function can get a reference to the tuple r, and if that
// code is preempted while holding a ref to r, the _PyTuple_Resize
// will raise a SystemError because the ref count is 2.
PyObject_GC_UnTrack(*r);
Copy link
Member

Choose a reason for hiding this comment

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

Move these code to _mysql_ResultObject_fetch_row.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

its pretty safe everywhere else we do it in the dangerous area where we allow threads.

Copy link
Member

Choose a reason for hiding this comment

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

It is safe untrack soon after creatin, and track again after _PyTuple_Resize().

Copy link
Member

Choose a reason for hiding this comment

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

For example, convert_row may execute Python code.
Execute python code means it allows threads switching, Calling gc module, etc.

Py_BEGIN_ALLOW_THREADS is not the only danger API. There are many danger APIs
which can execute any Python code. e.g. Py_DECREF, PyObject_RichCompareBool,
PyList_Append, etc.

Copy link
Member

Choose a reason for hiding this comment

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

ping?

@PyMySQL PyMySQL deleted a comment from codecov bot Jul 31, 2019
@methane methane added this to the v2.0 milestone Nov 18, 2019
@methane methane merged commit c67dbd4 into PyMySQL:master Feb 5, 2020
@methane methane mentioned this pull request Jul 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants