Date: Tue, 18 Jul 2017 08:15:03 +0000 (UTC) From: Ngie Cooper <ngie@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r321112 - in stable/10: share/man/man9 sys/kern sys/sys Message-ID: <201707180815.v6I8F3cE027998@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: ngie Date: Tue Jul 18 08:15:02 2017 New Revision: 321112 URL: https://svnweb.freebsd.org/changeset/base/321112 Log: MFC r279992,r280149,r280193,r288223,r288484,r321109: r279992 (by ian): Add a new flag, SBUF_INCLUDENUL, and new get/set/clear functions for flags. The SBUF_INCLUDENUL flag causes the nulterm byte at the end of the string to be counted in the length of the data. If copying the data using the sbuf_data() and sbuf_len() functions, or if writing it automatically with a drain function, the net effect is that the nulterm byte is copied along with the rest of the data. r280149 (by ian): Update an sbuf assertion to allow for the new SBUF_INCLUDENUL flag. If INCLUDENUL is set and sbuf_finish() has been called, the length has been incremented to count the nulterm byte, and in that case current length is allowed to be equal to buffer size, otherwise it must be less than. Add a predicate macro to test for SBUF_INCLUDENUL, and use it in tests, to be consistant with the style in the rest of this file. r280193 (by ian): The minimum sbuf buffer size is 2 bytes (a byte plus a nulterm), assert that. Values smaller than two lead to strange asserts that have nothing to do with the actual problem (in the case of size=0), or to writing beyond the end of the allocated buffer in sbuf_finish() (in the case of size=1). r288223 (by cem): sbuf: Process more than one char at a time Revamp sbuf_put_byte() to sbuf_put_bytes() in the obvious fashion and fixup callers. Add a thin shim around sbuf_put_bytes() with the old ABI to avoid ugly changes to some callers. Obtained from: Dan Sledz r288484 (by phk): Fail the sbuf if vsnprintf(3) fails. r321109: Fix whitespace regression accidentally checked in via ^/head@r280149 Modified: stable/10/share/man/man9/sbuf.9 stable/10/sys/kern/subr_sbuf.c stable/10/sys/sys/sbuf.h Directory Properties: stable/10/ (props changed) Modified: stable/10/share/man/man9/sbuf.9 ============================================================================== --- stable/10/share/man/man9/sbuf.9 Tue Jul 18 07:41:38 2017 (r321111) +++ stable/10/share/man/man9/sbuf.9 Tue Jul 18 08:15:02 2017 (r321112) @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 11, 2013 +.Dd March 14, 2015 .Dt SBUF 9 .Os .Sh NAME @@ -34,6 +34,9 @@ .Nm sbuf_new_auto , .Nm sbuf_new_for_sysctl , .Nm sbuf_clear , +.Nm sbuf_get_flags , +.Nm sbuf_set_flags , +.Nm sbuf_clear_flags , .Nm sbuf_setpos , .Nm sbuf_bcat , .Nm sbuf_bcopyin , @@ -69,6 +72,12 @@ .Ft void .Fn sbuf_clear "struct sbuf *s" .Ft int +.Fn sbuf_get_flags "struct sbuf *s" +.Ft void +.Fn sbuf_set_flags "struct sbuf *s" "int flags" +.Ft void +.Fn sbuf_clear_flags "struct sbuf *s" "int flags" +.Ft int .Fn sbuf_setpos "struct sbuf *s" "int pos" .Ft int .Fn sbuf_bcat "struct sbuf *s" "const void *buf" "size_t len" @@ -171,6 +180,8 @@ Attempting to extend the sbuf beyond this size results .It Dv SBUF_AUTOEXTEND This indicates that the storage buffer may be extended as necessary, so long as resources allow, to hold additional data. +.It Dv SBUF_INCLUDENUL +This causes the final nulterm byte to be counted in the length of the data. .El .Pp Note that if @@ -221,6 +232,18 @@ The function invalidates the contents of the .Fa sbuf and resets its position to zero. +.Pp +The +.Fn sbuf_get_flags +function returns the current user flags. +The +.Fn sbuf_set_flags +and +.Fn sbuf_get_flags +functions set or clear one or more user flags, respectively. +The user flags are described under the +.Fn sbuf_new +function. .Pp The .Fn sbuf_setpos Modified: stable/10/sys/kern/subr_sbuf.c ============================================================================== --- stable/10/sys/kern/subr_sbuf.c Tue Jul 18 07:41:38 2017 (r321111) +++ stable/10/sys/kern/subr_sbuf.c Tue Jul 18 08:15:02 2017 (r321112) @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <sys/ctype.h> #include <sys/errno.h> #include <sys/kernel.h> +#include <sys/limits.h> #include <sys/malloc.h> #include <sys/systm.h> #include <sys/uio.h> @@ -42,6 +43,7 @@ __FBSDID("$FreeBSD$"); #else /* _KERNEL */ #include <ctype.h> #include <errno.h> +#include <limits.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -70,6 +72,7 @@ static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers") #define SBUF_FREESPACE(s) ((s)->s_size - ((s)->s_len + 1)) #define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND) #define SBUF_ISSECTION(s) ((s)->s_flags & SBUF_INSECTION) +#define SBUF_NULINCLUDED(s) ((s)->s_flags & SBUF_INCLUDENUL) /* * Set / clear flags @@ -77,6 +80,7 @@ static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers") #define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0) #define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0) +#define SBUF_MINSIZE 2 /* Min is 1 byte + nulterm. */ #define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */ #ifdef PAGE_SIZE @@ -100,9 +104,15 @@ _assert_sbuf_integrity(const char *fun, struct sbuf *s ("%s called with a NULL sbuf pointer", fun)); KASSERT(s->s_buf != NULL, ("%s called with uninitialized or corrupt sbuf", fun)); - KASSERT(s->s_len < s->s_size, - ("wrote past end of sbuf (%jd >= %jd)", - (intmax_t)s->s_len, (intmax_t)s->s_size)); + if (SBUF_ISFINISHED(s) && SBUF_NULINCLUDED(s)) { + KASSERT(s->s_len <= s->s_size, + ("wrote past end of sbuf (%jd >= %jd)", + (intmax_t)s->s_len, (intmax_t)s->s_size)); + } else { + KASSERT(s->s_len < s->s_size, + ("wrote past end of sbuf (%jd >= %jd)", + (intmax_t)s->s_len, (intmax_t)s->s_size)); + } } static void @@ -185,8 +195,9 @@ sbuf_newbuf(struct sbuf *s, char *buf, int length, int s->s_buf = buf; if ((s->s_flags & SBUF_AUTOEXTEND) == 0) { - KASSERT(s->s_size >= 0, - ("attempt to create a too small sbuf")); + KASSERT(s->s_size >= SBUF_MINSIZE, + ("attempt to create an sbuf smaller than %d bytes", + SBUF_MINSIZE)); } if (s->s_buf != NULL) @@ -262,6 +273,28 @@ sbuf_uionew(struct sbuf *s, struct uio *uio, int *erro } #endif +int +sbuf_get_flags(struct sbuf *s) +{ + + return (s->s_flags & SBUF_USRFLAGMSK); +} + +void +sbuf_clear_flags(struct sbuf *s, int flags) +{ + + s->s_flags &= ~(flags & SBUF_USRFLAGMSK); +} + +void +sbuf_set_flags(struct sbuf *s, int flags) +{ + + + s->s_flags |= (flags & SBUF_USRFLAGMSK); +} + /* * Clear an sbuf and reset its position. */ @@ -352,55 +385,63 @@ sbuf_drain(struct sbuf *s) } /* - * Append a byte to an sbuf. This is the core function for appending + * Append bytes to an sbuf. This is the core function for appending * to an sbuf and is the main place that deals with extending the * buffer and marking overflow. */ static void -sbuf_put_byte(struct sbuf *s, int c) +sbuf_put_bytes(struct sbuf *s, const char *buf, size_t len) { + size_t n; assert_sbuf_integrity(s); assert_sbuf_state(s, 0); if (s->s_error != 0) return; - if (SBUF_FREESPACE(s) <= 0) { - /* - * If there is a drain, use it, otherwise extend the - * buffer. - */ - if (s->s_drain_func != NULL) - (void)sbuf_drain(s); - else if (sbuf_extend(s, 1) < 0) - s->s_error = ENOMEM; - if (s->s_error != 0) - return; + while (len > 0) { + if (SBUF_FREESPACE(s) <= 0) { + /* + * If there is a drain, use it, otherwise extend the + * buffer. + */ + if (s->s_drain_func != NULL) + (void)sbuf_drain(s); + else if (sbuf_extend(s, len > INT_MAX ? INT_MAX : len) + < 0) + s->s_error = ENOMEM; + if (s->s_error != 0) + return; + } + n = SBUF_FREESPACE(s); + if (len < n) + n = len; + memcpy(&s->s_buf[s->s_len], buf, n); + s->s_len += n; + if (SBUF_ISSECTION(s)) + s->s_sect_len += n; + len -= n; + buf += n; } - s->s_buf[s->s_len++] = c; - if (SBUF_ISSECTION(s)) - s->s_sect_len++; } +static void +sbuf_put_byte(struct sbuf *s, char c) +{ + + sbuf_put_bytes(s, &c, 1); +} + /* * Append a byte string to an sbuf. */ int sbuf_bcat(struct sbuf *s, const void *buf, size_t len) { - const char *str = buf; - const char *end = str + len; - assert_sbuf_integrity(s); - assert_sbuf_state(s, 0); - + sbuf_put_bytes(s, buf, len); if (s->s_error != 0) return (-1); - for (; str < end; str++) { - sbuf_put_byte(s, *str); - if (s->s_error != 0) - return (-1); - } return (0); } @@ -454,18 +495,12 @@ sbuf_bcpy(struct sbuf *s, const void *buf, size_t len) int sbuf_cat(struct sbuf *s, const char *str) { + size_t n; - assert_sbuf_integrity(s); - assert_sbuf_state(s, 0); - + n = strlen(str); + sbuf_put_bytes(s, str, n); if (s->s_error != 0) return (-1); - - while (*str != '\0') { - sbuf_put_byte(s, *str++); - if (s->s_error != 0) - return (-1); - } return (0); } @@ -588,6 +623,10 @@ sbuf_vprintf(struct sbuf *s, const char *fmt, va_list va_copy(ap_copy, ap); len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1, fmt, ap_copy); + if (len < 0) { + s->s_error = errno; + return (-1); + } va_end(ap_copy); if (SBUF_FREESPACE(s) >= len) @@ -697,11 +736,13 @@ sbuf_finish(struct sbuf *s) assert_sbuf_integrity(s); assert_sbuf_state(s, 0); + s->s_buf[s->s_len] = '\0'; + if (SBUF_NULINCLUDED(s)) + s->s_len++; if (s->s_drain_func != NULL) { while (s->s_len > 0 && s->s_error == 0) s->s_error = sbuf_drain(s); } - s->s_buf[s->s_len] = '\0'; SBUF_SETFLAG(s, SBUF_FINISHED); #ifdef _KERNEL return (s->s_error); @@ -743,6 +784,10 @@ sbuf_len(struct sbuf *s) if (s->s_error != 0) return (-1); + + /* If finished, nulterm is already in len, else add one. */ + if (SBUF_NULINCLUDED(s) && !SBUF_ISFINISHED(s)) + return (s->s_len + 1); return (s->s_len); } Modified: stable/10/sys/sys/sbuf.h ============================================================================== --- stable/10/sys/sys/sbuf.h Tue Jul 18 07:41:38 2017 (r321111) +++ stable/10/sys/sys/sbuf.h Tue Jul 18 08:15:02 2017 (r321112) @@ -48,6 +48,7 @@ struct sbuf { ssize_t s_len; /* current length of string */ #define SBUF_FIXEDLEN 0x00000000 /* fixed length buffer (default) */ #define SBUF_AUTOEXTEND 0x00000001 /* automatically extend buffer */ +#define SBUF_INCLUDENUL 0x00000002 /* nulterm byte is counted in len */ #define SBUF_USRFLAGMSK 0x0000ffff /* mask of flags the user may specify */ #define SBUF_DYNAMIC 0x00010000 /* s_buf must be freed */ #define SBUF_FINISHED 0x00020000 /* set by sbuf_finish() */ @@ -72,6 +73,9 @@ __BEGIN_DECLS struct sbuf *sbuf_new(struct sbuf *, char *, int, int); #define sbuf_new_auto() \ sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND) +int sbuf_get_flags(struct sbuf *); +void sbuf_clear_flags(struct sbuf *, int); +void sbuf_set_flags(struct sbuf *, int); void sbuf_clear(struct sbuf *); int sbuf_setpos(struct sbuf *, ssize_t); int sbuf_bcat(struct sbuf *, const void *, size_t);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201707180815.v6I8F3cE027998>