ben-strasser / fast-cpp-csv-parser

fast-cpp-csv-parser
BSD 3-Clause "New" or "Revised" License
2.15k stars 440 forks source link

LineReader buffer race condition with AsynchronousReader #36

Closed llchan closed 7 years ago

llchan commented 7 years ago

When the LineReader destructor is called, it frees the data buffer. However, there can be an in-flight read call in the AsynchronousReader worker thread, which will try to put stuff into the freed data buffer. This leads to a segfault. To reproduce, read a large file and throw an exception while it is reading.

The solution is simple: don't deallocate the buffer until the reader is joined. I have a PR I can send over, which basically replaces the char* buffer with a std::vector<char> buffer and puts that before the AsynchronousReader reader in the class members so that it gets destructed after the reader is destroyed.

ben-strasser commented 7 years ago

Hi,

thanks for the bug report. That's a nasty one. I should really setup auto fuzzer and thread sanitizers ...

Anyway, could please briefly review the patch below and verify that it solves the problem. Thanks. :)

Best Regards Ben Strasser

diff --git a/csv.h b/csv.h index 7e20d66..86d1a8d 100644 --- a/csv.h +++ b/csv.h @@ -314,12 +314,12 @@ namespace io{ class LineReader{ private: static const int block_len = 1<<24;

@@ -343,22 +343,18 @@ namespace io{ void init(std::unique_ptrbyte_source){ file_line = 0;

@@ -448,14 +444,14 @@ namespace io{ assert(data_end <= block_len*2);

                     if(data_begin >= block_len){

@@ -484,14 +480,10 @@ namespace io{ if(line_end != data_begin && buffer[line_end-1] == '\r') buffer[line_end-1] = '\0';

llchan commented 7 years ago

Looks good to me! Thanks for the quick turnaround.

ben-strasser commented 7 years ago

Hi,

I just committed the patch. Thanks for reporting.

Best Regards Ben Strasser