Add new gets_s(3) stdio function.
This implements the gets_s(3) function as documented at http://en.cppreference.com/w/c/io/gets. It facilitates the optional removal of gets(3). Reviewed by: ed MFC after: 2 weeks Relnotes: yes Differential Revision: https://reviews.freebsd.org/D12785
This commit is contained in:
parent
362e958eec
commit
a77546fbb3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=331936
@ -14,7 +14,7 @@ SRCS+= _flock_stub.c asprintf.c clrerr.c dprintf.c \
|
||||
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 @@ MLINKS+=ferror.3 ferror_unlocked.3 \
|
||||
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
|
||||
|
@ -165,6 +165,7 @@ FBSD_1.3 {
|
||||
FBSD_1.4 {
|
||||
fdclose;
|
||||
fopencookie;
|
||||
gets_s;
|
||||
};
|
||||
|
||||
FBSDprivate_1.0 {
|
||||
|
@ -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 @@ If any characters are read and there is no error, a
|
||||
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 @@ It is the caller's responsibility to ensure that the input line,
|
||||
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 @@ they return
|
||||
.Dv NULL
|
||||
and the buffer contents are indeterminate.
|
||||
The
|
||||
.Fn fgets
|
||||
.Fn fgets ,
|
||||
.Fn gets_s ,
|
||||
and
|
||||
.Fn gets
|
||||
functions
|
||||
@ -141,6 +156,13 @@ and
|
||||
.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
|
||||
|
102
lib/libc/stdio/gets_s.c
Normal file
102
lib/libc/stdio/gets_s.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2017, 2018
|
||||
* Cyril S. E. Schubert. 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 <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "namespace.h"
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#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);
|
||||
}
|
@ -7,6 +7,7 @@ ATF_TESTS_C+= fmemopen2_test
|
||||
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
|
||||
|
145
lib/libc/tests/stdio/gets_s_test.c
Normal file
145
lib/libc/tests/stdio/gets_s_test.c
Normal file
@ -0,0 +1,145 @@
|
||||
/*-
|
||||
* 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 <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <atf-c.h>
|
||||
|
||||
static errno_t error_code;
|
||||
static const char * message;
|
||||
|
||||
void
|
||||
h(const char * msg, void * ptr __unused, errno_t error)
|
||||
{
|
||||
error_code = error;
|
||||
message = msg;
|
||||
}
|
||||
|
||||
/* null ptr */
|
||||
ATF_TC_WITHOUT_HEAD(null_ptr);
|
||||
ATF_TC_BODY(null_ptr, tc)
|
||||
{
|
||||
ATF_CHECK_MSG(gets_s(NULL, 1) == NULL,
|
||||
"gets_s() failed to handle NULL pointer");
|
||||
}
|
||||
|
||||
/* normal */
|
||||
ATF_TC_WITHOUT_HEAD(normal);
|
||||
ATF_TC_BODY(normal, tc)
|
||||
{
|
||||
pid_t kidpid;
|
||||
int fd[2];
|
||||
int nfd;
|
||||
|
||||
// close(STDIN_FILENO);
|
||||
// close(STDOUT_FILENO);
|
||||
pipe(fd);
|
||||
|
||||
if ((kidpid = fork()) == 0) {
|
||||
char b[10];
|
||||
|
||||
close(fd[1]);
|
||||
nfd = dup2(fd[0], 0);
|
||||
close(fd[0]);
|
||||
stdin = fdopen(nfd, "r");
|
||||
ATF_CHECK_MSG(gets_s(b, sizeof(b)) == 0, "gets_s() normal failed");
|
||||
fclose(stdin);
|
||||
} else {
|
||||
int stat;
|
||||
|
||||
close(fd[0]);
|
||||
stdout = fdopen(fd[1], "w");
|
||||
puts("a sting");
|
||||
fclose(stdout);
|
||||
(void) waitpid(kidpid, &stat, WEXITED);
|
||||
}
|
||||
}
|
||||
|
||||
/* n > rmax */
|
||||
ATF_TC_WITHOUT_HEAD(n_gt_rmax);
|
||||
ATF_TC_BODY(n_gt_rmax, tc)
|
||||
{
|
||||
char b;
|
||||
|
||||
ATF_CHECK_MSG(gets_s(&b, RSIZE_MAX + 1) == NULL,
|
||||
"gets_s() n > RSIZE_MAX");
|
||||
}
|
||||
|
||||
/* n == 0 */
|
||||
ATF_TC_WITHOUT_HEAD(n_eq_zero);
|
||||
ATF_TC_BODY(n_eq_zero, tc)
|
||||
{
|
||||
char b;
|
||||
|
||||
ATF_CHECK_MSG(gets_s(&b, 0) == NULL, "gets_s() n is zero");
|
||||
}
|
||||
|
||||
/* n > rmax, handler */
|
||||
ATF_TC_WITHOUT_HEAD(n_gt_rmax_handler);
|
||||
ATF_TC_BODY(n_gt_rmax_handler, tc)
|
||||
{
|
||||
char b;
|
||||
|
||||
error_code = 0;
|
||||
message = NULL;
|
||||
set_constraint_handler_s(h);
|
||||
ATF_CHECK_MSG(gets_s(&b, RSIZE_MAX + 1) == NULL, "gets_s() n > RSIZE_MAX");
|
||||
ATF_CHECK_MSG(error_code > 0, "gets_s() error code is %d", error_code);
|
||||
ATF_CHECK_MSG(strcmp(message, "gets_s : n > RSIZE_MAX") == 0, "gets_s(): incorrect error message");
|
||||
}
|
||||
|
||||
/* n == 0, handler */
|
||||
ATF_TC_WITHOUT_HEAD(n_eq_zero_handler);
|
||||
ATF_TC_BODY(n_eq_zero_handler, tc)
|
||||
{
|
||||
char b;
|
||||
|
||||
error_code = 0;
|
||||
message = NULL;
|
||||
set_constraint_handler_s(h);
|
||||
ATF_CHECK(gets_s(&b, 0) == NULL);
|
||||
ATF_CHECK_MSG(error_code > 0, "gets_s() error code is %d", error_code);
|
||||
ATF_CHECK_MSG(strcmp(message, "gets_s : n == 0") == 0, "gets_s(): incorrect error message");
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
Loading…
Reference in New Issue
Block a user