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

View File

@ -116,6 +116,7 @@
# lstat \
# manywarnings \
# memmem-simple \
# mempcpy \
# memrchr \
# minmax \
# mkostemp \
@ -2027,6 +2028,17 @@ EXTRA_libgnu_a_SOURCES += memmem.c
endif
## 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
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 manywarnings:
# Code from module memmem-simple:
# Code from module mempcpy:
# Code from module memrchr:
# Code from module minmax:
# Code from module mkostemp:
@ -327,6 +328,12 @@ AC_DEFUN([gl_INIT],
AC_LIBOBJ([memmem])
fi
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
if test $ac_cv_func_memrchr = no; then
AC_LIBOBJ([memrchr])
@ -954,6 +961,7 @@ AC_DEFUN([gl_FILE_LIST], [
lib/md5.c
lib/md5.h
lib/memmem.c
lib/mempcpy.c
lib/memrchr.c
lib/minmax.h
lib/mkostemp.c
@ -1094,6 +1102,7 @@ AC_DEFUN([gl_FILE_LIST], [
m4/mbstate_t.m4
m4/md5.m4
m4/memmem.m4
m4/mempcpy.m4
m4/memrchr.m4
m4/minmax.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], [
:
])