Index: include/stdio.h =================================================================== --- include/stdio.h +++ include/stdio.h @@ -51,6 +51,11 @@ #define _SIZE_T_DECLARED #endif +#ifndef _RSIZE_T_DEFINED +#define _RSIZE_T_DEFINED +typedef size_t rsize_t; +#endif + #if __POSIX_VISIBLE >= 200809 #ifndef _OFF_T_DECLARED #define _OFF_T_DECLARED @@ -265,6 +270,9 @@ int getc(FILE *); int getchar(void); char *gets(char *); +#if defined(__EXT1_VISIBLE) && __EXT1_VISIBLE == 1 +char *gets_s(char *, rsize_t); +#endif void perror(const char *); int printf(const char * __restrict, ...); int putc(int, FILE *); Index: lib/libc/stdio/Makefile.inc =================================================================== --- lib/libc/stdio/Makefile.inc +++ lib/libc/stdio/Makefile.inc @@ -14,7 +14,7 @@ fputwc.c fputws.c fread.c freopen.c fscanf.c fseek.c fsetpos.c \ ftell.c funopen.c fvwrite.c fwalk.c fwide.c fwprintf.c fwscanf.c \ fwrite.c getc.c getchar.c getdelim.c getline.c \ - gets.c getw.c getwc.c getwchar.c makebuf.c mktemp.c \ + gets.c gets_s.c getw.c getwc.c getwchar.c makebuf.c mktemp.c \ open_memstream.c open_wmemstream.c \ perror.c printf.c printf-pos.c putc.c putchar.c \ puts.c putw.c putwc.c putwchar.c \ @@ -50,6 +50,7 @@ ferror.3 fileno.3 ferror.3 fileno_unlocked.3 MLINKS+=fflush.3 fpurge.3 MLINKS+=fgets.3 gets.3 +MLINKS+=fgets.3 gets_s.3 MLINKS+=flockfile.3 ftrylockfile.3 flockfile.3 funlockfile.3 MLINKS+=fopen.3 fdopen.3 fopen.3 freopen.3 fopen.3 fmemopen.3 MLINKS+=fputs.3 puts.3 Index: lib/libc/stdio/Symbol.map =================================================================== --- lib/libc/stdio/Symbol.map +++ lib/libc/stdio/Symbol.map @@ -165,6 +165,7 @@ FBSD_1.4 { fdclose; fopencookie; + gets_s; }; FBSDprivate_1.0 { Index: lib/libc/stdio/fgets.3 =================================================================== --- lib/libc/stdio/fgets.3 +++ lib/libc/stdio/fgets.3 @@ -46,6 +46,8 @@ .Ft char * .Fn fgets "char * restrict str" "int size" "FILE * restrict stream" .Ft char * +.Fn gets_s "char *str" "rsize_t size" +.Ft char * .Fn gets "char *str" .Sh DESCRIPTION The @@ -65,6 +67,17 @@ character is appended to end the string. .Pp The +.Fn gets_s +function +is equivalent to +.Fn fgets +with a +.Fa stream +of +.Dv stdin , +except that the newline character (if any) is not stored in the string. +.Pp +The .Fn gets function is equivalent to @@ -80,7 +93,8 @@ if any, is sufficiently short to fit in the string. .Sh RETURN VALUES Upon successful completion, -.Fn fgets +.Fn fgets , +.Fn gets_s and .Fn gets return @@ -94,7 +108,8 @@ .Dv NULL and the buffer contents are indeterminate. The -.Fn fgets +.Fn fgets , +.Fn gets_s and .Fn gets functions @@ -141,6 +156,13 @@ .Fn gets conform to .St -isoC-99 . +.Fn gets_s +conforms to +.St -isoC-2011 +K.3.7.4.1. +.Fn gets +has been removed from +.St -isoC-2011 . .Sh SECURITY CONSIDERATIONS The .Fn gets Index: lib/libc/stdio/gets_s.c =================================================================== --- lib/libc/stdio/gets_s.c +++ lib/libc/stdio/gets_s.c @@ -0,0 +1,102 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#include +#include "un-namespace.h" +#include "libc_private.h" +#include "local.h" + +static inline char * +_gets_s(char *buf, rsize_t n) +{ + int c; + char *s; + + ORIENT(stdin, -1); + for (s = buf, n--; (c = __sgetc(stdin)) != '\n' && n > 0 ; n--) { + if (c == EOF) { + if (s == buf) { + return (NULL); + } else + break; + } else + *s++ = c; + } + + /* + * If end of buffer reached, discard until \n or eof. + * Then throw an error. + */ + if (n == 0) { + /* discard */ + while ((c = __sgetc(stdin)) != '\n' && c != EOF); + /* throw the error after lock released prior to exit */ + __throw_constraint_handler_s("gets_s : end of buffer", E2BIG); + return (NULL); + } + + *s = 0; + return (buf); +} + +/* ISO/IEC 9899:2011 K.3.7.4.1 */ +char * +gets_s(char *buf, rsize_t n) +{ + char *ret; + + if (buf == NULL) { + __throw_constraint_handler_s("gets_s : str is NULL", EINVAL); + return(NULL); + } else if (n > RSIZE_MAX) { + __throw_constraint_handler_s("gets_s : n > RSIZE_MAX", + EINVAL); + return(NULL); + } else if (n == 0) { + __throw_constraint_handler_s("gets_s : n == 0", EINVAL); + return(NULL); + } + + FLOCKFILE_CANCELSAFE(stdin); + ret = _gets_s(buf, n); + FUNLOCKFILE_CANCELSAFE(); + return (ret); +} Index: lib/libc/tests/stdio/Makefile =================================================================== --- lib/libc/tests/stdio/Makefile +++ lib/libc/tests/stdio/Makefile @@ -7,6 +7,7 @@ ATF_TESTS_C+= fopen2_test ATF_TESTS_C+= freopen_test ATF_TESTS_C+= getdelim_test +ATF_TESTS_C+= gets_s_test ATF_TESTS_C+= mkostemp_test ATF_TESTS_C+= open_memstream2_test ATF_TESTS_C+= open_wmemstream_test Index: lib/libc/tests/stdio/gets_s_test.c =================================================================== --- lib/libc/tests/stdio/gets_s_test.c +++ lib/libc/tests/stdio/gets_s_test.c @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 2017 Cyril S. E. Schubert. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include + +static errno_t e; +static const char * restrict m; + +void +h(const char * restrict msg, void * restrict ptr __unused, errno_t error) +{ + e = error; + m = msg; +} + +/* null ptr */ +ATF_TC_WITHOUT_HEAD(null_ptr); +ATF_TC_BODY(null_ptr, tc) +{ + assert(gets_s(NULL, 1) != 0); +} + +/* normal */ +ATF_TC_WITHOUT_HEAD(normal); +ATF_TC_BODY(normal, tc) +{ + pid_t kidpid; + int fd[2]; + + close(STDIN_FILENO); + close(STDOUT_FILENO); + pipe(fd); + + assert((kidpid == fork()) >=0); + if (kidpid == 0) { + char b[10]; + + close(fd[1]); + stdin = fdopen(fd[0], "r"); + assert(gets_s(&b, sizeof(b)) == 0); + close(fd[0]); + exit (0); + } else { + int stat; + + close(fd[0]); + stdout = fdopen(fd[1], "w"); + puts("a sting"); + (void) wait(&stat); + exit (0); + } +} + +/* n > rmax */ +ATF_TC_WITHOUT_HEAD(n_gt_rmax); +ATF_TC_BODY(n_gt_rmax, tc) +{ + char b; + + assert(gets_s(&b, RSIZE_MAX + 1) != 0); +} + +/* n == 0 */ +ATF_TC_WITHOUT_HEAD(n_lt_zero); +ATF_TC_BODY(n_eq_zero, tc) +{ + char b; + + assert(memset_s(&b, 0) != 0); +} + +/* n > rmax, handler */ +ATF_TC_WITHOUT_HEAD(n_gt_rmax_handler); +ATF_TC_BODY(n_gt_rmax_handler, tc) +{ + char b; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(gets_s(&b, RSIZE_MAX + 1) != 0); + assert(e > 0); + assert(strcmp(m, "gets_s : n > RSIZE_MAX") == 0); +} + +/* n == 0, handler */ +ATF_TC_WITHOUT_HEAD(n_lt_zero_handler); +ATF_TC_BODY(n_eq_zero_handler, tc) +{ + char b; + + e = 0; + m = NULL; + set_constraint_handler_s(h); + assert(gets_s(&b, -1) != 0); + assert(e > 0); + assert(strcmp(m, "gets_s : n == 0") == 0); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, null_ptr) + ATF_TP_ADD_TC(tp, normal) + ATF_TP_ADD_TC(tp, n_gt_rmax) + ATF_TP_ADD_TC(tp, n_eq_zero) + ATF_TP_ADD_TC(tp, n_gt_rmax_handler) + ATF_TP_ADD_TC(tp, n_eq_zero_handler) + return (atf_no_error()); +}