FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

[backport to 3.5] bpo-29438: Fixed use-after-free in key sharing dict by methane · Pull Request #40 · python/cpython · GitHub

Repository navigation

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .c  (1) No extension  (1) All 2 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
2 changes: 2 additions & 0 deletions Misc/NEWS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Release date: XXXX-XX-XX
Core and Builtins
-----------------

- bpo-29438: Fixed use-after-free problem in key sharing dict.

- Issue #29319: Prevent RunMainFromImporter overwriting sys.path[0].

- Issue #29337: Fixed possible BytesWarning when compare the code objects.
Expand Down
10 changes: 4 additions & 6 deletions Objects/dictobject.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -3893,20 +3893,18 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr,
}
if (value == NULL) {
res = PyDict_DelItem(dict, key);
if (cached != ((PyDictObject *)dict)->ma_keys) {
CACHED_KEYS(tp) = NULL;
DK_DECREF(cached);
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Why these lines are deleted?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

In Python 3.5, PyDict_DelItem won't resize dict. So cached == dict->ma_keys in most cases.

One exception is callback called by weakref or __del__ inserts some items to the dict and resize happened.
In this case, cached != CACHED_KEYS(tp), so DK_DECREF(cached) will be "use-after-free".

In such case, the insertion from the callback would update CACHED_KEYS(tp) correctly.
So clearing CACHED_KEYS(tp) doesn't make sense for most case.

Even when the callback inserts items through __dict__ (not regular attribute access), skipping CACHED_KEYS(tp) = NULL
doesn't cause uncontrolled memory growth. And it happens very rarely.
So I think this code is not worth enough.

else {
int was_shared = cached == ((PyDictObject *)dict)->ma_keys;
int was_shared = (cached == ((PyDictObject *)dict)->ma_keys);
res = PyDict_SetItem(dict, key, value);
/* PyDict_SetItem() may call dictresize() and convert split table
* into combined table. In such case, convert it to split
* table again and update type's shared key only when this is
* the only dict sharing key with the type.
*/
if (was_shared && cached != ((PyDictObject *)dict)->ma_keys) {
if (was_shared &&
(cached = CACHED_KEYS(tp)) != NULL &&
cached != ((PyDictObject *)dict)->ma_keys) {
if (cached->dk_refcnt == 1) {
CACHED_KEYS(tp) = make_keys_shared(dict);
} else {
Expand Down

Back | FazBrowse Home | New Git URL