xref: /freebsd/lib/libc/tests/stdio/fmemopen2_test.c (revision 6b9f7133aba44189d9625c352bc2c2a59baf18ef)
141a3b124SEnji Cooper /*-
241a3b124SEnji Cooper Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
341a3b124SEnji Cooper 
441a3b124SEnji Cooper Redistribution and use in source and binary forms, with or without
541a3b124SEnji Cooper modification, are permitted provided that the following conditions
641a3b124SEnji Cooper are met:
741a3b124SEnji Cooper 1. Redistributions of source code must retain the above copyright
841a3b124SEnji Cooper    notice, this list of conditions and the following disclaimer.
941a3b124SEnji Cooper 2. Redistributions in binary form must reproduce the above copyright
1041a3b124SEnji Cooper    notice, this list of conditions and the following disclaimer in the
1141a3b124SEnji Cooper    documentation and/or other materials provided with the distribution.
1241a3b124SEnji Cooper 
1341a3b124SEnji Cooper THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1441a3b124SEnji Cooper ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1541a3b124SEnji Cooper IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1641a3b124SEnji Cooper ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
1741a3b124SEnji Cooper FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1841a3b124SEnji Cooper DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1941a3b124SEnji Cooper OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2041a3b124SEnji Cooper HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2141a3b124SEnji Cooper LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2241a3b124SEnji Cooper OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2341a3b124SEnji Cooper SUCH DAMAGE.
2441a3b124SEnji Cooper */
2541a3b124SEnji Cooper 
2641a3b124SEnji Cooper /*
2741a3b124SEnji Cooper  * Test basic FILE * functions (fread, fwrite, fseek, fclose) against
2841a3b124SEnji Cooper  * a FILE * retrieved using fmemopen()
2941a3b124SEnji Cooper  */
3041a3b124SEnji Cooper 
3141a3b124SEnji Cooper #include <errno.h>
3241a3b124SEnji Cooper #include <stdio.h>
3341a3b124SEnji Cooper #include <string.h>
3441a3b124SEnji Cooper #include <strings.h>
351ee02192SEnji Cooper 
3641a3b124SEnji Cooper #include <atf-c.h>
3741a3b124SEnji Cooper 
3841a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_preexisting);
ATF_TC_BODY(test_preexisting,tc)3941a3b124SEnji Cooper ATF_TC_BODY(test_preexisting, tc)
4041a3b124SEnji Cooper {
411ee02192SEnji Cooper 	/* Use a pre-existing buffer. */
4241a3b124SEnji Cooper 	char buf[512];
4341a3b124SEnji Cooper 	char buf2[512];
4441a3b124SEnji Cooper 	char str[]  = "Test writing some stuff";
4541a3b124SEnji Cooper 	char str2[] = "AAAAAAAAA";
4641a3b124SEnji Cooper 	char str3[] = "AAAA writing some stuff";
4741a3b124SEnji Cooper 	FILE *fp;
4841a3b124SEnji Cooper 	size_t nofw, nofr;
4941a3b124SEnji Cooper 	int rc;
5041a3b124SEnji Cooper 
5141a3b124SEnji Cooper 	/* Open a FILE * using fmemopen. */
5241a3b124SEnji Cooper 	fp = fmemopen(buf, sizeof(buf), "w");
5341a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
5441a3b124SEnji Cooper 
5541a3b124SEnji Cooper 	/* Write to the buffer. */
5641a3b124SEnji Cooper 	nofw = fwrite(str, 1, sizeof(str), fp);
5741a3b124SEnji Cooper 	ATF_REQUIRE(nofw == sizeof(str));
5841a3b124SEnji Cooper 
5941a3b124SEnji Cooper 	/* Close the FILE *. */
6041a3b124SEnji Cooper 	rc = fclose(fp);
6141a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
6241a3b124SEnji Cooper 
6341a3b124SEnji Cooper 	/* Re-open the FILE * to read back the data. */
6441a3b124SEnji Cooper 	fp = fmemopen(buf, sizeof(buf), "r");
6541a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
6641a3b124SEnji Cooper 
6741a3b124SEnji Cooper 	/* Read from the buffer. */
6841a3b124SEnji Cooper 	bzero(buf2, sizeof(buf2));
6941a3b124SEnji Cooper 	nofr = fread(buf2, 1, sizeof(buf2), fp);
7041a3b124SEnji Cooper 	ATF_REQUIRE(nofr == sizeof(buf2));
7141a3b124SEnji Cooper 
7241a3b124SEnji Cooper 	/*
7341a3b124SEnji Cooper 	 * Since a write on a FILE * retrieved by fmemopen
7441a3b124SEnji Cooper 	 * will add a '\0' (if there's space), we can check
7541a3b124SEnji Cooper 	 * the strings for equality.
7641a3b124SEnji Cooper 	 */
7741a3b124SEnji Cooper 	ATF_REQUIRE(strcmp(str, buf2) == 0);
7841a3b124SEnji Cooper 
7941a3b124SEnji Cooper 	/* Close the FILE *. */
8041a3b124SEnji Cooper 	rc = fclose(fp);
8141a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
8241a3b124SEnji Cooper 
8341a3b124SEnji Cooper 	/* Now open a FILE * on the first 4 bytes of the string. */
8441a3b124SEnji Cooper 	fp = fmemopen(str, 4, "w");
8541a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
8641a3b124SEnji Cooper 
8741a3b124SEnji Cooper 	/*
8841a3b124SEnji Cooper 	 * Try to write more bytes than we shoud, we'll get a short count (4).
8941a3b124SEnji Cooper 	 */
9041a3b124SEnji Cooper 	nofw = fwrite(str2, 1, sizeof(str2), fp);
9141a3b124SEnji Cooper 	ATF_REQUIRE(nofw == 4);
9241a3b124SEnji Cooper 
9341a3b124SEnji Cooper 	/* Close the FILE *. */
9441a3b124SEnji Cooper 	rc = fclose(fp);
95b95523e8SXin LI 	ATF_REQUIRE(rc == 0);
9641a3b124SEnji Cooper 
9741a3b124SEnji Cooper 	/* Check that the string was not modified after the first 4 bytes. */
9841a3b124SEnji Cooper 	ATF_REQUIRE(strcmp(str, str3) == 0);
9941a3b124SEnji Cooper }
10041a3b124SEnji Cooper 
10141a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_autoalloc);
ATF_TC_BODY(test_autoalloc,tc)10241a3b124SEnji Cooper ATF_TC_BODY(test_autoalloc, tc)
10341a3b124SEnji Cooper {
1041ee02192SEnji Cooper 	/* Let fmemopen allocate the buffer. */
10541a3b124SEnji Cooper 	FILE *fp;
10641a3b124SEnji Cooper 	long pos;
10795631a07SBaptiste Daroussin 	size_t nofw, i;
10841a3b124SEnji Cooper 	int rc;
10941a3b124SEnji Cooper 
11041a3b124SEnji Cooper 	/* Open a FILE * using fmemopen. */
11141a3b124SEnji Cooper 	fp = fmemopen(NULL, 512, "w+");
11241a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
11341a3b124SEnji Cooper 
11441a3b124SEnji Cooper 	/* fill the buffer */
11541a3b124SEnji Cooper 	for (i = 0; i < 512; i++) {
11641a3b124SEnji Cooper 		nofw = fwrite("a", 1, 1, fp);
11741a3b124SEnji Cooper 		ATF_REQUIRE(nofw == 1);
11841a3b124SEnji Cooper 	}
11941a3b124SEnji Cooper 
12041a3b124SEnji Cooper 	/* Get the current position into the stream. */
12141a3b124SEnji Cooper 	pos = ftell(fp);
12241a3b124SEnji Cooper 	ATF_REQUIRE(pos == 512);
12341a3b124SEnji Cooper 
1241ee02192SEnji Cooper 	/* Try to write past the end, we should get a short object count (0) */
12541a3b124SEnji Cooper 	nofw = fwrite("a", 1, 1, fp);
12641a3b124SEnji Cooper 	ATF_REQUIRE(nofw == 0);
12741a3b124SEnji Cooper 
12841a3b124SEnji Cooper 	/* Close the FILE *. */
12941a3b124SEnji Cooper 	rc = fclose(fp);
13041a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
13141a3b124SEnji Cooper 
13241a3b124SEnji Cooper 	/* Open a FILE * using a wrong mode */
13341a3b124SEnji Cooper 	fp = fmemopen(NULL, 512, "r");
13441a3b124SEnji Cooper 	ATF_REQUIRE(fp == NULL);
1350953460cSEd Maste 	ATF_REQUIRE(errno == EINVAL);
13641a3b124SEnji Cooper 
13741a3b124SEnji Cooper 	fp = fmemopen(NULL, 512, "w");
13841a3b124SEnji Cooper 	ATF_REQUIRE(fp == NULL);
1390953460cSEd Maste 	ATF_REQUIRE(errno == EINVAL);
14041a3b124SEnji Cooper }
14141a3b124SEnji Cooper 
14241a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_data_length);
ATF_TC_BODY(test_data_length,tc)14341a3b124SEnji Cooper ATF_TC_BODY(test_data_length, tc)
14441a3b124SEnji Cooper {
14541a3b124SEnji Cooper 	/*
14641a3b124SEnji Cooper 	 * Here we test that a read operation doesn't go past the end of the
14741a3b124SEnji Cooper 	 * data actually written, and that a SEEK_END seeks from the end of the
14841a3b124SEnji Cooper 	 * data, not of the whole buffer.
14941a3b124SEnji Cooper 	 */
15041a3b124SEnji Cooper 	FILE *fp;
15141a3b124SEnji Cooper 	char buf[512] = {'\0'};
15241a3b124SEnji Cooper 	char str[]  = "Test data length. ";
15341a3b124SEnji Cooper 	char str2[] = "Do we have two sentences?";
15441a3b124SEnji Cooper 	char str3[sizeof(str) + sizeof(str2) -1];
15541a3b124SEnji Cooper 	long pos;
15641a3b124SEnji Cooper 	size_t nofw, nofr;
15741a3b124SEnji Cooper 	int rc;
15841a3b124SEnji Cooper 
15941a3b124SEnji Cooper 	/* Open a FILE * for updating our buffer. */
16041a3b124SEnji Cooper 	fp = fmemopen(buf, sizeof(buf), "w+");
16141a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
16241a3b124SEnji Cooper 
16341a3b124SEnji Cooper 	/* Write our string into the buffer. */
16441a3b124SEnji Cooper 	nofw = fwrite(str, 1, sizeof(str), fp);
16541a3b124SEnji Cooper 	ATF_REQUIRE(nofw == sizeof(str));
16641a3b124SEnji Cooper 
1671ee02192SEnji Cooper 	/* Now seek to the end and check that ftell gives us sizeof(str). */
16841a3b124SEnji Cooper 	rc = fseek(fp, 0, SEEK_END);
16941a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
17041a3b124SEnji Cooper 	pos = ftell(fp);
17141a3b124SEnji Cooper 	ATF_REQUIRE(pos == sizeof(str));
17241a3b124SEnji Cooper 
17341a3b124SEnji Cooper 	/* Close the FILE *. */
17441a3b124SEnji Cooper 	rc = fclose(fp);
17541a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
17641a3b124SEnji Cooper 
17741a3b124SEnji Cooper 	/* Reopen the buffer for appending. */
17841a3b124SEnji Cooper 	fp = fmemopen(buf, sizeof(buf), "a+");
17941a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
18041a3b124SEnji Cooper 
18141a3b124SEnji Cooper 	/* We should now be writing after the first string. */
18241a3b124SEnji Cooper 	nofw = fwrite(str2, 1, sizeof(str2), fp);
18341a3b124SEnji Cooper 	ATF_REQUIRE(nofw == sizeof(str2));
18441a3b124SEnji Cooper 
18541a3b124SEnji Cooper 	/* Rewind the FILE *. */
18641a3b124SEnji Cooper 	rc = fseek(fp, 0, SEEK_SET);
18741a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
18841a3b124SEnji Cooper 
18941a3b124SEnji Cooper 	/* Make sure we're at the beginning. */
19041a3b124SEnji Cooper 	pos = ftell(fp);
19141a3b124SEnji Cooper 	ATF_REQUIRE(pos == 0);
19241a3b124SEnji Cooper 
19341a3b124SEnji Cooper 	/* Read the whole buffer. */
19441a3b124SEnji Cooper 	nofr = fread(str3, 1, sizeof(buf), fp);
19541a3b124SEnji Cooper 	ATF_REQUIRE(nofr == sizeof(str3));
19641a3b124SEnji Cooper 
19741a3b124SEnji Cooper 	/* Make sure the two strings are there. */
19841a3b124SEnji Cooper 	ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0);
19941a3b124SEnji Cooper 	ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
20041a3b124SEnji Cooper 
20141a3b124SEnji Cooper 	/* Close the FILE *. */
20241a3b124SEnji Cooper 	rc = fclose(fp);
20341a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
20441a3b124SEnji Cooper }
20541a3b124SEnji Cooper 
20641a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_binary);
ATF_TC_BODY(test_binary,tc)20741a3b124SEnji Cooper ATF_TC_BODY(test_binary, tc)
20841a3b124SEnji Cooper {
20941a3b124SEnji Cooper 	/*
21041a3b124SEnji Cooper 	 * Make sure that NULL bytes are never appended when opening a buffer
21141a3b124SEnji Cooper 	 * in binary mode.
21241a3b124SEnji Cooper 	 */
21341a3b124SEnji Cooper 
21441a3b124SEnji Cooper 	FILE *fp;
21541a3b124SEnji Cooper 	char buf[20];
21641a3b124SEnji Cooper 	char str[] = "Test";
21741a3b124SEnji Cooper 	size_t nofw;
21841a3b124SEnji Cooper 	int rc, i;
21941a3b124SEnji Cooper 
22041a3b124SEnji Cooper 	/* Pre-fill the buffer. */
22141a3b124SEnji Cooper 	memset(buf, 'A', sizeof(buf));
22241a3b124SEnji Cooper 
22341a3b124SEnji Cooper 	/* Open a FILE * in binary mode. */
22441a3b124SEnji Cooper 	fp = fmemopen(buf, sizeof(buf), "w+b");
22541a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
22641a3b124SEnji Cooper 
22741a3b124SEnji Cooper 	/* Write some data into it. */
22841a3b124SEnji Cooper 	nofw = fwrite(str, 1, strlen(str), fp);
22941a3b124SEnji Cooper 	ATF_REQUIRE(nofw == strlen(str));
23041a3b124SEnji Cooper 
23141a3b124SEnji Cooper 	/* Make sure that the buffer doesn't contain any NULL bytes. */
23241a3b124SEnji Cooper 	for (i = 0; i < sizeof(buf); i++)
23341a3b124SEnji Cooper 		ATF_REQUIRE(buf[i] != '\0');
23441a3b124SEnji Cooper 
23541a3b124SEnji Cooper 	/* Close the FILE *. */
23641a3b124SEnji Cooper 	rc = fclose(fp);
23741a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
23841a3b124SEnji Cooper }
23941a3b124SEnji Cooper 
24041a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_append_binary_pos);
ATF_TC_BODY(test_append_binary_pos,tc)24141a3b124SEnji Cooper ATF_TC_BODY(test_append_binary_pos, tc)
24241a3b124SEnji Cooper {
24341a3b124SEnji Cooper 	/*
24441a3b124SEnji Cooper 	 * For compatibility with other implementations (glibc), we set the
24541a3b124SEnji Cooper 	 * position to 0 when opening an automatically allocated binary stream
24641a3b124SEnji Cooper 	 * for appending.
24741a3b124SEnji Cooper 	 */
24841a3b124SEnji Cooper 
24941a3b124SEnji Cooper 	FILE *fp;
25041a3b124SEnji Cooper 
25141a3b124SEnji Cooper 	fp = fmemopen(NULL, 16, "ab+");
252c1755e51SEnji Cooper 	ATF_REQUIRE(fp != NULL);
25341a3b124SEnji Cooper 	ATF_REQUIRE(ftell(fp) == 0L);
25441a3b124SEnji Cooper 	fclose(fp);
25541a3b124SEnji Cooper 
2561ee02192SEnji Cooper 	/* Make sure that a pre-allocated buffer behaves correctly. */
25741a3b124SEnji Cooper 	char buf[] = "Hello";
25841a3b124SEnji Cooper 	fp = fmemopen(buf, sizeof(buf), "ab+");
259c1755e51SEnji Cooper 	ATF_REQUIRE(fp != NULL);
26041a3b124SEnji Cooper 	ATF_REQUIRE(ftell(fp) == strlen(buf));
26141a3b124SEnji Cooper 	fclose(fp);
26241a3b124SEnji Cooper }
26341a3b124SEnji Cooper 
26441a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_size_0);
ATF_TC_BODY(test_size_0,tc)26541a3b124SEnji Cooper ATF_TC_BODY(test_size_0, tc)
26641a3b124SEnji Cooper {
2671ee02192SEnji Cooper 	/* POSIX mandates that we return EINVAL if size is 0. */
26841a3b124SEnji Cooper 
26941a3b124SEnji Cooper 	FILE *fp;
27041a3b124SEnji Cooper 
27141a3b124SEnji Cooper 	fp = fmemopen(NULL, 0, "r+");
27241a3b124SEnji Cooper 	ATF_REQUIRE(fp == NULL);
27341a3b124SEnji Cooper 	ATF_REQUIRE(errno == EINVAL);
27441a3b124SEnji Cooper }
27541a3b124SEnji Cooper 
2760953460cSEd Maste /*
2770953460cSEd Maste  * PR281953 - ensure we cannot write in read-only only mode, and cannot read in
2780953460cSEd Maste  * write-only mode.
2790953460cSEd Maste  */
2800953460cSEd Maste ATF_TC_WITHOUT_HEAD(test_rdonly_wronly);
ATF_TC_BODY(test_rdonly_wronly,tc)2810953460cSEd Maste ATF_TC_BODY(test_rdonly_wronly, tc)
2820953460cSEd Maste {
2830953460cSEd Maste 	FILE *fp;
2840953460cSEd Maste 	char buf[16];
2850953460cSEd Maste 	char buf_orig[16] = "input data";
2860953460cSEd Maste 	char buf_write[16] = "write";
2870953460cSEd Maste 	size_t sz;
2880953460cSEd Maste 
2890953460cSEd Maste 	memcpy(buf, buf_orig, sizeof(buf));
2900953460cSEd Maste 	fp = fmemopen(buf, sizeof(buf), "r");
2910953460cSEd Maste 	ATF_REQUIRE(fp != NULL);
2920953460cSEd Maste 	sz = fwrite(buf_write, 1, strlen(buf_write), fp);
2930953460cSEd Maste 	ATF_REQUIRE(sz == 0);
2940953460cSEd Maste 	ATF_REQUIRE(errno == EBADF);
2950953460cSEd Maste 	ATF_REQUIRE(memcmp(buf, buf_orig, sizeof(buf)) == 0);
2960953460cSEd Maste 	fclose(fp);
2970953460cSEd Maste 
2980953460cSEd Maste 	fp = fmemopen(buf_orig, sizeof(buf), "w");
299*6b9f7133SEd Maste 	ATF_REQUIRE(fp != NULL);
3000953460cSEd Maste 	sz = fread(buf, sizeof(buf), 1, fp);
3010953460cSEd Maste 	ATF_REQUIRE(sz == 0);
3020953460cSEd Maste 	ATF_REQUIRE(errno == EBADF);
3030953460cSEd Maste 	fclose(fp);
3040953460cSEd Maste }
3050953460cSEd Maste 
ATF_TP_ADD_TCS(tp)30641a3b124SEnji Cooper ATF_TP_ADD_TCS(tp)
30741a3b124SEnji Cooper {
30841a3b124SEnji Cooper 
30941a3b124SEnji Cooper 	ATF_TP_ADD_TC(tp, test_autoalloc);
31041a3b124SEnji Cooper 	ATF_TP_ADD_TC(tp, test_preexisting);
31141a3b124SEnji Cooper 	ATF_TP_ADD_TC(tp, test_data_length);
31241a3b124SEnji Cooper 	ATF_TP_ADD_TC(tp, test_binary);
31341a3b124SEnji Cooper 	ATF_TP_ADD_TC(tp, test_append_binary_pos);
31441a3b124SEnji Cooper 	ATF_TP_ADD_TC(tp, test_size_0);
3150953460cSEd Maste 	ATF_TP_ADD_TC(tp, test_rdonly_wronly);
31641a3b124SEnji Cooper 
31741a3b124SEnji Cooper 	return (atf_no_error());
31841a3b124SEnji Cooper }
319