I have found that although coroutines generally work with objects requiring special allocation, the specific combination of using Seastar's coroutines without the Seastar allocator causes segmentation faults. The segmentation faults happen because the objects appear in memory with wrong alignment, at addresses not divisible by their sizes. The issue is gone if I allocate these objects using a unique_ptr, but it's a performance eating workaround.
Steps to reproduce
- Create a coroutine whose frame contains an object with unusual alignment requirements (such as
std::experimental::fixed_size_simd<char, 32> from <experimental/simd> of GCC or Clang)
- Run the coroutine without the Seastar allocator (diasbled by setting
options.smp_opts.memory_allocator to seastar::memory_allocator::standard)
- Ensure it's run a few times in a loop, since there's a chance the coroutine will coincidentally appear at a location with correct alignment
- Compile in Release with debug symbols and run in a debugger
A small program to reproduce
There's a small chance it won't crash because the alignment will happen to be correct in all attempts.
#include <seastar/core/seastar.hh>
#include <seastar/core/reactor.hh>
#include <seastar/core/future-util.hh>
#include <seastar/net/api.hh>
#include <seastar/core/app-template.hh>
#include <seastar/core/reactor.hh>
#include <seastar/core/sleep.hh>
#include <string_view>
#include <experimental/simd>
seastar::future<char> doSimd() {
std::experimental::fixed_size_simd<char, 32> breaker;
constexpr std::string_view sourceData = "We just need some data that would be written to a structure with bad alignment and crash";
breaker.copy_from(sourceData.data(), std::experimental::vector_aligned);
co_await seastar::sleep(std::chrono::milliseconds(1));
co_return breaker[0];
}
int main(int argc, char** argv)
{
seastar::app_template::seastar_options options;
options.smp_opts.memory_allocator = seastar::memory_allocator::standard;
seastar::app_template app{std::move(options)};
return app.run(argc, argv, [&] {
std::vector<seastar::future<char>> futures;
for (int i = 0; i < 4; i++) {
futures.push_back(seastar::smp::submit_to(i, [] {
return doSimd();
}));
}
return seastar::when_all_succeed(futures.begin(), futures.end()).then([] (std::vector<char>) {
std::cout << "Done.\n";
});
});
}
I have found that although coroutines generally work with objects requiring special allocation, the specific combination of using Seastar's coroutines without the Seastar allocator causes segmentation faults. The segmentation faults happen because the objects appear in memory with wrong alignment, at addresses not divisible by their sizes. The issue is gone if I allocate these objects using a
unique_ptr, but it's a performance eating workaround.Steps to reproduce
std::experimental::fixed_size_simd<char, 32>from<experimental/simd>of GCC or Clang)options.smp_opts.memory_allocatortoseastar::memory_allocator::standard)A small program to reproduce
There's a small chance it won't crash because the alignment will happen to be correct in all attempts.