https://github.com/ClickHouse/ClickHouse/blob/9a48cf0da8badfc5f3da08611eb44961aa28e3f6/src/Functions/FunctionsHashing.h#L669-L671

There's a call to `blake3_free_char_pointer` that passes ownership of the pointer back to Rust (which then frees the memory), then there's a call to `std::string`'s constructor that accepts that now-freed pointer.
{
        if (const ColumnString * col_from = checkAndGetColumn<ColumnString>(column))
        {
            const typename ColumnString::Chars & data = col_from->getChars();
            const typename ColumnString::Offsets & offsets = col_from->getOffsets();
            size_t size = offsets.size();
            ColumnString::Offset current_offset = 0;
            for (size_t i = 0; i < size; ++i)
            {
                const ToType h = Impl::apply(
                    reinterpret_cast<const char *>(&data[current_offset]),
                    offsets[i] - current_offset - 1);
                if constexpr (first)
                    vec_to[i] = h;
                else
                    vec_to[i] = Impl::combineHashes(vec_to[i], h);
                current_offset = offsets[i];
            }
        }
        else if (const ColumnFixedString * col_from_fixed = checkAndGetColumn<ColumnFixedString>(column))
        {
            const typename ColumnString::Chars & data = col_from_fixed->getChars();
            size_t n = col_from_fixed->getN();
            size_t size = data.size() / n;
            for (size_t i = 0; i < size; ++i)
            {
                const ToType h = Impl::apply(reinterpret_cast<const char *>(&data[i * n]), n);