bpo-18835: Add PyMem_AlignedAlloc()#4089
Conversation
|
AppVeyor crashed with a heap corruption (exception c0000374) on: |
Sorry, something went wrong.
|
TODO: _PyMem_DebugRawAlignedAlloc() is currently a copy of _PyMem_DebugRawAlloc(). Instead, it should trap such bug: PyMem_Free() called on a memory blocked allocated by PyMem_AlignedAlloc(). Maybe it should store the alignment as well, to dump it in a fatal error message? |
Sorry, something went wrong.
I rebuild Python from scratch in Debug|x64: I am unable to reproduce the bug. Strange. |
Sorry, something went wrong.
Done. PyMem_Free(PyMem_AlignedAlloc()) now fails as expected. I simply chose to use uppercase for the API identifier. I added an unit test to test exactly this. I also documented newly added functions. I'm not sure of my documentation on the alignment: Windows requires alignment to be "an integer power of 2". Maybe we should suggest to always use powers of 2 to best portability? I would be surprised if PyMem_AlignedAlloc() fails with an alignment equals to a power of 2. |
Sorry, something went wrong.
|
According to the discussion on https://bugs.python.org/issue18835 it seems like the feature (aligned memory allocations) is needed, so I finished my implementation:
The PR is now ready for a review. |
Sorry, something went wrong.
|
I asked a colleague who works on the glibc: posix_memalign() cannot return NULL on success in the glibc. Extract: By the way, posix_memalign() rejects alignment == 0 and alignement which is not a power of 2: Oh. PyObject_AlignedAlloc() doesn't reject allignement == 0. Should we reject it as well? (Return NULL in that case.) |
Sorry, something went wrong.
|
Oh wow, on Windows, _aligned_malloc() "simply" crash with abort() if called with alignment=0 or alignment=3 (not a power of 2)! |
Sorry, something went wrong.
|
I added a new commit to check alignment. New documentation: |
Sorry, something went wrong.
|
On Fri, Oct 27, 2017 at 05:59:09AM -0700, Victor Stinner wrote:
Oh wow, on Windows, _aligned_malloc() "simply" crash with abort() if called with alignment=0 or alignment=3 (not a power of 2)!
Haha, that's old school. :) I think it is not entirely unreasonable for a
high performance function.
I'd do all the Posix checks on Windows.
if (alignment % sizeof (void *) != 0
|| !powerof2 (alignment / sizeof (void *))
|| alignment == 0)
Then the Posix semantics are sort of official.
Object_AlignedAlloc() doesn't reject allignement == 0. Should we reject it as well? (Return NULL in that case.)
Yes, I think it should reject align==0 and !powerof2(align).
|
Sorry, something went wrong.
Oh. I checked and posix_memalign(2, 100) fails with EINVAL even if alignment (=2) is a power of 2. I modified my PR to also check that in check_alignment(). I propose to always check the alignment in Python even if the glibc posix_memalign() fails nicely with EINVAL, to get the same behaviour on all platforms. For example, with my current PR, PyMem_RawAlignedAlloc(0, 100) returns NULL in release mode, rather than crashing (on abort()), on Windows. |
Sorry, something went wrong.
|
@skrah: Does the PR look better with the new alignment checks? |
Sorry, something went wrong.
|
I wish the call chains were easier to understand. This one ends up calling the |
Sorry, something went wrong.
Wow, my code was completely wrong :-) Before fixing this bug, I wrote an unit test to make sure that PyMem_AlignedAlloc() respects the alignment constraint... Ooops again, _PyMem_DebugRawAlignedAlloc() was wrong too: it didn't align correctly the pointer... I fixed that too. Sometimes, it helps to write unit tests ;-) |
Sorry, something went wrong.
|
Oh ok, I understood the failure on Windows. _PyObject_AlignedAlloc() still fell back on the raw allocator rather than the aligned allocator, when pymalloc failed to allocated memory. I had to rewrite the pymalloc allocator to give control to the caller how to fall back on another allocator. |
Sorry, something went wrong.
|
This PR became too big, so I extracted two changes:
Once these PR will be merged, I will rebase this PR on top of master. |
Sorry, something went wrong.
|
Oh, the Travis CI failed again with https://bugs.python.org/issue31910 I restarted the job. |
Sorry, something went wrong.
* Add aligned_alloc and aligned_free fields to PyMemAllocatorEx * Rename PyMemAllocatorEx structure to PyMemAllocatorEx2 to make sure that C extensions are upgraded to fill the new aligned_alloc and aligned_free fields * Add 6 new functions: * PyMem_RawAlignedAlloc() * PyMem_RawAlignedFree() * PyMem_AlignedAlloc() * PyMem_AlignedFree() * PyObject_AlignedAlloc() * PyObject_AlignedFree()
|
I rebased my PR on top of master to get the fix for https://bugs.python.org/issue31910 |
Sorry, something went wrong.
|
https://bugs.python.org/issue18835 has been rejected, so I closed this PR. |
Sorry, something went wrong.
Add aligned_alloc and aligned_free fields to PyMemAllocatorEx
Rename PyMemAllocatorEx structure to PyMemAllocatorEx2 to make sure
that C extensions are upgraded to fill the new aligned_alloc and
aligned_free fields
Add 6 new functions:
https://bugs.python.org/issue18835