1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-06 06:20:55 -08:00

etags: remove some arbitrary limits

etags had undefined behavior if input files, lines, tags, etc.,
had more than INT_MAX bytes.  Clean up the usage of integer types
to fix the overflow errors I found.
* admin/merge-gnulib (GNULIB_MODULES): Add mempcpy.
* lib-src/etags.c: Include inttypes.h, intprops.h.
(memcpyz): New function.  Use it to simplify several occurrences
of memcpy followed by storing a trailing '\0'.
(xnew): Use xnmalloc, to catch overflow on integer multiplication.
(xrnew): Change last arg to multiplier.  The type is not needed.
All callers changed.
(node, lineno, charno, linecharno, invalidcharno, make_tag):
(pfnote, add_node, number_len, C_symtype, lbz, Makefile_targets)
(readline):
Use intmax_t for line numbers and character positions, instead of
int or long.
(linebuffer, make_tag, pfnote, total_size_of_entries, put_entry)
(in_word_set, C_symtype, token, cstack, pushclass_above):
(popclass_above, write_classname, consider_token, C_entries)
(Ruby_functions, Makefile_targets, Lua_functions, TeX_commands)
(TeX_decode_env, erlang_func, erlang_attribute, erlang_atom)
(substitute, regex_tag_multiline, nocase_tail, readline_interval)
(readline, savenstr, concat, etags_getcwd, relative_filename)
(linebuffer_setlen):
Use ptrdiff_t for object sizes, instead of int or long or unsigned
or size_t.
(write_classname, C_entries):
Avoid sprintf, as the result could exceed INT_MAX bytes
and then behavior goes haywire.
(main): Use int, instead of unsigned, for argv counts.
(get_language_from_filename): Use bool for boolean.
(Ruby_functions): Prefer strcpy to memcpy when copying "=".
(linebuffer_setlen): Use ‘if’ instead of ‘while’.
(memory_full, xnmalloc, xnrealloc): New functions.
(xmalloc): Use memory_full, and take a ptrdiff_t instead of a size_t.
(xrealloc): Remove; no longer needed.
* lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate.
* lib/mempcpy.c, m4/mempcpy.m4: New files, copied from Gnulib.
This commit is contained in:
Paul Eggert 2019-11-26 13:53:41 -08:00
parent 75b41a38dd
commit cffa5703b9
6 changed files with 287 additions and 194 deletions

View file

@ -37,7 +37,7 @@ GNULIB_MODULES='
filemode filevercmp flexmember fpieee fstatat fsusage fsync filemode filevercmp flexmember fpieee fstatat fsusage fsync
getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog
ieee754-h ignore-value intprops largefile lstat ieee754-h ignore-value intprops largefile lstat
manywarnings memmem-simple memrchr minmax mkostemp mktime nstrftime manywarnings memmem-simple mempcpy memrchr minmax mkostemp mktime nstrftime
pathmax pipe2 pselect pthread_sigmask putenv pathmax pipe2 pselect pthread_sigmask putenv
qcopy-acl readlink readlinkat regex qcopy-acl readlink readlinkat regex
sig2str socklen stat-time std-gnu11 stdalign stddef stdio sig2str socklen stat-time std-gnu11 stdalign stddef stdio

View file

