diff options
author | dormando <dormando@rydia.net> | 2020-11-11 15:50:08 -0800 |
---|---|---|
committer | dormando <dormando@rydia.net> | 2020-11-11 15:50:08 -0800 |
commit | 19aac5aeca5aaf588dc58d5c04264c6be14ff7c0 (patch) | |
tree | d164bc933a89c40e76d5b89abe856a3c24a60e9e | |
parent | 27b73a4e272280b9a52bc1b098f758af69e28956 (diff) | |
download | memcached-19aac5aeca5aaf588dc58d5c04264c6be14ff7c0.tar.gz |
portability fix for getsubopt
in the deferred IO patch I'd cribbed some code from another PR which
turned out to use a non-portable return state from getsubopt. On BSD
systems the subopts_value string is simply empty on a non-match.
Fixing this portably looks gross but I couldn't come up with a better
option... and frankly if we're going to pass options through DSO
submodules in the future this is better anyway.
-rw-r--r-- | memcached.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/memcached.c b/memcached.c index d84b0eb..e60f2c3 100644 --- a/memcached.c +++ b/memcached.c @@ -4952,6 +4952,11 @@ int main (int argc, char **argv) { subopts_orig = subopts = strdup(optarg); /* getsubopt() changes the original args */ while (*subopts != '\0') { + // BSD getsubopt (at least) has undefined behavior on -1, so + // if we want to retry the getsubopt call in submodules we + // need an extra layer of string copies. + char *subopts_temp_o = NULL; + char *subopts_temp = subopts_temp_o = strdup(subopts); switch (getsubopt(&subopts, subopts_tokens, &subopts_value)) { case MAXCONNS_FAST: @@ -5317,16 +5322,19 @@ int main (int argc, char **argv) { default: #ifdef EXTSTORE // TODO: differentiating response code. - if (storage_read_config(storage_cf, &subopts_value)) { + if (storage_read_config(storage_cf, &subopts_temp)) { return 1; } #else - printf("Illegal suboption \"%s\"\n", subopts_value); + printf("Illegal suboption \"%s\"\n", subopts_temp); return 1; #endif + } // switch + if (subopts_temp_o) { + free(subopts_temp_o); } - } + } // while free(subopts_orig); break; default: |