Skip to content

bpo-41531: Fix compilation of dict literals with more than 0xFFFF elements #21850

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 1 commit into from
Aug 13, 2020

Conversation

pablogsal
Copy link
Member

@pablogsal pablogsal commented Aug 12, 2020

if (elements == 0xFFFF) {
if (!compiler_subdict(c, e, i - elements, i)) {
if (elements == USHRT_MAX) {
if (!compiler_subdict(c, e, i - elements, i + 1)) {
Copy link
Member Author

@pablogsal pablogsal Aug 12, 2020

Choose a reason for hiding this comment

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

I just made the minimum edit to fix the problem but I would just remove this checkpoint and simply keep incrementing elements and leave the last check fill the dict, which is simpler and less error prone. Any reason we want to flush when we are in USHRT_MAX elements @markshannon ?

To be clear, this is what I propose:

diff --git a/Python/compile.c b/Python/compile.c
index b2beef9327..a348b13676 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -3893,19 +3893,7 @@ compiler_dict(struct compiler *c, expr_ty e)
             ADDOP_I(c, DICT_UPDATE, 1);
         }
         else {
-            if (elements == USHRT_MAX) {
-                if (!compiler_subdict(c, e, i - elements, i + 1)) {
-                    return 0;
-                }
-                if (have_dict) {
-                    ADDOP_I(c, DICT_UPDATE, 1);
-                }
-                have_dict = 1;
-                elements = 0;
-            }
-            else {
                 elements++;
-            }
         }
     }
     if (elements) {

@markshannon
Copy link
Member

My guess is that the 0xFFFF limit is a hangover from when bytecode instruction operands where two bytes.
Getting rid of that limit makes sense. However, it does make sense to have some smaller limit, as building the dict requires 2*n stack slots in the frame.

I'm merging this as it fixes the issue and adds a test.
However, I'd like to clean up the code before the release.

@markshannon markshannon merged commit c51db0e into python:master Aug 13, 2020
@miss-islington
Copy link
Contributor

Thanks @pablogsal for the PR, and @markshannon for merging it 🌮🎉.. I'm working now to backport this PR to: 3.9.
🐍🍒⛏🤖

@bedevere-bot
Copy link

GH-21853 is a backport of this pull request to the 3.9 branch.

@bedevere-bot bedevere-bot removed the needs backport to 3.9 only security fixes label Aug 13, 2020
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Aug 13, 2020
@hroncok
Copy link
Contributor

hroncok commented Aug 13, 2020

@pablogsal Thanks for the fix. I like the test :)

@pablogsal pablogsal deleted the bpo-31531 branch August 13, 2020 12:02
@pablogsal
Copy link
Member Author

pablogsal commented Aug 13, 2020

My guess is that the 0xFFFF limit is a hangover from when bytecode instruction operands where two bytes.
Getting rid of that limit makes sense. However, it does make sense to have some smaller limit, as building the dict requires 2*n stack slots in the frame.

I'm merging this as it fixes the issue and adds a test.
However, I'd like to clean up the code before the release.

Seems that this logic was introduced in this commit:

commit fd7ed407d79b797e20d0a6fe69e18f9ba9354979
Author: Raymond Hettinger <[email protected]>
Date:   Tue Dec 18 21:24:09 2007 +0000

    Give meaning to the oparg for BUILD_MAP:  estimated size of the dictionary.
    
    Allows dictionaries to be pre-sized (upto 255 elements) saving time lost
    to re-sizes with their attendant mallocs and re-insertions.
    
    Has zero effect on small dictionaries (5 elements or fewer), a slight
    benefit for dicts upto 22 elements (because they had to resize once
    anyway), and more benefit for dicts upto 255 elements (saving multiple
    resizes during the build-up and reducing the number of collisions on
    the first insertions).  Beyond 255 elements, there is no addional benefit.

diff --git a/Python/compile.c b/Python/compile.c
index 3b0c53fb19..36ad8a48e0 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -2922,11 +2922,9 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
        case IfExp_kind:
                return compiler_ifexp(c, e);
        case Dict_kind:
-               /* XXX get rid of arg? */
-               ADDOP_I(c, BUILD_MAP, 0);
                n = asdl_seq_LEN(e->v.Dict.values);
-               /* We must arrange things just right for STORE_SUBSCR.
-                  It wants the stack to look like (value) (dict) (key) */
+               ADDOP_I(c, BUILD_MAP, (n>255 ? 255 : n));
+               n = asdl_seq_LEN(e->v.Dict.values);
                for (i = 0; i < n; i++) {
                        VISIT(c, expr, 
                                (expr_ty)asdl_seq_GET(e->v.Dict.values, i));

shihai1991 pushed a commit to shihai1991/cpython that referenced this pull request Aug 20, 2020
@Mariatta Mariatta added the needs backport to 3.9 only security fixes label Sep 4, 2020
@miss-islington
Copy link
Contributor

Thanks @pablogsal for the PR, and @markshannon for merging it 🌮🎉.. I'm working now to backport this PR to: 3.9.
🐍🍒⛏🤖

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Sep 4, 2020
@bedevere-bot bedevere-bot removed the needs backport to 3.9 only security fixes label Sep 4, 2020
@bedevere-bot
Copy link

GH-22105 is a backport of this pull request to the 3.9 branch.

@Mariatta Mariatta added the needs backport to 3.9 only security fixes label Sep 4, 2020
@miss-islington
Copy link
Contributor

Thanks @pablogsal for the PR, and @markshannon for merging it 🌮🎉.. I'm working now to backport this PR to: 3.9.
🐍🍒⛏🤖

@miss-islington
Copy link
Contributor

Sorry @pablogsal and @markshannon, I had trouble checking out the 3.9 backport branch.
Please backport using cherry_picker on command line.
cherry_picker c51db0ea40ddabaf5f771ea633b37fcf4c90a495 3.9

@Mariatta Mariatta added needs backport to 3.9 only security fixes and removed needs backport to 3.9 only security fixes labels Sep 4, 2020
@miss-islington
Copy link
Contributor

Thanks @pablogsal for the PR, and @markshannon for merging it 🌮🎉.. I'm working now to backport this PR to: 3.9.
🐍🍒⛏🤖 I'm not a witch! I'm not a witch!

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Sep 4, 2020
@bedevere-bot bedevere-bot removed the needs backport to 3.9 only security fixes label Sep 4, 2020
@bedevere-bot
Copy link

GH-22107 is a backport of this pull request to the 3.9 branch.

pablogsal added a commit that referenced this pull request Sep 4, 2020
…ments (GH-21850) (GH-22107)

(cherry picked from commit c51db0e)

Co-authored-by: Pablo Galindo <[email protected]>
xzy3 pushed a commit to xzy3/cpython that referenced this pull request Oct 18, 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.

8 participants