summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2021-08-26 10:08:00 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2021-08-26 15:44:40 -0700
commit56b322516f8471584c8c67d2f749ae635560eeca (patch)
treebf63b196435c09a51e448097fcb41be365f71d2f
parent8fb3a827a2635915a9baa3926e6be6fad7b9ab2d (diff)
downloadgnulib-56b322516f8471584c8c67d2f749ae635560eeca.tar.gz
regex: use C99-style array arg syntax
This should help with some static checking. Derived from a suggestion by Martin Sebor in: https://sourceware.org/pipermail/libc-alpha/2021-August/130336.html This also ports recent and relevant Glibc changes to Gnulib and prepares to copy back. * lib/cdefs.h (__ARG_NELTS): New macro. * lib/regex.c: Ignore -Wvla for the whole file. * lib/regex.h (_ARG_NELTS_, _Attr_access_): New macros. Ignore -Wvla when declaring regexec. * lib/regex.h (re_compile_pattern, re_search, re_search_2) (re_match, re_match_2, regcomp, regerror): Use _Attr_access_ where that could help static checking. * lib/regexec.c (regexec, __compat_regexec, re_copy_regs) (re_search_internal, proceed_next_node, push_fail_stack) (pop_fail_stack, set_regs, update_regs): Use __ARG_NELTS for each array parameter whose size is another arg, but which might be null.
-rw-r--r--ChangeLog15
-rw-r--r--lib/cdefs.h9
-rw-r--r--lib/regex.c1
-rw-r--r--lib/regex.h52
-rw-r--r--lib/regexec.c78
5 files changed, 114 insertions, 41 deletions
diff --git a/ChangeLog b/ChangeLog
index 785fbc44b3..80c2b83846 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2021-08-26 Paul Eggert <eggert@cs.ucla.edu>
+
+ regex: use C99-style array arg syntax
+ This should help with some static checking.
+ Derived from a suggestion by Martin Sebor in:
+ https://sourceware.org/pipermail/libc-alpha/2021-August/130336.html
+ * lib/cdefs.h (__ARG_NELTS): New macro.
+ * lib/regex.c: Ignore -Wvla for the whole file.
+ * lib/regex.h (_ARG_NELTS_): New macro.
+ Ignore -Wvla when declaring regexec.
+ * lib/regexec.c (regexec, __compat_regexec, re_copy_regs)
+ (re_search_internal, proceed_next_node, push_fail_stack)
+ (pop_fail_stack, set_regs, update_regs):
+ Use __ARG_NELTS for each array parameter whose size is another arg.
+
2021-08-25 Bruno Haible <bruno@clisp.org>
execute tests: Fix test failure when libtool is in use.
diff --git a/lib/cdefs.h b/lib/cdefs.h
index 4dac9d264d..13c5542bfd 100644
--- a/lib/cdefs.h
+++ b/lib/cdefs.h
@@ -634,4 +634,13 @@ _Static_assert (0, "IEEE 128-bits long double requires redirection on this platf
# define __attribute_returns_twice__ /* Ignore. */
#endif
+/* Specify the number of elements of a function's array parameter,
+ as in 'int f (int n, int a[__ARG_NELTS (n)]);'. */
+#if (defined __STDC_VERSION__ && 199901L <= __STDC_VERSION__ \
+ && !defined __STDC_NO_VLA__)
+# define __ARG_NELTS(n) n
+#else
+# define __ARG_NELTS(n)
+#endif
+
#endif /* sys/cdefs.h */
diff --git a/lib/regex.c b/lib/regex.c
index 7296be0f08..d32863972c 100644
--- a/lib/regex.c
+++ b/lib/regex.c
@@ -24,6 +24,7 @@
# if __GNUC_PREREQ (4, 6)
# pragma GCC diagnostic ignored "-Wsuggest-attribute=pure"
+# pragma GCC diagnostic ignored "-Wvla"
# endif
# if __GNUC_PREREQ (4, 3)
# pragma GCC diagnostic ignored "-Wold-style-definition"
diff --git a/lib/regex.h b/lib/regex.h
index 8e4ef45578..540c323163 100644
--- a/lib/regex.h
+++ b/lib/regex.h
@@ -522,6 +522,32 @@ typedef struct
/* Declarations for routines. */
+#ifndef _ARG_NELTS_
+# ifdef __ARG_NELTS
+# define _ARG_NELTS_(arg) __ARG_NELTS (arg)
+# elif (defined __STDC_VERSION__ && 199901L <= __STDC_VERSION__ \
+ && !defined __STDC_NO_VLA__)
+# define _ARG_NELTS_(n) n
+# else
+# define _ARG_NELTS_(n)
+# endif
+#endif
+
+#if defined __GNUC__ && 4 < __GNUC__ + (6 <= __GNUC_MINOR__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wvla"
+#endif
+
+#ifndef _Attr_access_
+# ifdef __attr_access
+# define _Attr_access_(arg) __attr_access (arg)
+# elif defined __GNUC__ && 10 <= __GNUC__
+# define _Attr_access_(x) __attribute__ ((__access__ x))
+# else
+# define _Attr_access_(x)
+# endif
+#endif
+
#ifdef __USE_GNU
/* Sets the current default syntax to SYNTAX, and return the old syntax.
You can also simply assign to the 're_syntax_options' variable. */
@@ -536,7 +562,8 @@ extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax);
'regcomp', with a malloc'ed value, or set to NULL before calling
'regfree'. */
extern const char *re_compile_pattern (const char *__pattern, size_t __length,
- struct re_pattern_buffer *__buffer);
+ struct re_pattern_buffer *__buffer)
+ _Attr_access_ ((__read_only__, 1, 2));
/* Compile a fastmap for the compiled pattern in BUFFER; used to
@@ -553,7 +580,8 @@ extern int re_compile_fastmap (struct re_pattern_buffer *__buffer);
extern regoff_t re_search (struct re_pattern_buffer *__buffer,
const char *__String, regoff_t __length,
regoff_t __start, regoff_t __range,
- struct re_registers *__regs);
+ struct re_registers *__regs)
+ _Attr_access_ ((__read_only__, 2, 3));
/* Like 're_search', but search in the concatenation of STRING1 and
@@ -563,14 +591,17 @@ extern regoff_t re_search_2 (struct re_pattern_buffer *__buffer,
const char *__string2, regoff_t __length2,
regoff_t __start, regoff_t __range,
struct re_registers *__regs,
- regoff_t __stop);
+ regoff_t __stop)
+ _Attr_access_ ((__read_only__, 2, 3))
+ _Attr_access_ ((__read_only__, 4, 5));
/* Like 're_search', but return how many characters in STRING the regexp
in BUFFER matched, starting at position START. */
extern regoff_t re_match (struct re_pattern_buffer *__buffer,
const char *__String, regoff_t __length,
- regoff_t __start, struct re_registers *__regs);
+ regoff_t __start, struct re_registers *__regs)
+ _Attr_access_ ((__read_only__, 2, 3));
/* Relates to 're_match' as 're_search_2' relates to 're_search'. */
@@ -578,7 +609,9 @@ extern regoff_t re_match_2 (struct re_pattern_buffer *__buffer,
const char *__string1, regoff_t __length1,
const char *__string2, regoff_t __length2,
regoff_t __start, struct re_registers *__regs,
- regoff_t __stop);
+ regoff_t __stop)
+ _Attr_access_ ((__read_only__, 2, 3))
+ _Attr_access_ ((__read_only__, 4, 5));
/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
@@ -648,13 +681,18 @@ extern int regcomp (regex_t *_Restrict_ __preg,
extern int regexec (const regex_t *_Restrict_ __preg,
const char *_Restrict_ __String, size_t __nmatch,
regmatch_t __pmatch[_Restrict_arr_],
- int __eflags);
+ int __eflags)
+ _Attr_access_ ((__write_only__, 4, 3));
extern size_t regerror (int __errcode, const regex_t *_Restrict_ __preg,
- char *_Restrict_ __errbuf, size_t __errbuf_size);
+ char *_Restrict_ __errbuf, size_t __errbuf_size)
+ _Attr_access_ ((__write_only__, 3, 4));
extern void regfree (regex_t *__preg);
+#if defined __GNUC__ && 4 < __GNUC__ + (6 <= __GNUC_MINOR__)
+# pragma GCC diagnostic pop
+#endif
#ifdef __cplusplus
}
diff --git a/lib/regexec.c b/lib/regexec.c
index 5e4eb497a6..da1fb7fafa 100644
--- a/lib/regexec.c
+++ b/lib/regexec.c
@@ -31,11 +31,11 @@ static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop,
static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
re_dfastate_t **limited_sts, Idx last_node,
Idx last_str_idx);
-static reg_errcode_t re_search_internal (const regex_t *preg,
- const char *string, Idx length,
- Idx start, Idx last_start, Idx stop,
- size_t nmatch, regmatch_t pmatch[],
- int eflags);
+static reg_errcode_t
+re_search_internal (const regex_t *preg, const char *string, Idx length,
+ Idx start, Idx last_start, Idx stop, size_t nmatch,
+ regmatch_t pmatch[__ARG_NELTS (static nmatch)],
+ int eflags);
static regoff_t re_search_2_stub (struct re_pattern_buffer *bufp,
const char *string1, Idx length1,
const char *string2, Idx length2,
@@ -47,23 +47,29 @@ static regoff_t re_search_stub (struct re_pattern_buffer *bufp,
regoff_t range, Idx stop,
struct re_registers *regs,
bool ret_len);
-static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch,
- Idx nregs, int regs_allocated);
+static unsigned re_copy_regs (struct re_registers *regs, Idx nregs,
+ regmatch_t pmatch[__ARG_NELTS (static nregs)],
+ int regs_allocated);
static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx);
static Idx check_matching (re_match_context_t *mctx, bool fl_longest_match,
Idx *p_match_first);
static Idx check_halt_state_context (const re_match_context_t *mctx,
const re_dfastate_t *state, Idx idx);
-static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
- regmatch_t *prev_idx_match, Idx cur_node,
- Idx cur_idx, Idx nmatch);
-static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs,
- Idx str_idx, Idx dest_node, Idx nregs,
- regmatch_t *regs, regmatch_t *prevregs,
- re_node_set *eps_via_nodes);
+static void
+update_regs (const re_dfa_t *dfa, Idx nmatch,
+ regmatch_t pmatch[__ARG_NELTS (static nmatch)],
+ regmatch_t prev_idx_match[__ARG_NELTS (static nmatch)],
+ Idx cur_node, Idx cur_idx);
+static reg_errcode_t
+push_fail_stack (struct re_fail_stack_t *fs,
+ Idx str_idx, Idx dest_node, Idx nregs,
+ regmatch_t regs[__ARG_NELTS (static nregs)],
+ regmatch_t prevregs[__ARG_NELTS (static nregs)],
+ re_node_set *eps_via_nodes);
static reg_errcode_t set_regs (const regex_t *preg,
const re_match_context_t *mctx,
- size_t nmatch, regmatch_t *pmatch,
+ size_t nmatch,
+ regmatch_t pmatch[__ARG_NELTS (static nmatch)],
bool fl_backtrack);
static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs);
@@ -191,7 +197,7 @@ static reg_errcode_t extend_buffers (re_match_context_t *mctx, int min_len);
int
regexec (const regex_t *__restrict preg, const char *__restrict string,
- size_t nmatch, regmatch_t pmatch[], int eflags)
+ size_t nmatch, regmatch_t pmatch[__ARG_NELTS (nmatch)], int eflags)
{
reg_errcode_t err;
Idx start, length;
@@ -212,12 +218,8 @@ regexec (const regex_t *__restrict preg, const char *__restrict string,
}
lock_lock (dfa->lock);
- if (preg->no_sub)
- err = re_search_internal (preg, string, length, start, length,
- length, 0, NULL, eflags);
- else
- err = re_search_internal (preg, string, length, start, length,
- length, nmatch, pmatch, eflags);
+ err = re_search_internal (preg, string, length, start, length,
+ length, preg->no_sub ? 0 : nmatch, pmatch, eflags);
lock_unlock (dfa->lock);
return err != REG_NOERROR;
}
@@ -235,7 +237,7 @@ int
attribute_compat_text_section
__compat_regexec (const regex_t *__restrict preg,
const char *__restrict string, size_t nmatch,
- regmatch_t pmatch[], int eflags)
+ regmatch_t pmatch[__ARG_NELTS (nmatch)], int eflags)
{
return regexec (preg, string, nmatch, pmatch,
eflags & (REG_NOTBOL | REG_NOTEOL));
@@ -434,7 +436,7 @@ re_search_stub (struct re_pattern_buffer *bufp, const char *string, Idx length,
else if (regs != NULL)
{
/* If caller wants register contents data back, copy them. */
- bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs,
+ bufp->regs_allocated = re_copy_regs (regs, nregs, pmatch,
bufp->regs_allocated);
if (__glibc_unlikely (bufp->regs_allocated == REGS_UNALLOCATED))
rval = -2;
@@ -457,7 +459,8 @@ re_search_stub (struct re_pattern_buffer *bufp, const char *string, Idx length,
}
static unsigned
-re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, Idx nregs,
+re_copy_regs (struct re_registers *regs, Idx nregs,
+ regmatch_t pmatch[__ARG_NELTS (static nregs)],
int regs_allocated)
{
int rval = REGS_REALLOCATE;
@@ -585,7 +588,8 @@ static reg_errcode_t
__attribute_warn_unused_result__
re_search_internal (const regex_t *preg, const char *string, Idx length,
Idx start, Idx last_start, Idx stop, size_t nmatch,
- regmatch_t pmatch[], int eflags)
+ regmatch_t pmatch[__ARG_NELTS (static nmatch)],
+ int eflags)
{
reg_errcode_t err;
const re_dfa_t *dfa = preg->buffer;
@@ -1210,8 +1214,9 @@ check_halt_state_context (const re_match_context_t *mctx,
return -1 on match failure, -2 on error. */
static Idx
-proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs,
- regmatch_t *prevregs,
+proceed_next_node (const re_match_context_t *mctx, Idx nregs,
+ regmatch_t regs[__ARG_NELTS (static nregs)],
+ regmatch_t prevregs[__ARG_NELTS (static nregs)],
Idx *pidx, Idx node, re_node_set *eps_via_nodes,
struct re_fail_stack_t *fs)
{
@@ -1321,7 +1326,9 @@ proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs,
static reg_errcode_t
__attribute_warn_unused_result__
push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node,
- Idx nregs, regmatch_t *regs, regmatch_t *prevregs,
+ Idx nregs,
+ regmatch_t regs[__ARG_NELTS (static nregs)],
+ regmatch_t prevregs[__ARG_NELTS (static nregs)],
re_node_set *eps_via_nodes)
{
reg_errcode_t err;
@@ -1349,7 +1356,8 @@ push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node,
static Idx
pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx, Idx nregs,
- regmatch_t *regs, regmatch_t *prevregs,
+ regmatch_t regs[__ARG_NELTS (static nregs)],
+ regmatch_t prevregs[__ARG_NELTS (static nregs)],
re_node_set *eps_via_nodes)
{
if (fs == NULL || fs->num == 0)
@@ -1379,7 +1387,7 @@ pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx, Idx nregs,
static reg_errcode_t
__attribute_warn_unused_result__
set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch,
- regmatch_t *pmatch, bool fl_backtrack)
+ regmatch_t pmatch[__ARG_NELTS (static nmatch)], bool fl_backtrack)
{
const re_dfa_t *dfa = preg->buffer;
Idx idx, cur_node;
@@ -1415,7 +1423,7 @@ set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch,
for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;)
{
- update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch);
+ update_regs (dfa, nmatch, pmatch, prev_idx_match, cur_node, idx);
if ((idx == pmatch[0].rm_eo && cur_node == mctx->last_node)
|| (fs && re_node_set_contains (&eps_via_nodes, cur_node)))
@@ -1487,8 +1495,10 @@ free_fail_stack_return (struct re_fail_stack_t *fs)
}
static void
-update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
- regmatch_t *prev_idx_match, Idx cur_node, Idx cur_idx, Idx nmatch)
+update_regs (const re_dfa_t *dfa, Idx nmatch,
+ regmatch_t pmatch[__ARG_NELTS (static nmatch)],
+ regmatch_t prev_idx_match[__ARG_NELTS (static nmatch)],
+ Idx cur_node, Idx cur_idx)
{
int type = dfa->nodes[cur_node].type;
if (type == OP_OPEN_SUBEXP)