SpyInput uses a fixed-size buffer and explicitly zeros memory which is good for
catching logic errors but defeats valgrind's memory tracking. Use a separate
buffer of exactly the correct size for each request. This correctly catches the
problem under valgrind:
```
==8694== Invalid read of size 2
==8694== at 0x54EFFB: utf16_iterate (utf16.c:10)
==8694== by 0x551126: ts_lexer__get_lookahead (lexer.c:54)
==8694== by 0x5515CD: ts_lexer_start (lexer.c:154)
==8694== by 0x54699F: parser(long,...)(long long) (parser.c:297)
==8694== by 0x54788A: parser__get_lookahead (parser.c:439)
==8694== by 0x54B2D3: parser__advance (parser.c:1150)
==8694== by 0x54C2AA: parser_parse (parser.c:1348)
==8694== by 0x53F063: ts_document_parse_with_options (document.c:136)
==8694== by 0x53EF43: ts_document_parse (document.c:107)
==8694== by 0x4AED11: {lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda()#4}::operator()() const::{lambda()#4}::operator()() const (document_test.cc:82)
==8694== by 0x4B56B6: std::_Function_handler<void (), {lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda()#4}::operator()() const::{lambda()#4}>::_M_invoke(std::_Any_data const&) (functional:1871)
==8694== by 0x40F8C5: std::function<void ()>::operator()() const (functional:2267)
==8694== Address 0x5d08be0 is 0 bytes inside a block of size 1 alloc'd
==8694== at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8694== by 0x507C3E: SpyInput::read(void*, unsigned int*) (spy_input.cc:66)
==8694== by 0x55103D: ts_lexer__get_chunk (lexer.c:29)
==8694== by 0x5515B6: ts_lexer_start (lexer.c:152)
==8694== by 0x54699F: parser(long,...)(long long) (parser.c:297)
==8694== by 0x54788A: parser__get_lookahead (parser.c:439)
==8694== by 0x54B2D3: parser__advance (parser.c:1150)
==8694== by 0x54C2AA: parser_parse (parser.c:1348)
==8694== by 0x53F063: ts_document_parse_with_options (document.c:136)
==8694== by 0x53EF43: ts_document_parse (document.c:107)
==8694== by 0x4AED11: {lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda()#4}::operator()() const::{lambda()#4}::operator()() const (document_test.cc:82)
==8694== by 0x4B56B6: std::_Function_handler<void (), {lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda()#4}::operator()() const::{lambda()#4}>::_M_invoke(std::_Any_data const&) (functional:1871)
```
39 lines
943 B
C++
39 lines
943 B
C++
#ifndef HELPERS_SPY_INPUT_H_
|
|
#define HELPERS_SPY_INPUT_H_
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include "tree_sitter/runtime.h"
|
|
|
|
struct SpyInputEdit {
|
|
size_t start_byte;
|
|
size_t bytes_removed;
|
|
std::string text_inserted;
|
|
};
|
|
|
|
class SpyInput {
|
|
uint32_t chars_per_chunk;
|
|
char *buffer;
|
|
uint32_t byte_offset;
|
|
std::vector<SpyInputEdit> undo_stack;
|
|
|
|
static const char * read(void *, uint32_t *);
|
|
static int seek(void *, uint32_t, uint32_t);
|
|
std::pair<std::string, TSPoint> swap_substr(size_t, size_t, std::string);
|
|
|
|
public:
|
|
SpyInput(std::string content, size_t chars_per_chunk);
|
|
~SpyInput();
|
|
|
|
TSInput input();
|
|
void clear();
|
|
TSInputEdit replace(size_t start_char, size_t chars_removed, std::string text);
|
|
TSInputEdit undo();
|
|
std::vector<std::string> strings_read() const;
|
|
|
|
std::string content;
|
|
TSInputEncoding encoding;
|
|
std::vector<std::pair<uint32_t, uint32_t>> ranges_read;
|
|
};
|
|
|
|
#endif // HELPERS_SPY_INPUT_H_
|