@ -114,6 +114,7 @@ char pot_etags_version[] = "@(#) pot revision number is 17.38.1.4";
# define O_CLOEXEC O_NOINHERIT # define O_CLOEXEC O_NOINHERIT
#endif /* WINDOWSNT */ #endif /* WINDOWSNT */
#include <inttypes.h>
#include <limits.h> #include <limits.h>
#include <unistd.h> #include <unistd.h>
#include <stdarg.h> #include <stdarg.h>
@ -123,6 +124,7 @@ char pot_etags_version[] = "@(#) pot revision number is 17.38.1.4";
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <binary-io.h> #include <binary-io.h>
#include <intprops.h>
#include <unlocked-io.h> #include <unlocked-io.h>
#include <c-ctype.h> #include <c-ctype.h>
#include <c-strcase.h> #include <c-strcase.h>
@ -141,6 +143,14 @@ char pot_etags_version[] = "@(#) pot revision number is 17.38.1.4";
# define CTAGS false # define CTAGS false
#endif #endif
/* Copy to DEST from SRC (containing LEN bytes), and append a NUL byte. */
static void
memcpyz (void *dest, void const *src, ptrdiff_t len)
{
char *e = mempcpy (dest, src, len);
*e = '\0';
}
static bool static bool
streq (char const *s, char const *t) streq (char const *s, char const *t)
{ {
@ -235,11 +245,11 @@ endtoken (unsigned char c)
/* /*
* xnew, xrnew -- allocate, reallocate storage * xnew, xrnew -- allocate, reallocate storage
* *
* SYNOPSIS: Type *xnew (int n, Type); * SYNOPSIS: Type *xnew (ptrdiff_t n, Type);
* void xrnew (OldPointer, int n, Type); * void xrnew (OldPointer, ptrdiff_t n, int multiplier);
*/ */
#define xnew(n, Type) ((Type *) xmalloc ((n) * sizeof (Type))) #define xnew(n, Type) ((Type *) xnmalloc (n, sizeof (Type)))
#define xrnew(op, n, Type) ((op) = (Type *) xrealloc (op, (n) * sizeof (Type))) #define xrnew(op, n, m) ((op) = xnrealloc (op, n, (m) * sizeof *(op)))
typedef void Lang_function (FILE *); typedef void Lang_function (FILE *);
@ -282,8 +292,8 @@ typedef struct node_st
bool valid; /* write this tag on the tag file */ bool valid; /* write this tag on the tag file */
bool is_func; /* function tag: use regexp in CTAGS mode */ bool is_func; /* function tag: use regexp in CTAGS mode */
bool been_warned; /* warning already given for duplicated tag */ bool been_warned; /* warning already given for duplicated tag */
int lno; /* line number tag is on */ intmax_t lno; /* line number tag is on */
long cno; /* character number line starts on */ intmax_t cno; /* character number line starts on */
} node; } node;
/* /*
@ -295,8 +305,8 @@ typedef struct node_st
*/ */
typedef struct typedef struct
{ {
long size; ptrdiff_t size;
int len; ptrdiff_t len;
char *buffer; char *buffer;
} linebuffer; } linebuffer;
@ -365,7 +375,7 @@ static void just_read_file (FILE *);
static language *get_language_from_langname (const char *); static language *get_language_from_langname (const char *);
static void readline (linebuffer *, FILE *); static void readline (linebuffer *, FILE *);
static long readline_internal (linebuffer *, FILE *, char const *); static ptrdiff_t readline_internal (linebuffer *, FILE *, char const *);
static bool nocase_tail (const char *); static bool nocase_tail (const char *);
static void get_tag (char *, char **); static void get_tag (char *, char **);
static void get_lispy_tag (char *); static void get_lispy_tag (char *);
@ -385,7 +395,7 @@ static void process_file (FILE *, char *, language *);
static void find_entries (FILE *); static void find_entries (FILE *);
static void free_tree (node *); static void free_tree (node *);
static void free_fdesc (fdesc *); static void free_fdesc (fdesc *);
static void pfnote (char *, bool, char *, int, int, long); static void pfnote (char *, bool, char *, ptrdiff_t, intmax_t, intmax_t);
static void invalidate_nodes (fdesc *, node **); static void invalidate_nodes (fdesc *, node **);
static void put_entries (node *); static void put_entries (node *);
@ -393,7 +403,7 @@ static char *concat (const char *, const char *, const char *);
static char *skip_spaces (char *); static char *skip_spaces (char *);
static char *skip_non_spaces (char *); static char *skip_non_spaces (char *);
static char *skip_name (char *); static char *skip_name (char *);
static char *savenstr (const char *, int); static char *savenstr (const char *, ptrdiff_t);
static char *savestr (const char *); static char *savestr (const char *);
static char *etags_getcwd (void); static char *etags_getcwd (void);
static char *relative_filename (char *, char *); static char *relative_filename (char *, char *);
@ -403,9 +413,11 @@ static bool filename_is_absolute (char *f);
static void canonicalize_filename (char *); static void canonicalize_filename (char *);
static char *etags_mktmp (void); static char *etags_mktmp (void);
static void linebuffer_init (linebuffer *); static void linebuffer_init (linebuffer *);
static void linebuffer_setlen (linebuffer *, int); static void linebuffer_setlen (linebuffer *, ptrdiff_t);
static void *xmalloc (size_t); static void *xmalloc (ptrdiff_t) ATTRIBUTE_MALLOC_SIZE ((1));
static void *xrealloc (void *, size_t); static void *xnmalloc (ptrdiff_t, ptrdiff_t) ATTRIBUTE_MALLOC_SIZE ((1,2));
static void *xnrealloc (void *, ptrdiff_t, ptrdiff_t)
ATTRIBUTE_ALLOC_SIZE ((2,3));
static char searchar = '/'; /* use /.../ searches */ static char searchar = '/'; /* use /.../ searches */
@ -420,12 +432,12 @@ static ptrdiff_t whatlen_max; /* maximum length of any 'what' member */
static fdesc *fdhead; /* head of file description list */ static fdesc *fdhead; /* head of file description list */
static fdesc *curfdp; /* current file description */ static fdesc *curfdp; /* current file description */
static char *infilename; /* current input file name */ static char *infilename; /* current input file name */
static int lineno; /* line number of current line */ static intmax_t lineno; /* line number of current line */
static long charno; /* current character number */ static intmax_t charno; /* current character number */
static long linecharno; /* charno of start of current line */ static intmax_t linecharno; /* charno of start of current line */
static char *dbp; /* pointer to start of current tag */ static char *dbp; /* pointer to start of current tag */
static const int invalidcharno = -1; static intmax_t const invalidcharno = -1;
static node *nodehead; /* the head of the binary tree of tags */ static node *nodehead; /* the head of the binary tree of tags */
static node *last_node; /* the last node created */ static node *last_node; /* the last node created */
@ -1070,7 +1082,7 @@ int
main (int argc, char **argv) main (int argc, char **argv)
{ {
int i; int i;
unsigned int nincluded_files; int nincluded_files;
char **included_files; char **included_files;
argument *argbuffer; argument *argbuffer;
int current_arg, file_count; int current_arg, file_count;
@ -1484,7 +1496,7 @@ get_language_from_interpreter (char *interpreter)
* Return a language given the file name. * Return a language given the file name.
*/ */
static language * static language *
get_language_from_filename (char *file, int case_sensitive) get_language_from_filename (char *file, bool case_sensitive)
{ {
language *lang; language *lang;
const char **name, **ext, *suffix; const char **name, **ext, *suffix;
@ -1918,26 +1930,26 @@ find_entries (FILE *inf)
*/ */
static void static void
make_tag (const char *name, /* tag name, or NULL if unnamed */ make_tag (const char *name, /* tag name, or NULL if unnamed */
int namelen, /* tag length */ ptrdiff_t namelen, /* tag length */
bool is_func, /* tag is a function */ bool is_func, /* tag is a function */
char *linestart, /* start of the line where tag is */ char *linestart, /* start of the line where tag is */
int linelen, /* length of the line where tag is */ ptrdiff_t linelen, /* length of the line where tag is */
int lno, /* line number */ intmax_t lno, /* line number */
long int cno) /* character number */ intmax_t cno) /* character number */
{ {
bool named = (name != NULL && namelen > 0); bool named = (name != NULL && namelen > 0);
char *nname = NULL; char *nname = NULL;
if (debug) if (debug)
fprintf (stderr, "%s on %s:%d: %s\n", fprintf (stderr, "%s on %s:%"PRIdMAX": %s\n",
named ? name : "(unnamed)", curfdp->taggedfname, lno, linestart); named ? name : "(unnamed)", curfdp->taggedfname, lno, linestart);
if (!CTAGS && named) /* maybe set named to false */ if (!CTAGS && named) /* maybe set named to false */
/* Let's try to make an implicit tag name, that is, create an unnamed tag /* Let's try to make an implicit tag name, that is, create an unnamed tag
such that etags.el can guess a name from it. */ such that etags.el can guess a name from it. */
{ {
int i; ptrdiff_t i;
register const char *cp = name; const char *cp = name;
for (i = 0; i < namelen; i++) for (i = 0; i < namelen; i++)
if (notinname (*cp++)) if (notinname (*cp++))
@ -1963,8 +1975,8 @@ make_tag (const char *name, /* tag name, or NULL if unnamed */
/* Record a tag. */ /* Record a tag. */
static void static void
pfnote (char *name, bool is_func, char *linestart, int linelen, int lno, pfnote (char *name, bool is_func, char *linestart, ptrdiff_t linelen,
long int cno) intmax_t lno, intmax_t cno)
/* tag name, or NULL if unnamed */ /* tag name, or NULL if unnamed */
/* tag is a function */ /* tag is a function */
/* start of the line where tag is */ /* start of the line where tag is */
@ -2197,7 +2209,8 @@ add_node (node *np, node **cur_node_p)
if (!no_warnings) if (!no_warnings)
{ {
fprintf (stderr, fprintf (stderr,
"Duplicate entry in file %s, line %d: %s\n", ("Duplicate entry in file %s, "
"line %"PRIdMAX": %s\n"),
np->fdp->infname, lineno, np->name); np->fdp->infname, lineno, np->name);
fprintf (stderr, "Second entry ignored\n"); fprintf (stderr, "Second entry ignored\n");
} }
@ -2293,12 +2306,12 @@ invalidate_nodes (fdesc *badfdp, node **npp)
} }
static int total_size_of_entries (node *); static ptrdiff_t total_size_of_entries (node *);
static int number_len (long) ATTRIBUTE_CONST; static int number_len (intmax_t) ATTRIBUTE_CONST;
/* Length of a non-negative number's decimal representation. */ /* Length of a non-negative number's decimal representation. */
static int static int
number_len (long int num) number_len (intmax_t num)
{ {
int len = 1; int len = 1;
while ((num /= 10) > 0) while ((num /= 10) > 0)
@ -2312,10 +2325,10 @@ number_len (long int num)
* This count is irrelevant with etags.el since emacs 19.34 at least, * This count is irrelevant with etags.el since emacs 19.34 at least,
* but is still supplied for backward compatibility. * but is still supplied for backward compatibility.
*/ */
static int static ptrdiff_t
total_size_of_entries (register node *np) total_size_of_entries (node *np)
{ {
register int total = 0; ptrdiff_t total = 0;
for (; np != NULL; np = np->right) for (; np != NULL; np = np->right)
if (np->valid) if (np->valid)
@ -2323,7 +2336,7 @@ total_size_of_entries (register node *np)
total += strlen (np->regex) + 1; /* pat\177 */ total += strlen (np->regex) + 1; /* pat\177 */
if (np->name != NULL) if (np->name != NULL)
total += strlen (np->name) + 1; /* name\001 */ total += strlen (np->name) + 1; /* name\001 */
total += number_len ((long) np->lno) + 1; /* lno, */ total += number_len (np->lno) + 1; /* lno, */
if (np->cno != invalidcharno) /* cno */ if (np->cno != invalidcharno) /* cno */
total += number_len (np->cno); total += number_len (np->cno);
total += 1; /* newline */ total += 1; /* newline */
@ -2347,7 +2360,7 @@ put_entry (node *np)
if (fdp != np->fdp) if (fdp != np->fdp)
{ {
fdp = np->fdp; fdp = np->fdp;
fprintf (tagf, "\f\n%s,%d\n", fprintf (tagf, "\f\n%s,%"PRIdPTR"\n",
fdp->taggedfname, total_size_of_entries (np)); fdp->taggedfname, total_size_of_entries (np));
fdp->written = true; fdp->written = true;
} }
@ -2358,9 +2371,9 @@ put_entry (node *np)
fputs (np->name, tagf); fputs (np->name, tagf);
fputc ('\001', tagf); fputc ('\001', tagf);
} }
fprintf (tagf, "%d,", np->lno); fprintf (tagf, "%"PRIdMAX",", np->lno);
if (np->cno != invalidcharno) if (np->cno != invalidcharno)
fprintf (tagf, "%ld", np->cno); fprintf (tagf, "%"PRIdMAX, np->cno);
fputs ("\n", tagf); fputs ("\n", tagf);
} }
else else
@ -2372,10 +2385,10 @@ put_entry (node *np)
if (cxref_style) if (cxref_style)
{ {
if (vgrind_style) if (vgrind_style)
fprintf (stdout, "%s %s %d\n", fprintf (stdout, "%s %s %"PRIdMAX"\n",
np->name, np->fdp->taggedfname, (np->lno + 63) / 64); np->name, np->fdp->taggedfname, (np->lno + 63) / 64);
else else
fprintf (stdout, "%-16s %3d %-16s %s\n", fprintf (stdout, "%-16s %3"PRIdMAX" %-16s %s\n",
np->name, np->lno, np->fdp->taggedfname, np->regex); np->name, np->lno, np->fdp->taggedfname, np->regex);
} }
else else
@ -2397,7 +2410,7 @@ put_entry (node *np)
} }
else else
{ /* anything else; text pattern inadequate */ { /* anything else; text pattern inadequate */
fprintf (tagf, "%d", np->lno); fprintf (tagf, "%"PRIdMAX, np->lno);
} }
putc ('\n', tagf); putc ('\n', tagf);
} }
@ -2591,7 +2604,7 @@ hash (const char *str, int len)
} }
static struct C_stab_entry * static struct C_stab_entry *
in_word_set (register const char *str, register unsigned int len) in_word_set (const char *str, ptrdiff_t len)
{ {
enum enum
{ {
@ -2658,9 +2671,9 @@ in_word_set (register const char *str, register unsigned int len)
/*%>*/ /*%>*/
static enum sym_type static enum sym_type
C_symtype (char *str, int len, int c_ext) C_symtype (char *str, ptrdiff_t len, int c_ext)
{ {
register struct C_stab_entry *se = in_word_set (str, len); struct C_stab_entry *se = in_word_set (str, len);
if (se == NULL || (se->c_ext && !(c_ext & se->c_ext))) if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
return st_none; return st_none;
@ -2770,8 +2783,8 @@ static enum
static struct tok static struct tok
{ {
char *line; /* string containing the token */ char *line; /* string containing the token */
int offset; /* where the token starts in LINE */ ptrdiff_t offset; /* where the token starts in LINE */
int length; /* token length */ ptrdiff_t length; /* token length */
/* /*
The previous members can be used to pass strings around for generic The previous members can be used to pass strings around for generic
purposes. The following ones specifically refer to creating tags. In this purposes. The following ones specifically refer to creating tags. In this
@ -2782,23 +2795,23 @@ static struct tok
invalidated whenever a state machine is invalidated whenever a state machine is
reset prematurely */ reset prematurely */
bool named; /* create a named tag */ bool named; /* create a named tag */
int lineno; /* source line number of tag */ intmax_t lineno; /* source line number of tag */
long linepos; /* source char number of tag */ intmax_t linepos; /* source char number of tag */
} token; /* latest token read */ } token; /* latest token read */
/* /*
* Variables and functions for dealing with nested structures. * Variables and functions for dealing with nested structures.
* Idea by Mykola Dzyuba <mdzyuba@yahoo.com> (2001) * Idea by Mykola Dzyuba <mdzyuba@yahoo.com> (2001)
*/ */
static void pushclass_above (int, char *, int); static void pushclass_above (ptrdiff_t, char *, ptrdiff_t);
static void popclass_above (int); static void popclass_above (ptrdiff_t);
static void write_classname (linebuffer *, const char *qualifier); static void write_classname (linebuffer *, const char *qualifier);
static struct { static struct {
char **cname; /* nested class names */ char **cname; /* nested class names */
int *bracelev; /* nested class brace level */ ptrdiff_t *bracelev; /* nested class brace level */
int nl; /* class nesting level (elements used) */ ptrdiff_t nl; /* class nesting level (elements used) */
int size; /* length of the array */ ptrdiff_t size; /* length of the array */
} cstack; /* stack for nested declaration tags */ } cstack; /* stack for nested declaration tags */
/* Current struct nesting depth (namespace, class, struct, union, enum). */ /* Current struct nesting depth (namespace, class, struct, union, enum). */
#define nestlev (cstack.nl) #define nestlev (cstack.nl)
@ -2807,17 +2820,17 @@ static struct {
&& bracelev == cstack.bracelev[nestlev-1] + 1) && bracelev == cstack.bracelev[nestlev-1] + 1)
static void static void
pushclass_above (int bracelev, char *str, int len) pushclass_above (ptrdiff_t bracelev, char *str, ptrdiff_t len)
{ {
int nl; ptrdiff_t nl;
popclass_above (bracelev); popclass_above (bracelev);
nl = cstack.nl; nl = cstack.nl;
if (nl >= cstack.size) if (nl >= cstack.size)
{ {
int size = cstack.size *= 2; xrnew (cstack.cname, cstack.size, 2);
xrnew (cstack.cname, size, char *); xrnew (cstack.bracelev, cstack.size, 2);
xrnew (cstack.bracelev, size, int); cstack.size *= 2;
} }
assert (nl == 0 || cstack.bracelev[nl-1] < bracelev); assert (nl == 0 || cstack.bracelev[nl-1] < bracelev);
cstack.cname[nl] = (str == NULL) ? NULL : savenstr (str, len); cstack.cname[nl] = (str == NULL) ? NULL : savenstr (str, len);
@ -2826,11 +2839,9 @@ pushclass_above (int bracelev, char *str, int len)
} }
static void static void
popclass_above (int bracelev) popclass_above (ptrdiff_t bracelev)
{ {
int nl; for (ptrdiff_t nl = cstack.nl - 1;
for (nl = cstack.nl - 1;
nl >= 0 && cstack.bracelev[nl] >= bracelev; nl >= 0 && cstack.bracelev[nl] >= bracelev;
nl--) nl--)
{ {
@ -2842,8 +2853,7 @@ popclass_above (int bracelev)
static void static void
write_classname (linebuffer *cn, const char *qualifier) write_classname (linebuffer *cn, const char *qualifier)
{ {
int i, len; ptrdiff_t len;
int qlen = strlen (qualifier);
if (cstack.nl == 0 || cstack.cname[0] == NULL) if (cstack.nl == 0 || cstack.cname[0] == NULL)
{ {
@ -2857,18 +2867,22 @@ write_classname (linebuffer *cn, const char *qualifier)
linebuffer_setlen (cn, len); linebuffer_setlen (cn, len);
strcpy (cn->buffer, cstack.cname[0]); strcpy (cn->buffer, cstack.cname[0]);
} }
for (i = 1; i < cstack.nl; i++) for (ptrdiff_t i = 1; i < cstack.nl; i++)
{ {
char *s = cstack.cname[i]; char *s = cstack.cname[i];
if (s == NULL) if (s == NULL)
continue; continue;
linebuffer_setlen (cn, len + qlen + strlen (s)); int qlen = strlen (qualifier);
len += sprintf (cn->buffer + len, "%s%s", qualifier, s); ptrdiff_t slen = strlen (s);
linebuffer_setlen (cn, len + qlen + slen);
memcpyz (stpcpy (cn->buffer + len, qualifier), s, slen);
len += qlen + slen;
} }
} }
static bool consider_token (char *, int, int, int *, int, int, bool *); static bool consider_token (char *, ptrdiff_t, int, int *,
ptrdiff_t, ptrdiff_t, bool *);
static void make_C_tag (bool); static void make_C_tag (bool);
/* /*
@ -2889,8 +2903,8 @@ static void make_C_tag (bool);
*/ */
static bool static bool
consider_token (char *str, int len, int c, int *c_extp, consider_token (char *str, ptrdiff_t len, int c, int *c_extp,
int bracelev, int parlev, bool *is_func_or_var) ptrdiff_t bracelev, ptrdiff_t parlev, bool *is_func_or_var)
/* IN: token pointer */ /* IN: token pointer */
/* IN: token length */ /* IN: token length */
/* IN: first char after the token */ /* IN: first char after the token */
@ -2903,7 +2917,7 @@ consider_token (char *str, int len, int c, int *c_extp,
structtype is the type of the preceding struct-like keyword, and structtype is the type of the preceding struct-like keyword, and
structbracelev is the brace level where it has been seen. */ structbracelev is the brace level where it has been seen. */
static enum sym_type structtype; static enum sym_type structtype;
static int structbracelev; static ptrdiff_t structbracelev;
static enum sym_type toktype; static enum sym_type toktype;
@ -3098,8 +3112,7 @@ consider_token (char *str, int len, int c, int *c_extp,
fvdef = fvnone; fvdef = fvnone;
objdef = omethodtag; objdef = omethodtag;
linebuffer_setlen (&token_name, len); linebuffer_setlen (&token_name, len);
memcpy (token_name.buffer, str, len); memcpyz (token_name.buffer, str, len);
token_name.buffer[len] = '\0';
return true; return true;
} }
return false; return false;
@ -3113,11 +3126,10 @@ consider_token (char *str, int len, int c, int *c_extp,
objdef = omethodtag; objdef = omethodtag;
if (class_qualify) if (class_qualify)
{ {
int oldlen = token_name.len; ptrdiff_t oldlen = token_name.len;
fvdef = fvnone; fvdef = fvnone;
linebuffer_setlen (&token_name, oldlen + len); linebuffer_setlen (&token_name, oldlen + len);
memcpy (token_name.buffer + oldlen, str, len); memcpyz (token_name.buffer + oldlen, str, len);
token_name.buffer[oldlen + len] = '\0';
} }
return true; return true;
} }
@ -3228,7 +3240,7 @@ consider_token (char *str, int len, int c, int *c_extp,
*/ */
static struct static struct
{ {
long linepos; intmax_t linepos;
linebuffer lb; linebuffer lb;
} lbs[2]; } lbs[2];
@ -3302,19 +3314,19 @@ C_entries (int c_ext, FILE *inf)
/* extension of C */ /* extension of C */
/* input file */ /* input file */
{ {
register char c; /* latest char read; '\0' for end of line */ char c; /* latest char read; '\0' for end of line */
register char *lp; /* pointer one beyond the character `c' */ char *lp; /* pointer one beyond the character `c' */
int curndx, newndx; /* indices for current and new lb */ bool curndx, newndx; /* indices for current and new lb */
register int tokoff; /* offset in line of start of current token */ ptrdiff_t tokoff; /* offset in line of start of current token */
register int toklen; /* length of current token */ ptrdiff_t toklen; /* length of current token */
const char *qualifier; /* string used to qualify names */ const char *qualifier; /* string used to qualify names */
int qlen; /* length of qualifier */ int qlen; /* length of qualifier */
int bracelev; /* current brace level */ ptrdiff_t bracelev; /* current brace level */
int bracketlev; /* current bracket level */ ptrdiff_t bracketlev; /* current bracket level */
int parlev; /* current parenthesis level */ ptrdiff_t parlev; /* current parenthesis level */
int attrparlev; /* __attribute__ parenthesis level */ ptrdiff_t attrparlev; /* __attribute__ parenthesis level */
int templatelev; /* current template level */ ptrdiff_t templatelev; /* current template level */
int typdefbracelev; /* bracelev where a typedef struct body begun */ ptrdiff_t typdefbracelev; /* bracelev where a typedef struct body begun */
bool incomm, inquote, inchar, quotednl, midtoken; bool incomm, inquote, inchar, quotednl, midtoken;
bool yacc_rules; /* in the rules part of a yacc file */ bool yacc_rules; /* in the rules part of a yacc file */
struct tok savetoken = {0}; /* token saved during preprocessor handling */ struct tok savetoken = {0}; /* token saved during preprocessor handling */
@ -3327,7 +3339,7 @@ C_entries (int c_ext, FILE *inf)
cstack.size = (DEBUG) ? 1 : 4; cstack.size = (DEBUG) ? 1 : 4;
cstack.nl = 0; cstack.nl = 0;
cstack.cname = xnew (cstack.size, char *); cstack.cname = xnew (cstack.size, char *);
cstack.bracelev = xnew (cstack.size, int); cstack.bracelev = xnew (cstack.size, ptrdiff_t);
} }
tokoff = toklen = typdefbracelev = 0; /* keep compiler quiet */ tokoff = toklen = typdefbracelev = 0; /* keep compiler quiet */
@ -3579,20 +3591,19 @@ C_entries (int c_ext, FILE *inf)
{ {
if (class_qualify) if (class_qualify)
{ {
int len;
write_classname (&token_name, qualifier); write_classname (&token_name, qualifier);
len = token_name.len; ptrdiff_t len = token_name.len;
linebuffer_setlen (&token_name, linebuffer_setlen (&token_name,
len + qlen + toklen); len + qlen + toklen);
sprintf (token_name.buffer + len, "%s%.*s", memcpyz (stpcpy (token_name.buffer + len,
qualifier, toklen, qualifier),
newlb.buffer + tokoff); newlb.buffer + tokoff, toklen);
} }
else else
{ {
linebuffer_setlen (&token_name, toklen); linebuffer_setlen (&token_name, toklen);
sprintf (token_name.buffer, "%.*s", memcpyz (token_name.buffer,
toklen, newlb.buffer + tokoff); newlb.buffer + tokoff, toklen);
} }
token.named = true; token.named = true;
} }
@ -3601,17 +3612,19 @@ C_entries (int c_ext, FILE *inf)
{ {
if (class_qualify) if (class_qualify)
{ {
int len = strlen (objtag) + 2 + toklen; ptrdiff_t len = strlen (objtag) + 2 + toklen;
linebuffer_setlen (&token_name, len); linebuffer_setlen (&token_name, len);
sprintf (token_name.buffer, "%s(%.*s)", char *p1 = stpcpy (token_name.buffer, objtag);
objtag, toklen, char *p2 = stpcpy (p1, "(");
newlb.buffer + tokoff); char *p3 = mempcpy (p2, newlb.buffer + tokoff,
toklen);
strcpy (p3, ")");
} }
else else
{ {
linebuffer_setlen (&token_name, toklen); linebuffer_setlen (&token_name, toklen);
sprintf (token_name.buffer, "%.*s", memcpyz (token_name.buffer,
toklen, newlb.buffer + tokoff); newlb.buffer + tokoff, toklen);
} }
token.named = true; token.named = true;
} }
@ -3625,8 +3638,8 @@ C_entries (int c_ext, FILE *inf)
/* GNU DEFUN and similar macros */ /* GNU DEFUN and similar macros */
{ {
bool defun = (newlb.buffer[tokoff] == 'F'); bool defun = (newlb.buffer[tokoff] == 'F');
int off = tokoff; ptrdiff_t off = tokoff;
int len = toklen; ptrdiff_t len = toklen;
if (defun) if (defun)
{ {
@ -3635,9 +3648,8 @@ C_entries (int c_ext, FILE *inf)
/* First, tag it as its C name */ /* First, tag it as its C name */
linebuffer_setlen (&token_name, toklen); linebuffer_setlen (&token_name, toklen);
memcpy (token_name.buffer, memcpyz (token_name.buffer,
newlb.buffer + tokoff, toklen); newlb.buffer + tokoff, toklen);
token_name.buffer[toklen] = '\0';
token.named = true; token.named = true;
token.lineno = lineno; token.lineno = lineno;
token.offset = tokoff; token.offset = tokoff;
@ -3650,9 +3662,8 @@ C_entries (int c_ext, FILE *inf)
/* Rewrite the tag so that emacs lisp DEFUNs /* Rewrite the tag so that emacs lisp DEFUNs
can be found also by their elisp name */ can be found also by their elisp name */
linebuffer_setlen (&token_name, len); linebuffer_setlen (&token_name, len);
memcpy (token_name.buffer, memcpyz (token_name.buffer,
newlb.buffer + off, len); newlb.buffer + off, len);
token_name.buffer[len] = '\0';
if (defun) if (defun)
while (--len >= 0) while (--len >= 0)
if (token_name.buffer[len] == '_') if (token_name.buffer[len] == '_')
@ -3662,9 +3673,8 @@ C_entries (int c_ext, FILE *inf)
else else
{ {
linebuffer_setlen (&token_name, toklen); linebuffer_setlen (&token_name, toklen);
memcpy (token_name.buffer, memcpyz (token_name.buffer,
newlb.buffer + tokoff, toklen); newlb.buffer + tokoff, toklen);
token_name.buffer[toklen] = '\0';
/* Name macros and members. */ /* Name macros and members. */
token.named = (structdef == stagseen token.named = (structdef == stagseen
|| typdef == ttypeseen || typdef == ttypeseen
@ -3790,7 +3800,7 @@ C_entries (int c_ext, FILE *inf)
objdef = omethodcolon; objdef = omethodcolon;
if (class_qualify) if (class_qualify)
{ {
int toklen = token_name.len; ptrdiff_t toklen = token_name.len;
linebuffer_setlen (&token_name, toklen + 1); linebuffer_setlen (&token_name, toklen + 1);
strcpy (token_name.buffer + toklen, ":"); strcpy (token_name.buffer + toklen, ":");
} }
@ -4061,7 +4071,7 @@ C_entries (int c_ext, FILE *inf)
} }
if (uqname > token_name.buffer) if (uqname > token_name.buffer)
{ {
int uqlen = strlen (uqname); ptrdiff_t uqlen = strlen (uqname);
linebuffer_setlen (&token_name, uqlen); linebuffer_setlen (&token_name, uqlen);
memmove (token_name.buffer, uqname, uqlen + 1); memmove (token_name.buffer, uqname, uqlen + 1);
} }
@ -4979,12 +4989,11 @@ Ruby_functions (FILE *inf)
size_t name_len = cp - np + 1; size_t name_len = cp - np + 1;
char *wr_name = xnew (name_len + 1, char); char *wr_name = xnew (name_len + 1, char);
memcpy (wr_name, np, name_len - 1); strcpy (mempcpy (wr_name, np, name_len - 1), "=");
memcpy (wr_name + name_len - 1, "=", 2);
pfnote (wr_name, true, lb.buffer, cp - lb.buffer + 1, pfnote (wr_name, true, lb.buffer, cp - lb.buffer + 1,
lineno, linecharno); lineno, linecharno);
if (debug) if (debug)
fprintf (stderr, "%s on %s:%d: %s\n", wr_name, fprintf (stderr, "%s on %s:%"PRIdMAX": %s\n", wr_name,
curfdp->taggedfname, lineno, lb.buffer); curfdp->taggedfname, lineno, lb.buffer);
continuation = false; continuation = false;
} }
@ -5178,8 +5187,8 @@ static void
Pascal_functions (FILE *inf) Pascal_functions (FILE *inf)
{ {
linebuffer tline; /* mostly copied from C_entries */ linebuffer tline; /* mostly copied from C_entries */
long save_lcno; intmax_t save_lcno, save_lineno;
int save_lineno, namelen, taglen; ptrdiff_t namelen, taglen;
char c, *name; char c, *name;
bool /* each of these flags is true if: */ bool /* each of these flags is true if: */
@ -5455,7 +5464,7 @@ Lua_functions (FILE *inf)
if (tp_dot || tp_colon) if (tp_dot || tp_colon)
{ {
char *p = tp_dot > tp_colon ? tp_dot : tp_colon; char *p = tp_dot > tp_colon ? tp_dot : tp_colon;
int len_add = p - tag_name + 1; ptrdiff_t len_add = p - tag_name + 1;
get_tag (bp + len_add, NULL); get_tag (bp + len_add, NULL);
} }
@ -5656,7 +5665,7 @@ TeX_commands (FILE *inf)
if (strneq (cp, key->buffer, key->len)) if (strneq (cp, key->buffer, key->len))
{ {
char *p; char *p;
int namelen, linelen; ptrdiff_t namelen, linelen;
bool opgrp = false; bool opgrp = false;
cp = skip_spaces (cp + key->len); cp = skip_spaces (cp + key->len);
@ -5693,8 +5702,8 @@ TeX_commands (FILE *inf)
static void static void
TEX_decode_env (const char *evarname, const char *defenv) TEX_decode_env (const char *evarname, const char *defenv)
{ {
register const char *env, *p; const char *env, *p;
int i, len; ptrdiff_t len;
/* Append default string to environment. */ /* Append default string to environment. */
env = getenv (evarname); env = getenv (evarname);
@ -5711,7 +5720,7 @@ TEX_decode_env (const char *evarname, const char *defenv)
/* Unpack environment string into token table. Be careful about */ /* Unpack environment string into token table. Be careful about */
/* zero-length strings (leading ':', "::" and trailing ':') */ /* zero-length strings (leading ':', "::" and trailing ':') */
for (i = 0; *env != '\0';) for (ptrdiff_t i = 0; *env != '\0'; )
{ {
p = strchr (env, ':'); p = strchr (env, ':');
if (!p) /* End of environment string. */ if (!p) /* End of environment string. */
@ -5811,8 +5820,7 @@ HTML_labels (FILE *inf)
for (end = dbp; *end != '\0' && intoken (*end); end++) for (end = dbp; *end != '\0' && intoken (*end); end++)
continue; continue;
linebuffer_setlen (&token_name, end - dbp); linebuffer_setlen (&token_name, end - dbp);
memcpy (token_name.buffer, dbp, end - dbp); memcpyz (token_name.buffer, dbp, end - dbp);
token_name.buffer[end - dbp] = '\0';
dbp = end; dbp = end;
intag = false; /* we found what we looked for */ intag = false; /* we found what we looked for */
@ -5906,11 +5914,10 @@ Prolog_functions (FILE *inf)
tags later. */ tags later. */
if (allocated <= len) if (allocated <= len)
{ {
xrnew (last, len + 1, char); xrnew (last, len + 1, 1);
allocated = len + 1; allocated = len + 1;
} }
memcpy (last, cp, len); memcpyz (last, cp, len);
last[len] = '\0';
lastlen = len; lastlen = len;
} }
} }
@ -6031,9 +6038,9 @@ prolog_atom (char *s, size_t pos)
* Assumes that Erlang functions start at column 0. * Assumes that Erlang functions start at column 0.
* Original code by Anders Lindgren (1996) * Original code by Anders Lindgren (1996)
*/ */
static int erlang_func (char *, char *, ptrdiff_t, ptrdiff_t *); static ptrdiff_t erlang_func (char *, char *, ptrdiff_t, ptrdiff_t *);
static void erlang_attribute (char *); static void erlang_attribute (char *);
static int erlang_atom (char *); static ptrdiff_t erlang_atom (char *);
static void static void
Erlang_functions (FILE *inf) Erlang_functions (FILE *inf)
@ -6070,11 +6077,10 @@ Erlang_functions (FILE *inf)
tags later. */ tags later. */
if (allocated <= len) if (allocated <= len)
{ {
xrnew (last, len + 1, char); xrnew (last, len + 1, 1);
allocated = len + 1; allocated = len + 1;
} }
memcpy (last, cp + name_offset, len); memcpyz (last, cp + name_offset, len);
last[len] = '\0';
lastlen = len; lastlen = len;
} }
} }
@ -6093,7 +6099,7 @@ Erlang_functions (FILE *inf)
* Return the size of the name of the function, or 0 if no function * Return the size of the name of the function, or 0 if no function
* was found. * was found.
*/ */
static int static ptrdiff_t
erlang_func (char *s, char *last, ptrdiff_t lastlen, ptrdiff_t *name_offset) erlang_func (char *s, char *last, ptrdiff_t lastlen, ptrdiff_t *name_offset)
{ {
char *name = s; char *name = s;
@ -6133,15 +6139,13 @@ static void
erlang_attribute (char *s) erlang_attribute (char *s)
{ {
char *cp = s; char *cp = s;
int pos;
int len;
if ((LOOKING_AT (cp, "-define") || LOOKING_AT (cp, "-record")) if ((LOOKING_AT (cp, "-define") || LOOKING_AT (cp, "-record"))
&& *cp++ == '(') && *cp++ == '(')
{ {
cp = skip_spaces (cp); cp = skip_spaces (cp);
len = erlang_atom (cp); ptrdiff_t len = erlang_atom (cp);
pos = cp + len - s; ptrdiff_t pos = cp + len - s;
if (len > 0) if (len > 0)
{ {
/* If the name is quoted, the quotes are not part of the name. */ /* If the name is quoted, the quotes are not part of the name. */
@ -6161,10 +6165,10 @@ erlang_attribute (char *s)
* Consume an Erlang atom (or variable). * Consume an Erlang atom (or variable).
* Return the number of bytes consumed, or -1 if there was an error. * Return the number of bytes consumed, or -1 if there was an error.
*/ */
static int static ptrdiff_t
erlang_atom (char *s) erlang_atom (char *s)
{ {
int pos = 0; ptrdiff_t pos = 0;
if (c_isalpha (s[pos]) || s[pos] == '_') if (c_isalpha (s[pos]) || s[pos] == '_')
{ {
@ -6437,10 +6441,9 @@ static char *
substitute (char *in, char *out, struct re_registers *regs) substitute (char *in, char *out, struct re_registers *regs)
{ {
char *result, *t; char *result, *t;
int size, dig, diglen;
result = NULL; result = NULL;
size = strlen (out); ptrdiff_t size = strlen (out);
/* Pass 1: figure out how much to allocate by finding all \N strings. */ /* Pass 1: figure out how much to allocate by finding all \N strings. */
if (out[size - 1] == '\\') if (out[size - 1] == '\\')
@ -6450,8 +6453,8 @@ substitute (char *in, char *out, struct re_registers *regs)
t = strchr (t + 2, '\\')) t = strchr (t + 2, '\\'))
if (c_isdigit (t[1])) if (c_isdigit (t[1]))
{ {
dig = t[1] - '0'; int dig = t[1] - '0';
diglen = regs->end[dig] - regs->start[dig]; ptrdiff_t diglen = regs->end[dig] - regs->start[dig];
size += diglen - 2; size += diglen - 2;
} }
else else
@ -6464,8 +6467,8 @@ substitute (char *in, char *out, struct re_registers *regs)
for (t = result; *out != '\0'; out++) for (t = result; *out != '\0'; out++)
if (*out == '\\' && c_isdigit (*++out)) if (*out == '\\' && c_isdigit (*++out))
{ {
dig = *out - '0'; int dig = *out - '0';
diglen = regs->end[dig] - regs->start[dig]; ptrdiff_t diglen = regs->end[dig] - regs->start[dig];
memcpy (t, in + regs->start[dig], diglen); memcpy (t, in + regs->start[dig], diglen);
t += diglen; t += diglen;
} }
@ -6474,7 +6477,7 @@ substitute (char *in, char *out, struct re_registers *regs)
*t = '\0'; *t = '\0';
assert (t <= result + size); assert (t <= result + size);
assert (t - result == (int)strlen (result)); assert (t == result + strlen (result));
return result; return result;
} }
@ -6511,7 +6514,7 @@ regex_tag_multiline (void)
for (rp = p_head; rp != NULL; rp = rp->p_next) for (rp = p_head; rp != NULL; rp = rp->p_next)
{ {
int match = 0; ptrdiff_t match = 0;
if (!rp->multi_line) if (!rp->multi_line)
continue; /* skip normal regexps */ continue; /* skip normal regexps */
@ -6572,7 +6575,7 @@ regex_tag_multiline (void)
charno - linecharno + 1, lineno, linecharno); charno - linecharno + 1, lineno, linecharno);
if (debug) if (debug)
fprintf (stderr, "%s on %s:%d: %s\n", fprintf (stderr, "%s on %s:%"PRIdMAX": %s\n",
name ? name : "(unnamed)", curfdp->taggedfname, name ? name : "(unnamed)", curfdp->taggedfname,
lineno, buffer + linecharno); lineno, buffer + linecharno);
} }
@ -6589,7 +6592,7 @@ regex_tag_multiline (void)
static bool static bool
nocase_tail (const char *cp) nocase_tail (const char *cp)
{ {
int len = 0; ptrdiff_t len = 0;
while (*cp != '\0' && c_tolower (*cp) == c_tolower (dbp[len])) while (*cp != '\0' && c_tolower (*cp) == c_tolower (dbp[len]))
cp++, len++; cp++, len++;
@ -6648,7 +6651,7 @@ get_lispy_tag (register char *bp)
* If multi-line regular expressions are requested, each line read is * If multi-line regular expressions are requested, each line read is
* appended to `filebuf'. * appended to `filebuf'.
*/ */
static long static ptrdiff_t
readline_internal (linebuffer *lbp, FILE *stream, char const *filename) readline_internal (linebuffer *lbp, FILE *stream, char const *filename)
{ {
char *buffer = lbp->buffer; char *buffer = lbp->buffer;
@ -6664,8 +6667,8 @@ readline_internal (linebuffer *lbp, FILE *stream, char const *filename)
if (p == pend) if (p == pend)
{ {
/* We're at the end of linebuffer: expand it. */ /* We're at the end of linebuffer: expand it. */
xrnew (buffer, lbp->size, 2);
lbp->size *= 2; lbp->size *= 2;
xrnew (buffer, lbp->size, char);
p += buffer - lbp->buffer; p += buffer - lbp->buffer;
pend = buffer + lbp->size; pend = buffer + lbp->size;
lbp->buffer = buffer; lbp->buffer = buffer;
@ -6702,13 +6705,12 @@ readline_internal (linebuffer *lbp, FILE *stream, char const *filename)
while (filebuf.size <= filebuf.len + lbp->len + 1) /* +1 for \n */ while (filebuf.size <= filebuf.len + lbp->len + 1) /* +1 for \n */
{ {
/* Expand filebuf. */ /* Expand filebuf. */
xrnew (filebuf.buffer, filebuf.size, 2);
filebuf.size *= 2; filebuf.size *= 2;
xrnew (filebuf.buffer, filebuf.size, char);
} }
memcpy (filebuf.buffer + filebuf.len, lbp->buffer, lbp->len); strcpy (mempcpy (filebuf.buffer + filebuf.len, lbp->buffer, lbp->len),
filebuf.len += lbp->len; "\n");
filebuf.buffer[filebuf.len++] = '\n'; filebuf.len += lbp->len + 1;
filebuf.buffer[filebuf.len] = '\0';
} }
return lbp->len + chars_deleted; return lbp->len + chars_deleted;
@ -6722,10 +6724,8 @@ readline_internal (linebuffer *lbp, FILE *stream, char const *filename)
static void static void
readline (linebuffer *lbp, FILE *stream) readline (linebuffer *lbp, FILE *stream)
{ {
long result;
linecharno = charno; /* update global char number of line start */ linecharno = charno; /* update global char number of line start */
result = readline_internal (lbp, stream, infilename); /* read line */ ptrdiff_t result = readline_internal (lbp, stream, infilename);
lineno += 1; /* increment global line number */ lineno += 1; /* increment global line number */
charno += result; /* increment global char number */ charno += result; /* increment global char number */
@ -6737,10 +6737,10 @@ readline (linebuffer *lbp, FILE *stream)
/* Check whether this is a #line directive. */ /* Check whether this is a #line directive. */
if (result > 12 && strneq (lbp->buffer, "#line ", 6)) if (result > 12 && strneq (lbp->buffer, "#line ", 6))
{ {
unsigned int lno; intmax_t lno;
int start = 0; int start = 0;
if (sscanf (lbp->buffer, "#line %u \"%n", &lno, &start) >= 1 if (sscanf (lbp->buffer, "#line %"SCNdMAX" \"%n", &lno, &start) >= 1
&& start > 0) /* double quote character found */ && start > 0) /* double quote character found */
{ {
char *endp = lbp->buffer + start; char *endp = lbp->buffer + start;
@ -6850,7 +6850,7 @@ readline (linebuffer *lbp, FILE *stream)
} /* if #line directives should be considered */ } /* if #line directives should be considered */
{ {
int match; ptrdiff_t match;
regexp *rp; regexp *rp;
char *name; char *name;
@ -6900,7 +6900,7 @@ readline (linebuffer *lbp, FILE *stream)
/* Force explicit tag name, if a name is there. */ /* Force explicit tag name, if a name is there. */
pfnote (name, true, lbp->buffer, match, lineno, linecharno); pfnote (name, true, lbp->buffer, match, lineno, linecharno);
if (debug) if (debug)
fprintf (stderr, "%s on %s:%d: %s\n", fprintf (stderr, "%s on %s:%"PRIdMAX": %s\n",
name ? name : "(unnamed)", curfdp->taggedfname, name ? name : "(unnamed)", curfdp->taggedfname,
lineno, lbp->buffer); lineno, lbp->buffer);
} }
@ -6925,11 +6925,11 @@ savestr (const char *cp)
} }
/* /*
* Return a pointer to a space of size LEN+1 allocated with xnew where * Return a pointer to a space of size LEN+1 allocated with xnew
* the string CP has been copied for at most the first LEN characters. * with a copy of CP (containing LEN bytes) followed by a NUL byte.
*/ */
static char * static char *
savenstr (const char *cp, int len) savenstr (const char *cp, ptrdiff_t len)
{ {
char *dp = xnew (len + 1, char); char *dp = xnew (len + 1, char);
dp[len] = '\0'; dp[len] = '\0';
@ -7013,13 +7013,9 @@ verror (char const *format, va_list ap)
static char * static char *
concat (const char *s1, const char *s2, const char *s3) concat (const char *s1, const char *s2, const char *s3)
{ {
int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); ptrdiff_t len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
char *result = xnew (len1 + len2 + len3 + 1, char); char *result = xnew (len1 + len2 + len3 + 1, char);
strcpy (stpcpy (stpcpy (result, s1), s2), s3);
strcpy (result, s1);
strcpy (result + len1, s2);
strcpy (result + len1 + len2, s3);
return result; return result;
} }
@ -7029,16 +7025,16 @@ concat (const char *s1, const char *s2, const char *s3)
static char * static char *
etags_getcwd (void) etags_getcwd (void)
{ {
int bufsize = 200; ptrdiff_t bufsize = 200;
char *path = xnew (bufsize, char); char *path = xnew (bufsize, char);
while (getcwd (path, bufsize) == NULL) while (getcwd (path, bufsize) == NULL)
{ {
if (errno != ERANGE) if (errno != ERANGE)
pfatal ("getcwd"); pfatal ("getcwd");
bufsize *= 2;
free (path); free (path);
path = xnew (bufsize, char); path = xnmalloc (bufsize, 2 * sizeof *path);
bufsize *= 2;
} }
canonicalize_filename (path); canonicalize_filename (path);
@ -7099,7 +7095,7 @@ static char *
relative_filename (char *file, char *dir) relative_filename (char *file, char *dir)
{ {
char *fp, *dp, *afn, *res; char *fp, *dp, *afn, *res;
int i; ptrdiff_t i;
/* Find the common root of file and dir (with a trailing slash). */ /* Find the common root of file and dir (with a trailing slash). */
afn = absolute_filename (file, cwd); afn = absolute_filename (file, cwd);
@ -7282,32 +7278,54 @@ linebuffer_init (linebuffer *lbp)
/* Set the minimum size of a string contained in a linebuffer. */ /* Set the minimum size of a string contained in a linebuffer. */
static void static void
linebuffer_setlen (linebuffer *lbp, int toksize) linebuffer_setlen (linebuffer *lbp, ptrdiff_t toksize)
{ {
while (lbp->size <= toksize) if (lbp->size <= toksize)
{ {
lbp->size *= 2; ptrdiff_t multiplier = toksize / lbp->size + 1;
xrnew (lbp->buffer, lbp->size, char); xrnew (lbp->buffer, lbp->size, multiplier);
lbp->size *= multiplier;
} }
lbp->len = toksize; lbp->len = toksize;
} }
/* Like malloc but get fatal error if memory is exhausted. */ /* Memory allocators with a fatal error if memory is exhausted. */
static void * ATTRIBUTE_MALLOC
xmalloc (size_t size) static void
memory_full (void)
{ {
fatal ("virtual memory exhausted");
}
static void *
xmalloc (ptrdiff_t size)
{
if (SIZE_MAX < size)
memory_full ();
void *result = malloc (size); void *result = malloc (size);
if (result == NULL) if (result == NULL)
fatal ("virtual memory exhausted"); memory_full ();
return result; return result;
} }
static void * static void *
xrealloc (void *ptr, size_t size) xnmalloc (ptrdiff_t nitems, ptrdiff_t item_size)
{ {
void *result = realloc (ptr, size); ptrdiff_t nbytes;
if (result == NULL) if (INT_MULTIPLY_WRAPV (nitems, item_size, &nbytes))
fatal ("virtual memory exhausted"); memory_full ();
return xmalloc (nbytes);
}
static void *
xnrealloc (void *pa, ptrdiff_t nitems, ptrdiff_t item_size)
{
ptrdiff_t nbytes;
if (INT_MULTIPLY_WRAPV (nitems, item_size, &nbytes) || SIZE_MAX < nbytes)
memory_full ();
void *result = realloc (pa, nbytes);
if (!result)
memory_full ();
return result; return result;
} }

View file

@ -116,6 +116,7 @@
# lstat \ # lstat \
# manywarnings \ # manywarnings \
# memmem-simple \ # memmem-simple \
# mempcpy \
# memrchr \ # memrchr \
# minmax \ # minmax \
# mkostemp \ # mkostemp \
@ -2027,6 +2028,17 @@ EXTRA_libgnu_a_SOURCES += memmem.c
endif endif
## end gnulib module memmem-simple ## end gnulib module memmem-simple
## begin gnulib module mempcpy
ifeq (,$(OMIT_GNULIB_MODULE_mempcpy))
EXTRA_DIST += mempcpy.c
EXTRA_libgnu_a_SOURCES += mempcpy.c
endif
## end gnulib module mempcpy
## begin gnulib module memrchr ## begin gnulib module memrchr
ifeq (,$(OMIT_GNULIB_MODULE_memrchr)) ifeq (,$(OMIT_GNULIB_MODULE_memrchr))

28
lib/mempcpy.c Normal file
View file

@ -0,0 +1,28 @@
/* Copy memory area and return pointer after last written byte.
Copyright (C) 2003, 2007, 2009-2019 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <https://www.gnu.org/licenses/>. */
#include <config.h>
/* Specification. */
#include <string.h>
/* Copy N bytes of SRC to DEST, return pointer to bytes after the
last written byte. */
void *
mempcpy (void *dest, const void *src, size_t n)
{
return (char *) memcpy (dest, src, n) + n;
}

View file

@ -118,6 +118,7 @@ AC_DEFUN([gl_EARLY],
# Code from module malloca: # Code from module malloca:
# Code from module manywarnings: # Code from module manywarnings:
# Code from module memmem-simple: # Code from module memmem-simple:
# Code from module mempcpy:
# Code from module memrchr: # Code from module memrchr:
# Code from module minmax: # Code from module minmax:
# Code from module mkostemp: # Code from module mkostemp:
@ -327,6 +328,12 @@ AC_DEFUN([gl_INIT],
AC_LIBOBJ([memmem]) AC_LIBOBJ([memmem])
fi fi
gl_STRING_MODULE_INDICATOR([memmem]) gl_STRING_MODULE_INDICATOR([memmem])
gl_FUNC_MEMPCPY
if test $HAVE_MEMPCPY = 0; then
AC_LIBOBJ([mempcpy])
gl_PREREQ_MEMPCPY
fi
gl_STRING_MODULE_INDICATOR([mempcpy])
gl_FUNC_MEMRCHR gl_FUNC_MEMRCHR
if test $ac_cv_func_memrchr = no; then if test $ac_cv_func_memrchr = no; then
AC_LIBOBJ([memrchr]) AC_LIBOBJ([memrchr])
@ -954,6 +961,7 @@ AC_DEFUN([gl_FILE_LIST], [
lib/md5.c lib/md5.c
lib/md5.h lib/md5.h
lib/memmem.c lib/memmem.c
lib/mempcpy.c
lib/memrchr.c lib/memrchr.c
lib/minmax.h lib/minmax.h
lib/mkostemp.c lib/mkostemp.c
@ -1094,6 +1102,7 @@ AC_DEFUN([gl_FILE_LIST], [
m4/mbstate_t.m4 m4/mbstate_t.m4
m4/md5.m4 m4/md5.m4
m4/memmem.m4 m4/memmem.m4
m4/mempcpy.m4
m4/memrchr.m4 m4/memrchr.m4
m4/minmax.m4 m4/minmax.m4
m4/mkostemp.m4 m4/mkostemp.m4

26
m4/mempcpy.m4 Normal file
View file

@ -0,0 +1,26 @@
# mempcpy.m4 serial 11
dnl Copyright (C) 2003-2004, 2006-2007, 2009-2019 Free Software Foundation,
dnl Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
AC_DEFUN([gl_FUNC_MEMPCPY],
[
dnl Persuade glibc <string.h> to declare mempcpy().
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
dnl The mempcpy() declaration in lib/string.in.h uses 'restrict'.
AC_REQUIRE([AC_C_RESTRICT])
AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
AC_CHECK_FUNCS([mempcpy])
if test $ac_cv_func_mempcpy = no; then
HAVE_MEMPCPY=0
fi
])
# Prerequisites of lib/mempcpy.c.
AC_DEFUN([gl_PREREQ_MEMPCPY], [
:
])