summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2018-01-16 15:44:34 +0100
committerUlf Hermann <ulf.hermann@qt.io>2018-01-16 15:26:23 +0000
commit6165f644c98238036fd7353f2b1de6f07376c30a (patch)
treef3d23925c9b16cfe7bca800f78e41558f8916e12
parentd9483eb79086970df1dd875f6914bd0a442e8566 (diff)
The shifting-instead-of-masking trick outlined there is very clever, but only works incidentally. Explicitly preserve the sign, and still shift, but shift unsigned values for which left-shifting bits out is defined. make distcheck complains about the previous code with sufficiently recent compilers with UB sanitizers. Change-Id: I6f2942f307a2c154ea7d414a85c60e4f088fc918 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
-rw-r--r--libgnu/argp-parse.c15
1 files changed, 9 insertions, 6 deletions
diff --git a/libgnu/argp-parse.c b/libgnu/argp-parse.c
index 3f723bc8..dc3106e7 100644
--- a/libgnu/argp-parse.c
+++ b/libgnu/argp-parse.c
@@ -740,12 +740,15 @@ parser_parse_opt (struct parser *parser, int opt, char *val)
}
}
else
- /* A long option. We use shifts instead of masking for extracting
- the user value in order to preserve the sign. */
- err =
- group_parse (&parser->groups[group_key - 1], &parser->state,
- (opt << GROUP_BITS) >> GROUP_BITS,
- parser->opt_data.optarg);
+ {
+ uint maskable = (uint)(opt < 0 ? -opt : opt);
+ maskable = (maskable << GROUP_BITS) >> GROUP_BITS;
+ int masked = opt < 0 ? -(int)maskable : (int)maskable;
+
+ err =
+ group_parse (&parser->groups[group_key - 1], &parser->state,
+ masked, parser->opt_data.optarg);
+ }
if (err == EBADKEY)
/* At least currently, an option not recognized is an error in the