diff --git a/c/input/lrec_reader_mmap_dkvp.c b/c/input/lrec_reader_mmap_dkvp.c index 448e21469..f92103780 100644 --- a/c/input/lrec_reader_mmap_dkvp.c +++ b/c/input/lrec_reader_mmap_dkvp.c @@ -123,6 +123,7 @@ lrec_t* lrec_parse_mmap_dkvp_single_irs_single_others(file_reader_mmap_state_t * int saw_ps = FALSE; int saw_rs = FALSE; + //*phandle->eof = 'A'; // xxx temp for ( ; p < phandle->eof && *p; ) { if (*p == irs) { *p = 0; @@ -170,7 +171,8 @@ lrec_t* lrec_parse_mmap_dkvp_single_irs_single_others(file_reader_mmap_state_t * // There are two ways out of that loop: saw IRS, or saw end of file. if (saw_rs) { - // Easy and simple case: we read until end of line. + // Easy and simple case: we read until end of line. We zero-poked the irs to a null character to terminate the + // C string so it's OK to retain a pointer to that. if (*key == 0 || value <= key) { char free_flags = 0; @@ -187,20 +189,27 @@ lrec_t* lrec_parse_mmap_dkvp_single_irs_single_others(file_reader_mmap_state_t * } } else { - // Messier case: we read to end of file without seeing end of line. + // Messier case: we read to end of file without seeing end of line. We can't always zero-poke a null character + // to terminate the C string: if the file size is not a multiple of the OS page size it'll work (it's our + // copy-on-write memory). But if the file size is a multiple of the page size, then zero-poking at EOF is one + // byte past the page and that will segv us. if (*key == 0 || value <= key) { char free_flags = 0; - if (value >= phandle->eof) + if (value >= phandle->eof) { lrec_put(prec, make_nidx_key(idx, &free_flags), "", free_flags); - else - lrec_put(prec, make_nidx_key(idx, &free_flags), value, free_flags); + } else { + char* copy = mlr_alloc_string_from_char_range(value, phandle->eof - value); + lrec_put(prec, make_nidx_key(idx, &free_flags), copy, free_flags | FREE_ENTRY_VALUE); + } } else { - if (value >= phandle->eof) + if (value >= phandle->eof) { lrec_put(prec, key, "", NO_FREE); - else - lrec_put(prec, key, value, NO_FREE); + } else { + char* copy = mlr_alloc_string_from_char_range(value, phandle->eof - value); + lrec_put(prec, key, copy, FREE_ENTRY_VALUE); + } } } diff --git a/c/lib/mlrregex.c b/c/lib/mlrregex.c index 5f6040d92..b60f0e764 100644 --- a/c/lib/mlrregex.c +++ b/c/lib/mlrregex.c @@ -194,10 +194,7 @@ void copy_regex_captures(string_array_t* pregex_captures_1_up, char* input, regm string_array_realloc(pregex_captures_1_up, n+1); // n+1 since slot 0 of this 1-up array is unused for (int i = 1; i <= n; i++) { int len = matches[i].rm_eo - matches[i].rm_so; - char* dst = mlr_malloc_or_die(len + 1); - memcpy(dst, &input[matches[i].rm_so], len); - dst[len] = 0; - pregex_captures_1_up->strings[i] = dst; + pregex_captures_1_up->strings[i] = mlr_alloc_string_from_char_range(&input[matches[i].rm_so], len); } pregex_captures_1_up->strings_need_freeing = TRUE; } diff --git a/c/lib/mlrutil.c b/c/lib/mlrutil.c index f5a4714b1..87d6fa238 100644 --- a/c/lib/mlrutil.c +++ b/c/lib/mlrutil.c @@ -119,6 +119,13 @@ char* mlr_alloc_string_from_int(int value) { return string; } +char* mlr_alloc_string_from_char_range(char* start, int num_bytes) { + char* string = mlr_malloc_or_die(num_bytes+1); + memcpy(string, start, num_bytes); + string[num_bytes] = 0; + return string; +} + char* mlr_alloc_hexfmt_from_ll(long long value) { int n = snprintf(NULL, 0, "0x%llx", (unsigned long long)value); char* string = mlr_malloc_or_die(n+1); diff --git a/c/lib/mlrutil.h b/c/lib/mlrutil.h index f76127b84..b5b9398f7 100644 --- a/c/lib/mlrutil.h +++ b/c/lib/mlrutil.h @@ -90,6 +90,8 @@ char* mlr_alloc_string_from_ull(unsigned long long value); char* mlr_alloc_string_from_ll(long long value); char* mlr_alloc_string_from_ll_and_format(long long value, char* fmt); char* mlr_alloc_string_from_int(int value); +// The input doesn't include the null-terminator; the output does. +char* mlr_alloc_string_from_char_range(char* start, int num_bytes); char* mlr_alloc_hexfmt_from_ll(long long value);