From fc5cb9894ea57b7b3eeb9fad1fc2557483fbc65c Mon Sep 17 00:00:00 2001 From: ache Date: Thu, 25 Aug 2016 19:55:31 +0000 Subject: MFC r295632 getln: We cannot expand the buffer beyond INT_MAX (_size overflows). In such cases return ENOMEM. This is a limitation of our implementation, alternatively you may consider getline(3). Differential Revision: https://reviews.freebsd.org/D442 (Partial) Obtained from: Apple Inc. (Libc 997.90.3) --- lib/libc/stdio/fgetln.3 | 5 ++++- lib/libc/stdio/fgetln.c | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/fgetln.3 b/lib/libc/stdio/fgetln.3 index 4b83664..7d4b89a5 100644 --- a/lib/libc/stdio/fgetln.3 +++ b/lib/libc/stdio/fgetln.3 @@ -28,7 +28,7 @@ .\" @(#)fgetln.3 8.3 (Berkeley) 4/19/94 .\" $FreeBSD$ .\" -.Dd April 19, 1994 +.Dd February 15, 2016 .Dt FGETLN 3 .Os .Sh NAME @@ -97,6 +97,9 @@ These changes are lost as soon as the pointer becomes invalid. The argument .Fa stream is not a stream open for reading. +.It Bq Er ENOMEM +The internal line buffer could not be expanded due to lack of available memory, +or because it would need to expand beyond INT_MAX in size. .El .Pp The diff --git a/lib/libc/stdio/fgetln.c b/lib/libc/stdio/fgetln.c index 6546768..1509bc8 100644 --- a/lib/libc/stdio/fgetln.c +++ b/lib/libc/stdio/fgetln.c @@ -37,6 +37,8 @@ static char sccsid[] = "@(#)fgetln.c 8.2 (Berkeley) 1/2/94"; __FBSDID("$FreeBSD$"); #include "namespace.h" +#include +#include #include #include #include @@ -61,6 +63,10 @@ __slbexpand(FILE *fp, size_t newsize) #endif if (fp->_lb._size >= newsize) return (0); + if (newsize > INT_MAX) { + errno = ENOMEM; + return (-1); + } if ((p = realloc(fp->_lb._base, newsize)) == NULL) return (-1); fp->_lb._base = p; @@ -152,7 +158,7 @@ fgetln(FILE *fp, size_t *lenp) } *lenp = len; #ifdef notdef - fp->_lb._base[len] = 0; + fp->_lb._base[len] = '\0'; #endif FUNLOCKFILE(fp); return ((char *)fp->_lb._base); -- cgit v1.1 From 44a2fcec2fdaabcd0d1098de82edc7c928352d9e Mon Sep 17 00:00:00 2001 From: ache Date: Fri, 26 Aug 2016 21:19:23 +0000 Subject: MFC r304703, r304755 1) _locale.h LC_*_MASK bit shifting order was partially broken from the initial commit time at year 2012. Only LC_COLLATE_MASK and LC_CTYPE_MASK are in the right order. The order here should match XLC_* from "xlocale_private.h" which, in turn, match LC_* publicly visible order from which determines how locale components are stored in the structure. LC_*_MASK -> XLC_* translation done as "ffs(mask) - 1" in the querylocale() and equivalent shift loop in the newlocale(), so mapped to some wrong components (excluding two mentioned above). Formally the fix is ABI breakage, but old code using those masks never works properly in any case. Only newlocale() and querylocale() are affected. 2) msgcat.c Use current locale (f.e. set by thread). It was global locale always previously. PR: 211743 --- lib/libc/nls/msgcat.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/nls/msgcat.c b/lib/libc/nls/msgcat.c index 0cba460..b373a3d 100644 --- a/lib/libc/nls/msgcat.c +++ b/lib/libc/nls/msgcat.c @@ -47,7 +47,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -56,7 +55,7 @@ __FBSDID("$FreeBSD$"); #include #include "un-namespace.h" -#include "../locale/setlocale.h" /* for ENCODING_LEN */ +#include "../locale/xlocale_private.h" #define _DEFAULT_NLS_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:/usr/local/share/nls/%L/%N.cat:/usr/local/share/nls/%N/%L" @@ -115,9 +114,10 @@ catopen(const char *name, int type) { struct stat sbuf; struct catentry *np; - char *base, *cptr, *cptr1, *lang, *nlspath, *pathP, *pcode; - char *plang, *pter, *tmpptr; + char *base, *cptr, *cptr1, *nlspath, *pathP, *pcode; + char *plang, *pter; int saverr, spcleft; + const char *lang, *tmpptr; char path[PATH_MAX]; /* sanity checking */ @@ -129,7 +129,7 @@ catopen(const char *name, int type) lang = NULL; else { if (type == NL_CAT_LOCALE) - lang = setlocale(LC_MESSAGES, NULL); + lang = querylocale(LC_MESSAGES_MASK, __get_locale()); else lang = getenv("LANG"); -- cgit v1.1 From d5deef2805b5b8f2ca41fbe42c1456e9ab6a2534 Mon Sep 17 00:00:00 2001 From: ache Date: Sat, 27 Aug 2016 09:58:06 +0000 Subject: MFC r304810 Don't check for __SERR which may stick from one of any previous stdio functions. __SERR is for user and the rest of stdio code do not check it for error sensing internally, only set it. In vf(w)printf.c here it is more easy to save __SERR, clear and restore it. --- lib/libc/stdio/getdelim.c | 4 ++-- lib/libc/stdio/vfprintf.c | 6 ++++++ lib/libc/stdio/vfwprintf.c | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/getdelim.c b/lib/libc/stdio/getdelim.c index d7d5627..7e0b2e2 100644 --- a/lib/libc/stdio/getdelim.c +++ b/lib/libc/stdio/getdelim.c @@ -125,7 +125,7 @@ getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim, if (fp->_r <= 0 && __srefill(fp)) { /* If fp is at EOF already, we just need space for the NUL. */ - if (__sferror(fp) || expandtofit(linep, 1, linecapp)) + if (!__sfeof(fp) || expandtofit(linep, 1, linecapp)) goto error; FUNLOCKFILE(fp); (*linep)[0] = '\0'; @@ -137,7 +137,7 @@ getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim, if (sappend(linep, &linelen, linecapp, fp->_p, fp->_r)) goto error; if (__srefill(fp)) { - if (__sferror(fp)) + if (!__sfeof(fp)) goto error; goto done; /* hit EOF */ } diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c index e54e8ac..bf45bfb 100644 --- a/lib/libc/stdio/vfprintf.c +++ b/lib/libc/stdio/vfprintf.c @@ -364,6 +364,7 @@ __vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap) int nextarg; /* 1-based argument index */ va_list orgap; /* original argument pointer */ char *convbuf; /* wide to multibyte conversion result */ + int savserr; static const char xdigs_lower[16] = "0123456789abcdef"; static const char xdigs_upper[16] = "0123456789ABCDEF"; @@ -460,6 +461,9 @@ __vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap) return (EOF); } + savserr = fp->_flags & __SERR; + fp->_flags &= ~__SERR; + convbuf = NULL; fmt = (char *)fmt0; argtable = NULL; @@ -1031,6 +1035,8 @@ error: free(convbuf); if (__sferror(fp)) ret = EOF; + else + fp->_flags |= savserr; if ((argtable != NULL) && (argtable != statargtable)) free (argtable); return (ret); diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c index b75c504..9a5381d 100644 --- a/lib/libc/stdio/vfwprintf.c +++ b/lib/libc/stdio/vfwprintf.c @@ -444,6 +444,7 @@ __vfwprintf(FILE *fp, locale_t locale, const wchar_t *fmt0, va_list ap) int nextarg; /* 1-based argument index */ va_list orgap; /* original argument pointer */ wchar_t *convbuf; /* multibyte to wide conversion result */ + int savserr; static const char xdigs_lower[16] = "0123456789abcdef"; static const char xdigs_upper[16] = "0123456789ABCDEF"; @@ -536,6 +537,9 @@ __vfwprintf(FILE *fp, locale_t locale, const wchar_t *fmt0, va_list ap) return (EOF); } + savserr = fp->_flags & __SERR; + fp->_flags &= ~__SERR; + convbuf = NULL; fmt = (wchar_t *)fmt0; argtable = NULL; @@ -1096,6 +1100,8 @@ error: free(convbuf); if (__sferror(fp)) ret = EOF; + else + fp->_flags |= savserr; if ((argtable != NULL) && (argtable != statargtable)) free (argtable); return (ret); -- cgit v1.1 From 7767fddf9fce411b32f1cc6cc3b725dc57dead47 Mon Sep 17 00:00:00 2001 From: ache Date: Sat, 27 Aug 2016 10:34:01 +0000 Subject: MFC r304607,r304641,r304819,r304811 1) Don't forget to set __SERR on __slbexpand() error. 2) Remove "Fast path" from fgetwc()/fputwc() since it can't detect encoding errors and ignores them all. One of affected encoding example: US-ASCII 3) Original fgetln() from 44lite return success for line tail errors, i.e. partial line, but set __SERR and errno in the same time, which is inconsistent. Now both OpenBSD and NetBSD return failure, i.e. no line and set error indicators for such case, so make our fgetln() and fgetwln() (as its wide version) compatible with the rest of *BSD. PR: 212033 --- lib/libc/stdio/fgetln.c | 7 +++++-- lib/libc/stdio/fgetwc.c | 13 ++----------- lib/libc/stdio/fgetwln.c | 7 +++++-- lib/libc/stdio/fputwc.c | 16 +++------------- 4 files changed, 15 insertions(+), 28 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/stdio/fgetln.c b/lib/libc/stdio/fgetln.c index 1509bc8..c8e30ee 100644 --- a/lib/libc/stdio/fgetln.c +++ b/lib/libc/stdio/fgetln.c @@ -139,8 +139,11 @@ fgetln(FILE *fp, size_t *lenp) (void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p, len - off); off = len; - if (__srefill(fp)) - break; /* EOF or error: return partial line */ + if (__srefill(fp)) { + if (__sfeof(fp)) + break; + goto error; + } if ((p = memchr((void *)fp->_p, '\n', (size_t)fp->_r)) == NULL) continue; diff --git a/lib/libc/stdio/fgetwc.c b/lib/libc/stdio/fgetwc.c index 52bc988..cf649fd 100644 --- a/lib/libc/stdio/fgetwc.c +++ b/lib/libc/stdio/fgetwc.c @@ -79,18 +79,9 @@ __fgetwc_mbs(FILE *fp, mbstate_t *mbs, int *nread, locale_t locale) size_t nconv; struct xlocale_ctype *l = XLOCALE_CTYPE(locale); - if (fp->_r <= 0 && __srefill(fp)) { - *nread = 0; - return (WEOF); - } - if (MB_CUR_MAX == 1) { - /* Fast path for single-byte encodings. */ - wc = *fp->_p++; - fp->_r--; - *nread = 1; - return (wc); - } *nread = 0; + if (fp->_r <= 0 && __srefill(fp)) + return (WEOF); do { nconv = l->__mbrtowc(&wc, fp->_p, fp->_r, mbs); if (nconv == (size_t)-1) diff --git a/lib/libc/stdio/fgetwln.c b/lib/libc/stdio/fgetwln.c index 8439496..34a80a0 100644 --- a/lib/libc/stdio/fgetwln.c +++ b/lib/libc/stdio/fgetwln.c @@ -56,13 +56,15 @@ fgetwln_l(FILE * __restrict fp, size_t *lenp, locale_t locale) while ((wc = __fgetwc(fp, locale)) != WEOF) { #define GROW 512 if (len * sizeof(wchar_t) >= fp->_lb._size && - __slbexpand(fp, (len + GROW) * sizeof(wchar_t))) + __slbexpand(fp, (len + GROW) * sizeof(wchar_t))) { + fp->_flags |= __SERR; goto error; + } *((wchar_t *)fp->_lb._base + len++) = wc; if (wc == L'\n') break; } - if (len == 0) + if (len == 0 || (wc == WEOF && !__sfeof(fp))) goto error; FUNLOCKFILE(fp); @@ -74,6 +76,7 @@ error: *lenp = 0; return (NULL); } + wchar_t * fgetwln(FILE * __restrict fp, size_t *lenp) { diff --git a/lib/libc/stdio/fputwc.c b/lib/libc/stdio/fputwc.c index 7b05d4a..7f0c910 100644 --- a/lib/libc/stdio/fputwc.c +++ b/lib/libc/stdio/fputwc.c @@ -53,19 +53,9 @@ __fputwc(wchar_t wc, FILE *fp, locale_t locale) size_t i, len; struct xlocale_ctype *l = XLOCALE_CTYPE(locale); - if (MB_CUR_MAX == 1 && wc > 0 && wc <= UCHAR_MAX) { - /* - * Assume single-byte locale with no special encoding. - * A more careful test would be to check - * _CurrentRuneLocale->encoding. - */ - *buf = (unsigned char)wc; - len = 1; - } else { - if ((len = l->__wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) { - fp->_flags |= __SERR; - return (WEOF); - } + if ((len = l->__wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) { + fp->_flags |= __SERR; + return (WEOF); } for (i = 0; i < len; i++) -- cgit v1.1 From c058f89f159ec8b3fa8ba18b416d961ef92ca783 Mon Sep 17 00:00:00 2001 From: ngie Date: Mon, 29 Aug 2016 05:46:35 +0000 Subject: MFstable/11 r304945: MFC r304034: Initialize `ai` to NULL and test for `ai` with type-appropriate values Depending on the address family and ai_flags containing AI_V4MAPPED, it might not do a proper DNS lookup on the provided DNS address Convert some `ai` boolean true/false checks to NULL/non-NULL while here. PR: 211790 --- lib/libc/net/getaddrinfo.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'lib/libc') diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c index 54ac329..d987a16 100644 --- a/lib/libc/net/getaddrinfo.c +++ b/lib/libc/net/getaddrinfo.c @@ -2251,6 +2251,8 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap) struct res_target q, q2; res_state res; + ai = NULL; + hostname = va_arg(ap, char *); pai = va_arg(ap, const struct addrinfo *); @@ -2329,16 +2331,16 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap) /* prefer IPv6 */ if (q.next) { ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai, res); - if (ai) { + if (ai != NULL) { cur->ai_next = ai; while (cur && cur->ai_next) cur = cur->ai_next; } } - if (!ai || pai->ai_family != AF_UNSPEC || + if (ai == NULL || pai->ai_family != AF_UNSPEC || (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) != AI_V4MAPPED) { ai = getanswer(buf, q.n, q.name, q.qtype, pai, res); - if (ai) + if (ai != NULL) cur->ai_next = ai; } free(buf); -- cgit v1.1 From de43eec3e10416a7e9f3a7565f70e1ba2d265384 Mon Sep 17 00:00:00 2001 From: ache Date: Tue, 30 Aug 2016 00:57:57 +0000 Subject: MFC r304911 The formal behavior of qsort is unstable with regard to objects that are equal. Unfortunately, RFC 3484 requires that otherwise equal objects remain in the order supplied by the DNS server. The present code attempts to deal with this by returning -1 for objects that are equal (i.e., returns that the first parameter is less then the second parameter). Unfortunately, the qsort API does not state that the first parameter passed in is in any particular position in the list. PR: 212122 Submitted by: Herbie.Robinson@stratus.com --- lib/libc/net/getaddrinfo.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'lib/libc') diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c index d987a16..c5bfc5e 100644 --- a/lib/libc/net/getaddrinfo.c +++ b/lib/libc/net/getaddrinfo.c @@ -207,6 +207,7 @@ struct ai_order { struct policyqueue *aio_dstpolicy; struct addrinfo *aio_ai; int aio_matchlen; + int aio_initial_sequence; }; static const ns_src default_dns_files[] = { @@ -690,6 +691,7 @@ reorder(struct addrinfo *sentinel) aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr, &policyhead); set_source(&aio[i], &policyhead); + aio[i].aio_initial_sequence = i; } /* perform sorting. */ @@ -1048,6 +1050,23 @@ comp_dst(const void *arg1, const void *arg2) } /* Rule 10: Otherwise, leave the order unchanged. */ + + /* + * Note that qsort is unstable; so, we can't return zero and + * expect the order to be unchanged. + * That also means we can't depend on the current position of + * dst2 being after dst1. We must enforce the initial order + * with an explicit compare on the original position. + * The qsort specification requires that "When the same objects + * (consisting of width bytes, irrespective of their current + * positions in the array) are passed more than once to the + * comparison function, the results shall be consistent with one + * another." + * In other words, If A < B, then we must also return B > A. + */ + if (dst2->aio_initial_sequence < dst1->aio_initial_sequence) + return(1); + return(-1); } -- cgit v1.1