Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/usr.bin/xlint/lint1 lint: fix crash from ckgetopt.c 1.2 and ...



details:   https://anonhg.NetBSD.org/src/rev/3ae81cabeee8
branches:  trunk
changeset: 952872:3ae81cabeee8
user:      rillig <rillig%NetBSD.org@localhost>
date:      Sat Feb 20 09:57:02 2021 +0000

description:
lint: fix crash from ckgetopt.c 1.2 and document the data structures

diffstat:

 usr.bin/xlint/lint1/ckgetopt.c |  35 ++++++++++++++++++++++++++++-------
 1 files changed, 28 insertions(+), 7 deletions(-)

diffs (80 lines):

diff -r 98dbfd45affb -r 3ae81cabeee8 usr.bin/xlint/lint1/ckgetopt.c
--- a/usr.bin/xlint/lint1/ckgetopt.c    Sat Feb 20 09:51:20 2021 +0000
+++ b/usr.bin/xlint/lint1/ckgetopt.c    Sat Feb 20 09:57:02 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ckgetopt.c,v 1.3 2021/02/20 01:18:02 christos Exp $ */
+/* $NetBSD: ckgetopt.c,v 1.4 2021/02/20 09:57:02 rillig Exp $ */
 
 /*-
  * Copyright (c) 2021 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: ckgetopt.c,v 1.3 2021/02/20 01:18:02 christos Exp $");
+__RCSID("$NetBSD: ckgetopt.c,v 1.4 2021/02/20 09:57:02 rillig Exp $");
 #endif
 
 #include <stdbool.h>
@@ -51,10 +51,28 @@
  */
 
 struct {
+       /*
+        * 0    means outside a while loop with a getopt call.
+        * 1    means directly inside a while loop with a getopt call.
+        * > 1  means in a nested while loop; this is used for finishing the
+        *      check at the correct point.
+        */
+       int while_level;
+
+       /*
+        * The options string from the getopt call.  Whenever an option is
+        * handled by a case label, it is set to ' ' in unhandled_options.
+        * In the end, only ' ' and ':' should remain in unhandled_options.
+        */
        pos_t options_pos;
        char *options;
        char *unhandled_options;
-       int while_level;
+
+       /*
+        * The nesting level of switch statements, is only modified if
+        * while_level > 0.  Only the case labels at switch_level == 1 are
+        * relevant, all nested case labels are ignored.
+        */
        int switch_level;
 } ck;
 
@@ -100,7 +118,9 @@
 static void
 check_unlisted_option(char opt)
 {
-       if (opt == '?' || ck.options == NULL)
+       lint_assert(ck.options != NULL);
+
+       if (opt == '?')
                return;
 
        const char *optptr = strchr(ck.options, opt);
@@ -116,8 +136,7 @@
 static void
 check_unhandled_option(void)
 {
-       if (ck.unhandled_options == NULL)
-               return;
+       lint_assert(ck.unhandled_options != NULL);
 
        for (const char *opt = ck.unhandled_options; *opt != '\0'; opt++) {
                if (*opt == ' ' || *opt == ':')
@@ -135,7 +154,9 @@
 void
 check_getopt_begin_while(const tnode_t *tn)
 {
-       if (ck.while_level == 0 && is_getopt_call(tn, &ck.options)) {
+       if (ck.while_level == 0) {
+               if (!is_getopt_call(tn, &ck.options))
+                       return;
                ck.unhandled_options = xstrdup(ck.options);
                ck.options_pos = curr_pos;
        }



Home | Main Index | Thread Index | Old Index