seq_lengths's contents are copied, so this is OK.
When destroying alignment_streams, the destructor for each emplaced sam_file_output_t is called.
The destructor wants to access the reference IDs.
Because the constructor was called with an lvalue reference seq_names, it will try to access seq_names.
seq_names has already been destroyed.
Without the alignment_streams.reserve, a reallocation happens.
This will then use the move constructor.
Error 4 (Segfault)
Simplification of Error 3
After a move, the internal unique pointers primary_stream and secondary_stream are nullptr for the moved-from object. On destruction, this moved-from object then tries to write the header.
Error 1 was found and reported by @tloka (via mail).
Background
1)
If no header has been written, the header is written on destruction
https://github.com/seqan/seqan3/blob/4d03890530089b040221876c9e368fc250c4583f/include/seqan3/io/sam_file/output.hpp#L156-L172
2)
The header might not own the reference IDs (here:
seq_names
):https://github.com/seqan/seqan3/blob/4d03890530089b040221876c9e368fc250c4583f/include/seqan3/io/sam_file/header.hpp#L59-L70
Errors
Error 1 (Segfault)
Destructors are called in reverse order:
~seq_lengths
~seq_names
~alignment_streams
seq_lengths
's contents are copied, so this is OK. When destroyingalignment_streams
, the destructor for each emplacedsam_file_output_t
is called. The destructor wants to access the reference IDs. Because the constructor was called with an lvalue referenceseq_names
, it will try to accessseq_names
.seq_names
has already been destroyed.Error 2 (Unexpected output)
Expected:
Actual:
Error 3 (Segfault)
Segfault happens on Clang. GCC gives assertion:
Without the
alignment_streams.reserve
, a reallocation happens. This will then use the move constructor.Error 4 (Segfault)
Simplification of Error 3
After a move, the internal unique pointers
primary_stream
andsecondary_stream
arenullptr
for the moved-from object. On destruction, this moved-from object then tries to write the header.Solutions
For 1 and 2
Always taking ownership of the reference IDs:
From the user's side, error 1 can be worked around by transferring ownership:
For 3 and 4
Since moved-from
unique_ptr
s are guaranteed to be set tonullptr
, also check for non-nullprimary_stream
before writing the header.