maint: update copyright
[gnulib.git] / tests / test-strerror_r.c
1 /* Test of strerror_r() function.
2    Copyright (C) 2007-2014 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
16
17 #include <config.h>
18
19 #include <string.h>
20
21 #include "signature.h"
22 SIGNATURE_CHECK (strerror_r, int, (int, char *, size_t));
23
24 #include <errno.h>
25
26 #include "macros.h"
27
28 int
29 main (void)
30 {
31   char buf[100];
32   int ret;
33
34   /* Test results with valid errnum and enough room.  */
35
36   errno = 0;
37   buf[0] = '\0';
38   ASSERT (strerror_r (EACCES, buf, sizeof buf) == 0);
39   ASSERT (buf[0] != '\0');
40   ASSERT (errno == 0);
41   ASSERT (strlen (buf) < sizeof buf);
42
43   errno = 0;
44   buf[0] = '\0';
45   ASSERT (strerror_r (ETIMEDOUT, buf, sizeof buf) == 0);
46   ASSERT (buf[0] != '\0');
47   ASSERT (errno == 0);
48   ASSERT (strlen (buf) < sizeof buf);
49
50   errno = 0;
51   buf[0] = '\0';
52   ASSERT (strerror_r (EOVERFLOW, buf, sizeof buf) == 0);
53   ASSERT (buf[0] != '\0');
54   ASSERT (errno == 0);
55   ASSERT (strlen (buf) < sizeof buf);
56
57   /* POSIX requires strerror (0) to succeed.  Reject use of "Unknown
58      error", but allow "Success", "No error", or even Solaris' "Error
59      0" which are distinct patterns from true out-of-range strings.
60      http://austingroupbugs.net/view.php?id=382  */
61   errno = 0;
62   buf[0] = '\0';
63   ret = strerror_r (0, buf, sizeof buf);
64   ASSERT (ret == 0);
65   ASSERT (buf[0]);
66   ASSERT (errno == 0);
67   ASSERT (strstr (buf, "nknown") == NULL);
68   ASSERT (strstr (buf, "ndefined") == NULL);
69
70   /* Test results with out-of-range errnum and enough room.  POSIX
71      allows an empty string on success, and allows an unchanged buf on
72      error, but these are not useful, so we guarantee contents.  */
73   errno = 0;
74   buf[0] = '^';
75   ret = strerror_r (-3, buf, sizeof buf);
76   ASSERT (ret == 0 || ret == EINVAL);
77   ASSERT (buf[0] != '^');
78   ASSERT (*buf);
79   ASSERT (errno == 0);
80   ASSERT (strlen (buf) < sizeof buf);
81
82   /* Test results with a too small buffer.  POSIX requires an error;
83      only ERANGE for 0 and valid errors, and a choice of ERANGE or
84      EINVAL for out-of-range values.  On error, POSIX permits buf to
85      be empty, unchanged, or unterminated, but these are not useful,
86      so we guarantee NUL-terminated truncated contents for all but
87      size 0.  http://austingroupbugs.net/view.php?id=398.  Also ensure
88      that no out-of-bounds writes occur.  */
89   {
90     int errs[] = { EACCES, 0, -3, };
91     int j;
92
93     buf[sizeof buf - 1] = '\0';
94     for (j = 0; j < SIZEOF (errs); j++)
95       {
96         int err = errs[j];
97         char buf2[sizeof buf] = "";
98         size_t len;
99         size_t i;
100
101         strerror_r (err, buf2, sizeof buf2);
102         len = strlen (buf2);
103         ASSERT (len < sizeof buf);
104
105         for (i = 0; i <= len; i++)
106           {
107             memset (buf, '^', sizeof buf - 1);
108             errno = 0;
109             ret = strerror_r (err, buf, i);
110             ASSERT (errno == 0);
111             if (err < 0)
112               ASSERT (ret == ERANGE || ret == EINVAL);
113             else
114               ASSERT (ret == ERANGE);
115             if (i)
116               {
117                 ASSERT (strncmp (buf, buf2, i - 1) == 0);
118                 ASSERT (buf[i - 1] == '\0');
119               }
120             ASSERT (strspn (buf + i, "^") == sizeof buf - 1 - i);
121           }
122
123         strcpy (buf, "BADFACE");
124         errno = 0;
125         ret = strerror_r (err, buf, len + 1);
126         ASSERT (ret != ERANGE);
127         ASSERT (errno == 0);
128         ASSERT (strcmp (buf, buf2) == 0);
129       }
130   }
131
132 #if GNULIB_STRERROR
133   /* Test that strerror_r does not clobber strerror buffer.  On some
134      platforms, this test can only succeed if gnulib also replaces
135      strerror.  */
136   {
137     const char *msg1;
138     const char *msg2;
139     const char *msg3;
140     const char *msg4;
141     char *str1;
142     char *str2;
143     char *str3;
144     char *str4;
145
146     msg1 = strerror (ENOENT);
147     ASSERT (msg1);
148     str1 = strdup (msg1);
149     ASSERT (str1);
150
151     msg2 = strerror (ERANGE);
152     ASSERT (msg2);
153     str2 = strdup (msg2);
154     ASSERT (str2);
155
156     msg3 = strerror (-4);
157     ASSERT (msg3);
158     str3 = strdup (msg3);
159     ASSERT (str3);
160
161     msg4 = strerror (1729576);
162     ASSERT (msg4);
163     str4 = strdup (msg4);
164     ASSERT (str4);
165
166     strerror_r (EACCES, buf, sizeof buf);
167     strerror_r (-5, buf, sizeof buf);
168     ASSERT (msg1 == msg2 || msg1 == msg4 || STREQ (msg1, str1));
169     ASSERT (msg2 == msg4 || STREQ (msg2, str2));
170     ASSERT (msg3 == msg4 || STREQ (msg3, str3));
171     ASSERT (STREQ (msg4, str4));
172
173     free (str1);
174     free (str2);
175     free (str3);
176     free (str4);
177   }
178 #endif
179
180   return 0;
181 }