(root)/
glibc-2.38/
stdio-common/
tst-fmemopen3.c
       1  /* fmemopen tests for append and read mode.
       2     Copyright (C) 2015-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <assert.h>
      20  #include <stdio.h>
      21  #include <string.h>
      22  #include <sys/types.h>
      23  
      24  #include <support/xstdio.h>
      25  
      26  static void
      27  print_buffer (const char *s, size_t n)
      28  {
      29    size_t i;
      30    printf ("{");
      31    for (i=0; i<n; ++i)
      32      {
      33        printf ("0x%02X (%c)", s[i], s[i]);
      34        if (i != n)
      35  	printf (", ");
      36      }
      37  }
      38  
      39  /* This test check append mode initial position (a/a+) based on POSIX definition
      40     (BZ#6544 and BZ#13151).  */
      41  static int
      42  do_test_write_append (const char *mode)
      43  {
      44    char buf[32] = "testing buffer";
      45    char exp[32] = "testing bufferXX";
      46  
      47    FILE *fp = fmemopen (buf, sizeof (buf), mode);
      48  
      49    fflush (fp);
      50    fprintf (fp, "X");
      51    fseek (fp, 0, SEEK_SET);
      52    fprintf (fp, "X");
      53    fclose (fp);
      54  
      55    if (strcmp (buf, exp) != 0)
      56      {
      57        printf ("%s: check failed: %s != %s\n", __FUNCTION__, buf, exp);
      58        return 1;
      59      }
      60  
      61    return 0;
      62  }
      63  
      64  /* This test check append mode initial position (a/a+) based on POSIX definition
      65     (BZ#6544 and BZ#13151) for buffer without null byte end.  */
      66  static int
      67  do_test_write_append_without_null (const char *mode)
      68  {
      69    char buf[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
      70    char exp[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
      71  
      72    /* If '\0' is not found in buffer, POSIX states that SEEK_SET should be
      73       the size argument.  */
      74    FILE *fp = fmemopen (buf, sizeof (buf) - 2, "a");
      75  
      76    fflush (fp);
      77    fputc (0x70, fp);
      78    fseek (fp, 0, SEEK_SET);
      79    fputc (0x70, fp);
      80    fputc (0x70, fp);
      81    fclose (fp);
      82  
      83    /* POSIX also states that a write operation on the stream shall not advance
      84       the current buffer size beyond the size given in fmemopen, so the string
      85       should be same.  */
      86    if (memcmp (buf, exp, sizeof (buf)) != 0)
      87      {
      88        printf ("%s: check failed: ", __FUNCTION__);
      89        print_buffer (buf, sizeof (buf));
      90        printf ("!= ");
      91        print_buffer (exp, sizeof (exp));
      92        printf ("\n");
      93        return 1;
      94      }
      95  
      96    return 0;
      97  }
      98  
      99  /* This test check for initial position and seek value for fmemopen objects
     100     opened with append mode.  */
     101  static int
     102  do_test_read_append (void)
     103  {
     104    char buf[32] = "testing buffer";
     105    size_t buflen = strlen (buf);
     106    long fpos;
     107  
     108    /* POSIX defines for 'a+' the initial position is the first null byte.  */
     109    FILE *fp = fmemopen (buf, sizeof (buf), "a+");
     110  
     111    fpos = ftell (fp);
     112    if (fpos != buflen)
     113      {
     114        printf ("%s: ftell|SEEK_SET (fp) %li != strlen (%s) %zu\n",
     115  	      __FUNCTION__, fpos, buf, buflen);
     116        fclose (fp);
     117        return 1;
     118      }
     119  
     120    fseek (fp, 0, SEEK_END);
     121  
     122    if (fpos != buflen)
     123      {
     124        printf ("%s: ftell|SEEK_END (fp) %li != strlen (%s) %zu\n",
     125  	      __FUNCTION__, fpos, buf, buflen);
     126        fclose (fp);
     127        return 1;
     128      }
     129    fclose (fp);
     130  
     131    /* Check if attempting to read past the current size, defined as strlen (buf)
     132       yield an EOF.  */
     133    fp = fmemopen (buf, sizeof (buf), "a+");
     134    if (getc(fp) != EOF)
     135      {
     136        printf ("%s: getc(fp) != EOF\n", __FUNCTION__);
     137        fclose (fp);
     138        return -1;
     139      }
     140  
     141    fclose (fp);
     142  
     143    return 0;
     144  }
     145  
     146  /* This test check for fseek (SEEK_END) using negative offsets (BZ#14292).  The
     147     starting position of descriptor is different base on the opening mode.  */
     148  static int
     149  do_test_read_seek_neg (const char *mode, const char *expected)
     150  {
     151    char buf[] = "abcdefghijklmnopqrstuvxz0123456789";
     152    char tmp[10];
     153    size_t tmps = sizeof (tmps);
     154    long offset = -11;
     155  
     156    FILE *fp = fmemopen (buf, sizeof (buf), mode);
     157    fseek (fp, offset, SEEK_END);
     158    xfread (tmp, tmps, 1, fp);
     159  
     160    if (memcmp (tmp, expected, tmps) != 0)
     161      {
     162        printf ("%s: fmemopen(%s) - fseek (fp, %li, SEEK_END):\n",
     163  	      __FUNCTION__, mode, offset);
     164        printf ("  returned: ");
     165        print_buffer (tmp, tmps);
     166        printf ("\n");
     167        printf ("  expected: ");
     168        print_buffer (expected, tmps);
     169        printf ("\n");
     170        return 1;
     171      }
     172  
     173    fclose (fp);
     174  
     175    return 0;
     176  }
     177  
     178  static int
     179  do_test_read_seek_negative (void)
     180  {
     181    int ret = 0;
     182  
     183    /* 'r' and 'w' modes defines the initial position at the buffer start and
     184       seek with SEEK_END shall seek relative to its size give in fmemopen
     185       call.  The expected tmp result is 0 to 9 *without* the ending null  */
     186    ret += do_test_read_seek_neg ("r", "0123456789");
     187    /* 'a+' mode sets the initial position at the first null byte in buffer and
     188      SEEK_END shall seek relative to its size as well.  The expected result is
     189      z012345678, since SEEK_END plus a+ start at '\0', not size.  */
     190    ret += do_test_read_seek_neg ("a+", "z012345678");
     191  
     192    return ret;
     193  }
     194  
     195  static int
     196  do_test_write_append_2 (const char *str)
     197  {
     198    char buf[10];
     199    size_t strn = strlen (str);
     200    strcpy (buf, str);
     201  
     202    FILE *fp = fmemopen (buf, sizeof (buf), "a+");
     203    size_t r = ftell (fp);
     204    size_t e = strlen (buf);
     205    if (r != e)
     206      {
     207        printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e);
     208        return 1;
     209      }
     210  
     211    if (fseek (fp, 0, SEEK_SET) == -1)
     212      {
     213        printf ("%s: fseek returned -1\n", __FUNCTION__);
     214        return 1;
     215      }
     216  
     217    int gr;
     218    for (int i=0; i<strn; ++i)
     219      {
     220        if ((gr = getc (fp)) != str[i])
     221  	{
     222  	  printf ("%s: getc failed returned %d, expected %d\n", __FUNCTION__,
     223  		  gr, str[i]);
     224  	  return 1;
     225          }
     226      }
     227    if ((gr = getc (fp)) != EOF)
     228      {
     229        printf ("%s: getc failed returned %d, expected EOF\n", __FUNCTION__,
     230  	      gr);
     231        return 1;
     232      }
     233  
     234    if (fseek (fp, e+1, SEEK_SET) == -1)
     235      {
     236        printf ("%s: fseek returned -1\n", __FUNCTION__);
     237        return 1;
     238      }
     239  
     240    if ((r = ftell (fp)) != e+1)
     241      {
     242        printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e+1);
     243        return 1;
     244      }
     245  
     246    if ((gr = getc (fp)) != EOF)
     247      {
     248        printf ("%s: getc failed returned %i\n", __FUNCTION__, gr);
     249        return 1;
     250      }
     251  
     252    /* Check if internal position is not changed with a getc returning EOF.  */
     253    if ((r = ftell (fp)) != e+1)
     254      {
     255        printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e+1);
     256        return 1;
     257      }
     258  
     259    if (fseek (fp, 0, SEEK_CUR) == -1)
     260      {
     261        printf ("%s: fseek returned -1\n", __FUNCTION__);
     262        return 1;
     263      }
     264  
     265    /* This should be overwritten by fprintf + fflush.  */
     266    buf[e+2] = 'X';
     267  
     268    if ((r = fprintf (fp, "%d", 101)) != 3)
     269      {
     270        printf ("%s: fprintf returned %zu, expected %d\n", __FUNCTION__, r, 3);
     271        return 1;
     272      }
     273  
     274    fflush (fp);
     275  
     276    /* Check if internal position is changed by 3 (strlen of '101').  */
     277    if ((r = ftell (fp)) != e+3)
     278      {
     279        printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e+3);
     280        return 1;
     281      }
     282  
     283    char exp[20];
     284    sprintf (exp, "%s%d", str,  101);
     285    if (memcmp (buf, exp, strlen (exp)) != 0)
     286      {
     287        printf ("%s: check failed:", __FUNCTION__);
     288        printf ("\nexpected: ");
     289        print_buffer (buf, sizeof (buf));
     290        printf ("\nbuffer:   ");
     291        print_buffer (exp, sizeof (exp));
     292        printf ("\n");
     293        return 1;
     294      }
     295  
     296    fclose(fp);
     297  
     298    return 0;
     299  }
     300  
     301  static int
     302  do_test (void)
     303  {
     304    int ret = 0;
     305  
     306    ret += do_test_write_append ("a");
     307    ret += do_test_write_append_without_null ("a");
     308    ret += do_test_write_append ("a+");
     309    ret += do_test_write_append_without_null ("a+");
     310  
     311    ret += do_test_read_append ();
     312  
     313    ret += do_test_read_seek_negative ();
     314  
     315    /* First test plus addend will fit in the define buffer of size 10.  */
     316    ret += do_test_write_append_2 ("test");
     317    /* The second test will also fit, but not the final '\0'.  */
     318    ret += do_test_write_append_2 ("testing");
     319  
     320    return ret;
     321  }
     322  
     323  #define TEST_FUNCTION do_test ()
     324  #include "../test-skeleton.c"