Try to fix crash due to fifo read regression

I saw a crash when running

	git log --oneline %arg{@}
	hook -once buffer NormalIdle .* %{
		execute-keys -draft \
		%{gk!} \
		%{git diff --quiet || echo "Unstaged changes";} \
		%{git diff --quiet --cached || echo "Staged changes";} \
		<ret>
	}

Backtrace (I still have GDB attached):

    #4  0x00006502c740b13f in Kakoune::operator- (rhs=..., lhs=...) at /home/johannes/git/kakoune/src/units.hh:33
    33	   { return RealType(lhs.m_value - rhs.m_value); }
    (gdb) up
    #5  Kakoune::Buffer::next (coord=..., this=0x6502c90d7ff0) at /home/johannes/git/kakoune/src/buffer.inl.hh:18
    18	   if (coord.column < m_lines[coord.line].length() - 1)
    (gdb) up
    #6  FifoWatcher::read_fifo (this=0x6502c90d9e48) at buffer_utils.cc:252
    252	                           m_buffer.erase(pos, m_buffer.next(pos));

This was introduced in 582c3c56b (Do not add trailing newline to
non-scrolling fifo buffers, 2024-01-28).

The problem seems to be that we call "m_buffer.next()" on a position
that is past-end the buffer, so m_lines[coord.line] is out-of-bounds.
Fix it.
For some reason I have not managed to reproduce the crash, not even
with sanitize=address.

There might be another problem: m_had_trailing_newline is intentionally
uninitialized because it is supposed to be read only on the second
read() with a positive return value. Unfortunately I think it's
possible that e.g. a NormalIdle hook inserts some text before the
first positive read(). Then, this line

        const bool is_first = pos == BufferCoord{0,0};
        if (not m_scroll and (is_first or m_had_trailing_newline))
            pos = m_buffer.next(pos);

will read uninitialized "m_had_trailing_newline".  Fix that too, to
be on the safe side. Sadly I don't have a test for this one either
so I'm not sure.
This commit is contained in:
Johannes Altmanninger 2024-02-17 22:32:05 +01:00 committed by Maxime Coste
parent a85b81e08a
commit 22b1d4ec4a

View File

@ -246,7 +246,7 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll
if (is_first)
m_buffer.erase({0,0}, m_buffer.next({0,0}));
else if (not m_had_trailing_newline and have_trailing_newline)
m_buffer.erase(pos, m_buffer.next(pos));
m_buffer.erase(m_buffer.prev(pos), pos);
}
m_had_trailing_newline = have_trailing_newline;
}
@ -264,7 +264,7 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll
Buffer& m_buffer;
bool m_scroll;
bool m_had_trailing_newline;
bool m_had_trailing_newline = false;
};
buffer->values()[fifo_watcher_id] = Value(Meta::Type<FifoWatcher>{}, fd, *buffer, scroll);