Skip to content

__sizeof__ underreports size of 0 by 4 bytes #98159

Closed

Description

@envp

Bug report

sys.getsizeof and int#__sizeof__() both underreport the size of the 0 singleton by 4 bytes, due to _PyLong_DIGIT_INIT setting ob_size to 0 when initializing the 0 singleton, the correct value should be 1, since there is a single ob_digit stored, as I understand it.

Examples:

Python 3.10.7 (main, Sep 15 2022, 01:51:29) [Clang 14.0.0 (clang-1400.0.29.102)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getsizeof(0)
24
>>> sys.getsizeof(1)
28
Python 3.8.14 (default, Sep  6 2022, 23:26:50)
[Clang 13.1.6 (clang-1316.0.21.2.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getsizeof(0)
24
>>> sys.getsizeof(1)
28

Details

  1. _PyLong_DIGIT_INIT(val) is used to initialize an immortal PyVarObject.
  2. Depending on the val passed it sets the the ob_size field of the immortal using the expression: ((val) == 0 ? 0 : ((val) > 0 ? 1 : -1))
    2.1. When val is 0, this creates an _PyVarObject_IMMORTAL_INIT(&PyLong_Type, 0), which sets the underlying PyVarObject's ob_size to 0.
  3. int___sizeof___impl uses ob_size (through Py_SIZE) to calculate the size
  4. The ob_size should be 1 because ob_digit has one digit stored.
    4.1. However, ob_size is set to 0, and this contributes to under-reporting the size of 0 by the sizeof(digit) which is 4

Your environment

  • CPython versions tested on: 3.8.14, 3.10.7
  • Operating system and architecture: Darwin 21.6.0 Darwin Kernel Version 21.6.0: Wed Aug 10 14:25:27 PDT 2022; root:xnu-8020.141.5~2/RELEASE_X86_6

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on Oct 10, 2022
  2. envp commented on Oct 10, 2022

    @envp
    Author

    I'm not entirely sure if this behaviour is incorrect, but my understanding is that ob_size should count the single digit stored in ob_digit. That is my premise for filing this as a bug.

    Compiler explorer link: https://godbolt.org/z/rx7PbEYxd

  3. corona10 commented on Nov 6, 2022

    @corona10
    Member

    This behavior looks like have a long history,
    but the first trigger was from 36820dd by @mdickinson

    @mdickinson
    By this patch, The zero was set toPy_SIZE(v) = 0; since the sign is zero, was this intended? or it should be fixed to have ob_size = 1 even if the sign is 0?

  4. corona10 commented on Nov 6, 2022

    @corona10
    Member

    @envp See also: #69408

  5. mdickinson commented on Nov 6, 2022

    @mdickinson
    Member

    or it should be fixed to have ob_size = 1 even if the sign is 0?

    Definitely not: ob_size=0 is the correct value for a zero; IIRC, there are a good few places in the code that expect ob_size=0 for zero.

    And yes, it's true that sys.getsizeof sometimes underreports for ints; that effect isn't limited to zero - there are lots of places in longobject.c where we allocate enough space and then don't reallocate after normalisation. That's a deliberate choice.

  6. corona10 commented on Nov 6, 2022

    @corona10
    Member

    Thanks, Mark, I will close the issue.
    The behavior looks like be intended.
    cc @envp

  7. envp commented on Jan 4, 2023

    @envp
    Author

    Thanks Mark! That rationale definitely cleared it up for me.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions