| 9497 | |
| 9498 | template <typename T> |
| 9499 | T* usertype_allocate(lua_State* L) { |
| 9500 | typedef std::integral_constant<bool, |
| 9501 | #if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT |
| 9502 | false |
| 9503 | #else |
| 9504 | (std::alignment_of<T*>::value > 1 || std::alignment_of<T>::value > 1) |
| 9505 | #endif |
| 9506 | > |
| 9507 | use_align; |
| 9508 | if (!use_align::value) { |
| 9509 | T** pointerpointer = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T))); |
| 9510 | T*& pointerreference = *pointerpointer; |
| 9511 | T* allocationtarget = reinterpret_cast<T*>(pointerpointer + 1); |
| 9512 | pointerreference = allocationtarget; |
| 9513 | return allocationtarget; |
| 9514 | } |
| 9515 | |
| 9516 | /* the assumption is that `lua_newuserdata` -- unless someone |
| 9517 | passes a specific lua_Alloc that gives us bogus, un-aligned pointers |
| 9518 | -- uses malloc, which tends to hand out more or less aligned pointers to memory |
| 9519 | (most of the time, anyhow) |
| 9520 | |
| 9521 | but it's not guaranteed, so we have to do a post-adjustment check and increase padding |
| 9522 | |
| 9523 | we do this preliminarily with compile-time stuff, to see |
| 9524 | if we strike lucky with the allocator and alignment values |
| 9525 | |
| 9526 | otherwise, we have to re-allocate the userdata and |
| 9527 | over-allocate some space for additional padding because |
| 9528 | compilers are optimized for aligned reads/writes |
| 9529 | (and clang will barf UBsan errors on us for not being aligned) |
| 9530 | */ |
| 9531 | static const std::size_t initial_size = aligned_space_for<T*, T>(nullptr); |
| 9532 | static const std::size_t misaligned_size = aligned_space_for<T*, T>(reinterpret_cast<void*>(0x1)); |
| 9533 | |
| 9534 | void* pointer_adjusted; |
| 9535 | void* data_adjusted; |
| 9536 | bool result |
| 9537 | = attempt_alloc(L, std::alignment_of_v<T*>, sizeof(T*), std::alignment_of_v<T>, sizeof(T), initial_size, pointer_adjusted, data_adjusted); |
| 9538 | if (!result) { |
| 9539 | // we're likely to get something that fails to perform the proper allocation a second time, |
| 9540 | // so we use the suggested_new_size bump to help us out here |
| 9541 | pointer_adjusted = nullptr; |
| 9542 | data_adjusted = nullptr; |
| 9543 | result = attempt_alloc( |
| 9544 | L, std::alignment_of_v<T*>, sizeof(T*), std::alignment_of_v<T>, sizeof(T), misaligned_size, pointer_adjusted, data_adjusted); |
| 9545 | if (!result) { |
| 9546 | if (pointer_adjusted == nullptr) { |
| 9547 | luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str()); |
| 9548 | } |
| 9549 | else { |
| 9550 | luaL_error(L, "aligned allocation of userdata block (data section) for '%s' failed", detail::demangle<T>().c_str()); |
| 9551 | } |
| 9552 | return nullptr; |
| 9553 | } |
| 9554 | } |
| 9555 | |
| 9556 | T** pointerpointer = reinterpret_cast<T**>(pointer_adjusted); |
nothing calls this directly
no test coverage detected