From 5389db9e7160a85080078a1cf26dbc46ace55c21 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 11 Nov 2013 08:37:54 -0800 Subject: [PATCH] * search.c (find_newline): Rewrite to prefer offsets to pointers. This avoids undefined behavior when subtracting pointers into different aways. On my platform it also makes the code a tad smaller and presumably faster. --- src/ChangeLog | 7 ++++ src/search.c | 98 ++++++++++++++++++++------------------------------- 2 files changed, 45 insertions(+), 60 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index cc20b68c729..03d806ee7f1 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,10 @@ +2013-11-11 Paul Eggert + + * search.c (find_newline): Rewrite to prefer offsets to pointers. + This avoids undefined behavior when subtracting pointers into + different aways. On my platform it also makes the code a tad + smaller and presumably faster. + 2013-11-11 Stefan Monnier * keyboard.c (command_loop_1): Use region-extract-function. diff --git a/src/search.c b/src/search.c index 1d0740428d7..c9e27627cd1 100644 --- a/src/search.c +++ b/src/search.c @@ -720,58 +720,45 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, { /* The termination address of the dumb loop. */ - register unsigned char *ceiling_addr - = BYTE_POS_ADDR (ceiling_byte) + 1; - register unsigned char *cursor - = BYTE_POS_ADDR (start_byte); - unsigned char *base = cursor; + unsigned char *lim_addr = BYTE_POS_ADDR (ceiling_byte) + 1; + ptrdiff_t lim_byte = ceiling_byte + 1; - while (cursor < ceiling_addr) - { + /* Nonpositive offsets (relative to LIM_ADDR and LIM_BYTE) + of the base, the cursor, and the next line. */ + ptrdiff_t base = start_byte - lim_byte; + ptrdiff_t cursor, next; + + for (cursor = base; cursor < 0; cursor = next) + { /* The dumb loop. */ - unsigned char *nl = memchr (cursor, '\n', ceiling_addr - cursor); + unsigned char *nl = memchr (lim_addr + cursor, '\n', - cursor); + next = nl ? nl - lim_addr : 0; /* If we're looking for newlines, cache the fact that - the region from start to cursor is free of them. */ + this line's region is free of them. */ if (newline_cache) { - unsigned char *low = cursor; - unsigned char *lim = nl ? nl : ceiling_addr; know_region_cache (current_buffer, newline_cache, - BYTE_TO_CHAR (low - base + start_byte), - BYTE_TO_CHAR (lim - base + start_byte)); + BYTE_TO_CHAR (lim_byte + cursor), + BYTE_TO_CHAR (lim_byte + next)); + /* know_region_cache can relocate buffer text. */ + lim_addr = BYTE_POS_ADDR (ceiling_byte) + 1; } if (! nl) break; + next++; if (--count == 0) { immediate_quit = 0; if (bytepos) - *bytepos = nl + 1 - base + start_byte; - return BYTE_TO_CHAR (nl + 1 - base + start_byte); - } - if (newline_cache) - { - /* The call to know_region_cache could have - allocated memory and caused relocation of buffer - text. If it did, adjust pointers into buffer - text. */ - ptrdiff_t offset = BYTE_POS_ADDR (start_byte) - base; - - if (offset != 0) - { - cursor += offset; - base += offset; - ceiling_addr += offset; - nl += offset; - } + *bytepos = lim_byte + next; + return BYTE_TO_CHAR (lim_byte + next); } - cursor = nl + 1; } - start_byte += ceiling_addr - base; + start_byte = lim_byte; start = BYTE_TO_CHAR (start_byte); } } @@ -810,24 +797,28 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, { /* The termination address of the dumb loop. */ - register unsigned char *ceiling_addr = BYTE_POS_ADDR (ceiling_byte); - register unsigned char *cursor = BYTE_POS_ADDR (start_byte - 1); - unsigned char *base = cursor; + unsigned char *ceiling_addr = BYTE_POS_ADDR (ceiling_byte); + + /* Offsets (relative to CEILING_ADDR and CEILING_BYTE) of + the base, the cursor, and the previous line. These + offsets are at least -1. */ + ptrdiff_t base = start_byte - ceiling_byte; + ptrdiff_t cursor, prev; - while (cursor >= ceiling_addr) + for (cursor = base; 0 < cursor; cursor = prev) { - unsigned char *nl = memrchr (ceiling_addr, '\n', - cursor + 1 - ceiling_addr); + unsigned char *nl = memrchr (ceiling_addr, '\n', cursor); + prev = nl ? nl - ceiling_addr : -1; /* If we're looking for newlines, cache the fact that - the region from after the cursor to start is free of them. */ + this line's region is free of them. */ if (newline_cache) { - unsigned char *low = nl ? nl : ceiling_addr - 1; - unsigned char *lim = cursor; know_region_cache (current_buffer, newline_cache, - BYTE_TO_CHAR (low - base + start_byte), - BYTE_TO_CHAR (lim - base + start_byte)); + BYTE_TO_CHAR (ceiling_byte + prev + 1), + BYTE_TO_CHAR (ceiling_byte + cursor)); + /* know_region_cache can relocate buffer text. */ + ceiling_addr = BYTE_POS_ADDR (ceiling_byte); } if (! nl) @@ -837,25 +828,12 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, { immediate_quit = 0; if (bytepos) - *bytepos = nl - base + start_byte; - return BYTE_TO_CHAR (nl - base + start_byte); - } - if (newline_cache) - { - ptrdiff_t offset = BYTE_POS_ADDR (start_byte - 1) - base; - - if (offset != 0) - { - cursor += offset; - base += offset; - ceiling_addr += offset; - nl += offset; - } + *bytepos = ceiling_byte + prev + 1; + return BYTE_TO_CHAR (ceiling_byte + prev + 1); } - cursor = nl - 1; } - start_byte += ceiling_addr - 1 - base; + start_byte = ceiling_byte; start = BYTE_TO_CHAR (start_byte); } } -- 2.39.2