Sun Jan 13 06:10:34 2019 UTC ()
Always return from expandm() with errno unaltered, so on the
off chance it failed, there's still the possibility that whatever
processes the result will be able to deal with the %m that would
(presumably) be left in the format string.

And as a frill, don't call strerror() until we know we are
going to use its result (still call it only once, no matter
how many %m's are in the format string).


(kre)
diff -r1.6 -r1.7 src/lib/libwrap/expandm.c

cvs diff -r1.6 -r1.7 src/lib/libwrap/expandm.c (expand / switch to unified diff)

--- src/lib/libwrap/expandm.c 2019/01/13 01:32:51 1.6
+++ src/lib/libwrap/expandm.c 2019/01/13 06:10:34 1.7
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: expandm.c,v 1.6 2019/01/13 01:32:51 christos Exp $ */ 1/* $NetBSD: expandm.c,v 1.7 2019/01/13 06:10:34 kre Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2018 The NetBSD Foundation, Inc. 4 * Copyright (c) 2018 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas. 8 * by Christos Zoulas.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -19,89 +19,94 @@ @@ -19,89 +19,94 @@
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31#include <sys/cdefs.h> 31#include <sys/cdefs.h>
32__RCSID("$NetBSD: expandm.c,v 1.6 2019/01/13 01:32:51 christos Exp $"); 32__RCSID("$NetBSD: expandm.c,v 1.7 2019/01/13 06:10:34 kre Exp $");
33 33
34#include <limits.h> 34#include <limits.h>
35#include <stdio.h> 35#include <stdio.h>
36#include <string.h> 36#include <string.h>
37#include <stdlib.h> 37#include <stdlib.h>
38#include <errno.h> 38#include <errno.h>
39 39
40#include "expandm.h" 40#include "expandm.h"
41 41
42#ifdef TEST 42#ifdef TEST
43#undef INT_MAX 43#undef INT_MAX
44#define INT_MAX 31 44#define INT_MAX 31
45#endif 45#endif
46 46
47 47
48const char * __attribute__((__format_arg__(1))) 48const char * __attribute__((__format_arg__(1)))
49expandm(const char *fmt, const char *sf, char **rbuf) 49expandm(const char *fmt, const char *sf, char **rbuf)
50{ 50{
51 const char *e = strerror(errno); 51 const int err = errno;
 52 const char *e = NULL;
52 char *buf, *m, *nbuf; 53 char *buf, *m, *nbuf;
53 const char *ptr; 54 const char *ptr;
54 55
55 for (ptr = fmt, buf = NULL; (m = strstr(ptr, "%m")) != NULL; 56 for (ptr = fmt, buf = NULL; (m = strstr(ptr, "%m")) != NULL;
56 ptr = m + 2) 57 ptr = m + 2)
57 { 58 {
58 size_t cnt = 0; 59 size_t cnt = 0;
59 60
60 for (char *p = m; p >= ptr && *p == '%'; p--) 61 for (char *p = m; p >= ptr && *p == '%'; p--)
61 cnt++; 62 cnt++;
62 63
63 if (__predict_false((m - ptr) >= INT_MAX)) { 64 if (__predict_false((m - ptr) >= INT_MAX)) {
64 size_t blen = buf ? strlen(buf) : 0; 65 size_t blen = buf ? strlen(buf) : 0;
65 size_t nlen = (size_t)(m - ptr); 66 size_t nlen = (size_t)(m - ptr);
66 67
67 nbuf = realloc(buf, blen + nlen + 1); 68 nbuf = realloc(buf, blen + nlen + 1);
68 if (nbuf == NULL) 69 if (nbuf == NULL)
69 goto out; 70 goto out;
70 71
71 memcpy(nbuf + blen, ptr, nlen); 72 memcpy(nbuf + blen, ptr, nlen);
72 nbuf[blen + nlen] = '\0'; 73 nbuf[blen + nlen] = '\0';
73 ptr += nlen; 74 ptr += nlen;
74 buf = nbuf; 75 buf = nbuf;
75 } 76 }
76 77
 78 if (__predict_true(e == NULL && (cnt & 1) != 0))
 79 e = strerror(err);
77 if (asprintf(&nbuf, "%s%.*s%s", buf ? buf : "", 80 if (asprintf(&nbuf, "%s%.*s%s", buf ? buf : "",
78 (int)(m - ptr), ptr, (cnt & 1) ? e : "%m") == -1) 81 (int)(m - ptr), ptr, (cnt & 1) ? e : "%m") == -1)
79 goto out; 82 goto out;
80 free(buf); 83 free(buf);
81 buf = nbuf; 84 buf = nbuf;
82 } 85 }
83 86
84 if (asprintf(&nbuf, "%s%s%s", buf ? buf : "", ptr, sf ? sf : "") == -1) 87 if (asprintf(&nbuf, "%s%s%s", buf ? buf : "", ptr, sf ? sf : "") == -1)
85 goto out; 88 goto out;
86 89
87 free(buf); 90 free(buf);
88 if (rbuf) 91 if (rbuf)
89 *rbuf = nbuf; 92 *rbuf = nbuf;
 93 errno = err;
90 return nbuf; 94 return nbuf;
91out: 95out:
92 free(buf); 96 free(buf);
93 if (rbuf) 97 if (rbuf)
94 *rbuf = NULL; 98 *rbuf = NULL;
 99 errno = err;
95 return fmt; 100 return fmt;
96} 101}
97 102
98#ifdef TEST 103#ifdef TEST
99int 104int
100main(int argc, char *argv[]) 105main(int argc, char *argv[])
101{ 106{
102 errno = ERANGE; 107 errno = ERANGE;
103 printf("%s\n", expandm(argc > 1 ? argv[1] : "Message %%m=%m: %%%m%%", 108 printf("%s\n", expandm(argc > 1 ? argv[1] : "Message %%m=%m: %%%m%%",
104 "...", NULL)); 109 "...", NULL));
105 return 0; 110 return 0;
106} 111}
107#endif 112#endif