Skip to content
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

__sizeof__ underreports size of 0 by 4 bytes #98159

Closed
envp opened this issue Oct 10, 2022 · 6 comments
Closed

__sizeof__ underreports size of 0 by 4 bytes #98159

envp opened this issue Oct 10, 2022 · 6 comments
Labels
type-bug An unexpected behavior, bug, or error

Comments

@envp
Copy link

envp commented Oct 10, 2022

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
@envp envp added the type-bug An unexpected behavior, bug, or error label Oct 10, 2022
@envp
Copy link
Author

envp commented Oct 10, 2022

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

@corona10
Copy link
Member

corona10 commented Nov 6, 2022

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?

@corona10
Copy link
Member

corona10 commented Nov 6, 2022

@envp See also: #69408

@mdickinson
Copy link
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.

@corona10
Copy link
Member

corona10 commented Nov 6, 2022

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

@envp
Copy link
Author

envp commented Jan 4, 2023

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
Labels
type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

3 participants