2020-12-04 13:47:15 +00:00
|
|
|
use std::alloc::{Allocator, Global, Layout, System};
|
alloc_system: don’t assume MIN_ALIGN for small sizes, fix #45955
The GNU C library (glibc) is documented to always allocate with an alignment
of at least 8 or 16 bytes, on 32-bit or 64-bit platforms:
https://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html
This matches our use of `MIN_ALIGN` before this commit.
However, even when libc is glibc, the program might be linked
with another allocator that redefines the `malloc` symbol and friends.
(The `alloc_jemalloc` crate does, in some cases.)
So `alloc_system` doesn’t know which allocator it calls,
and needs to be conservative in assumptions it makes.
The C standard says:
https://port70.net/%7Ensz/c/c11/n1570.html#7.22.3
> The pointer returned if the allocation succeeds is suitably aligned
> so that it may be assigned to a pointer to any type of object
> with a fundamental alignment requirement
https://port70.net/~nsz/c/c11/n1570.html#6.2.8p2
> A fundamental alignment is represented by an alignment less than
> or equal to the greatest alignment supported by the implementation
> in all contexts, which is equal to `_Alignof (max_align_t)`.
`_Alignof (max_align_t)` depends on the ABI and doesn’t seem to have
a clear definition, but it seems to match our `MIN_ALIGN` in practice.
However, the size of objects is rounded up to the next multiple
of their alignment (since that size is also the stride used in arrays).
Conversely, the alignment of a non-zero-size object is at most its size.
So for example it seems ot be legal for `malloc(8)` to return a pointer
that’s only 8-bytes-aligned, even if `_Alignof (max_align_t)` is 16.
2017-11-20 14:30:04 +00:00
|
|
|
|
2019-07-02 10:56:51 +00:00
|
|
|
/// Issue #45955 and #62251.
|
alloc_system: don’t assume MIN_ALIGN for small sizes, fix #45955
The GNU C library (glibc) is documented to always allocate with an alignment
of at least 8 or 16 bytes, on 32-bit or 64-bit platforms:
https://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html
This matches our use of `MIN_ALIGN` before this commit.
However, even when libc is glibc, the program might be linked
with another allocator that redefines the `malloc` symbol and friends.
(The `alloc_jemalloc` crate does, in some cases.)
So `alloc_system` doesn’t know which allocator it calls,
and needs to be conservative in assumptions it makes.
The C standard says:
https://port70.net/%7Ensz/c/c11/n1570.html#7.22.3
> The pointer returned if the allocation succeeds is suitably aligned
> so that it may be assigned to a pointer to any type of object
> with a fundamental alignment requirement
https://port70.net/~nsz/c/c11/n1570.html#6.2.8p2
> A fundamental alignment is represented by an alignment less than
> or equal to the greatest alignment supported by the implementation
> in all contexts, which is equal to `_Alignof (max_align_t)`.
`_Alignof (max_align_t)` depends on the ABI and doesn’t seem to have
a clear definition, but it seems to match our `MIN_ALIGN` in practice.
However, the size of objects is rounded up to the next multiple
of their alignment (since that size is also the stride used in arrays).
Conversely, the alignment of a non-zero-size object is at most its size.
So for example it seems ot be legal for `malloc(8)` to return a pointer
that’s only 8-bytes-aligned, even if `_Alignof (max_align_t)` is 16.
2017-11-20 14:30:04 +00:00
|
|
|
#[test]
|
|
|
|
fn alloc_system_overaligned_request() {
|
|
|
|
check_overalign_requests(System)
|
|
|
|
}
|
|
|
|
|
2017-11-20 14:42:34 +00:00
|
|
|
#[test]
|
|
|
|
fn std_heap_overaligned_request() {
|
2018-04-03 19:15:06 +00:00
|
|
|
check_overalign_requests(Global)
|
2017-11-20 14:42:34 +00:00
|
|
|
}
|
|
|
|
|
2020-12-04 13:47:15 +00:00
|
|
|
fn check_overalign_requests<T: Allocator>(allocator: T) {
|
2019-12-22 22:42:04 +00:00
|
|
|
for &align in &[4, 8, 16, 32] {
|
|
|
|
// less than and bigger than `MIN_ALIGN`
|
|
|
|
for &size in &[align / 2, align - 1] {
|
|
|
|
// size less than alignment
|
2019-07-02 10:56:51 +00:00
|
|
|
let iterations = 128;
|
|
|
|
unsafe {
|
2019-12-22 22:42:04 +00:00
|
|
|
let pointers: Vec<_> = (0..iterations)
|
|
|
|
.map(|_| {
|
2020-12-04 13:47:15 +00:00
|
|
|
allocator.allocate(Layout::from_size_align(size, align).unwrap()).unwrap()
|
2019-12-22 22:42:04 +00:00
|
|
|
})
|
|
|
|
.collect();
|
2019-07-02 10:56:51 +00:00
|
|
|
for &ptr in &pointers {
|
2019-12-22 22:42:04 +00:00
|
|
|
assert_eq!(
|
2020-08-04 16:03:34 +00:00
|
|
|
(ptr.as_non_null_ptr().as_ptr() as usize) % align,
|
2019-12-22 22:42:04 +00:00
|
|
|
0,
|
|
|
|
"Got a pointer less aligned than requested"
|
|
|
|
)
|
2019-07-02 10:56:51 +00:00
|
|
|
}
|
alloc_system: don’t assume MIN_ALIGN for small sizes, fix #45955
The GNU C library (glibc) is documented to always allocate with an alignment
of at least 8 or 16 bytes, on 32-bit or 64-bit platforms:
https://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html
This matches our use of `MIN_ALIGN` before this commit.
However, even when libc is glibc, the program might be linked
with another allocator that redefines the `malloc` symbol and friends.
(The `alloc_jemalloc` crate does, in some cases.)
So `alloc_system` doesn’t know which allocator it calls,
and needs to be conservative in assumptions it makes.
The C standard says:
https://port70.net/%7Ensz/c/c11/n1570.html#7.22.3
> The pointer returned if the allocation succeeds is suitably aligned
> so that it may be assigned to a pointer to any type of object
> with a fundamental alignment requirement
https://port70.net/~nsz/c/c11/n1570.html#6.2.8p2
> A fundamental alignment is represented by an alignment less than
> or equal to the greatest alignment supported by the implementation
> in all contexts, which is equal to `_Alignof (max_align_t)`.
`_Alignof (max_align_t)` depends on the ABI and doesn’t seem to have
a clear definition, but it seems to match our `MIN_ALIGN` in practice.
However, the size of objects is rounded up to the next multiple
of their alignment (since that size is also the stride used in arrays).
Conversely, the alignment of a non-zero-size object is at most its size.
So for example it seems ot be legal for `malloc(8)` to return a pointer
that’s only 8-bytes-aligned, even if `_Alignof (max_align_t)` is 16.
2017-11-20 14:30:04 +00:00
|
|
|
|
2019-07-02 10:56:51 +00:00
|
|
|
// Clean up
|
|
|
|
for &ptr in &pointers {
|
2020-12-04 13:47:15 +00:00
|
|
|
allocator.deallocate(
|
2020-08-04 16:03:34 +00:00
|
|
|
ptr.as_non_null_ptr(),
|
|
|
|
Layout::from_size_align(size, align).unwrap(),
|
|
|
|
)
|
2019-07-02 10:56:51 +00:00
|
|
|
}
|
|
|
|
}
|
alloc_system: don’t assume MIN_ALIGN for small sizes, fix #45955
The GNU C library (glibc) is documented to always allocate with an alignment
of at least 8 or 16 bytes, on 32-bit or 64-bit platforms:
https://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html
This matches our use of `MIN_ALIGN` before this commit.
However, even when libc is glibc, the program might be linked
with another allocator that redefines the `malloc` symbol and friends.
(The `alloc_jemalloc` crate does, in some cases.)
So `alloc_system` doesn’t know which allocator it calls,
and needs to be conservative in assumptions it makes.
The C standard says:
https://port70.net/%7Ensz/c/c11/n1570.html#7.22.3
> The pointer returned if the allocation succeeds is suitably aligned
> so that it may be assigned to a pointer to any type of object
> with a fundamental alignment requirement
https://port70.net/~nsz/c/c11/n1570.html#6.2.8p2
> A fundamental alignment is represented by an alignment less than
> or equal to the greatest alignment supported by the implementation
> in all contexts, which is equal to `_Alignof (max_align_t)`.
`_Alignof (max_align_t)` depends on the ABI and doesn’t seem to have
a clear definition, but it seems to match our `MIN_ALIGN` in practice.
However, the size of objects is rounded up to the next multiple
of their alignment (since that size is also the stride used in arrays).
Conversely, the alignment of a non-zero-size object is at most its size.
So for example it seems ot be legal for `malloc(8)` to return a pointer
that’s only 8-bytes-aligned, even if `_Alignof (max_align_t)` is 16.
2017-11-20 14:30:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|