vppinfra: c11 safe string functions
[vpp.git] / src / vppinfra / string.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16   Copyright (c) 2006 Eliot Dresselhaus
17
18   Permission is hereby granted, free of charge, to any person obtaining
19   a copy of this software and associated documentation files (the
20   "Software"), to deal in the Software without restriction, including
21   without limitation the rights to use, copy, modify, merge, publish,
22   distribute, sublicense, and/or sell copies of the Software, and to
23   permit persons to whom the Software is furnished to do so, subject to
24   the following conditions:
25
26   The above copyright notice and this permission notice shall be
27   included in all copies or substantial portions of the Software.
28
29   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37
38 #include <vppinfra/string.h>
39 #include <vppinfra/error.h>
40
41 /**
42  * @file
43  * @brief String Handling routines, including a performant
44  * implementation of many c-11 "safe" string functions.
45  */
46
47 /* Exchanges source and destination. */
48 void
49 clib_memswap (void *_a, void *_b, uword bytes)
50 {
51   uword pa = pointer_to_uword (_a);
52   uword pb = pointer_to_uword (_b);
53
54 #define _(TYPE)                                 \
55   if (0 == ((pa | pb) & (sizeof (TYPE) - 1)))   \
56     {                                           \
57       TYPE * a = uword_to_pointer (pa, TYPE *); \
58       TYPE * b = uword_to_pointer (pb, TYPE *); \
59                                                 \
60       while (bytes >= 2*sizeof (TYPE))          \
61         {                                       \
62           TYPE a0, a1, b0, b1;                  \
63           bytes -= 2*sizeof (TYPE);             \
64           a += 2;                               \
65           b += 2;                               \
66           a0 = a[-2]; a1 = a[-1];               \
67           b0 = b[-2]; b1 = b[-1];               \
68           a[-2] = b0; a[-1] = b1;               \
69           b[-2] = a0; b[-1] = a1;               \
70         }                                       \
71       pa = pointer_to_uword (a);                \
72       pb = pointer_to_uword (b);                \
73     }
74
75   if (BITS (uword) == BITS (u64))
76     _(u64);
77   _(u32);
78   _(u16);
79   _(u8);
80
81 #undef _
82
83   ASSERT (bytes < 2);
84   if (bytes)
85     {
86       u8 *a = uword_to_pointer (pa, u8 *);
87       u8 *b = uword_to_pointer (pb, u8 *);
88       u8 a0 = a[0], b0 = b[0];
89       a[0] = b0;
90       b[0] = a0;
91     }
92 }
93
94 void
95 clib_c11_violation (const char *s)
96 {
97   _clib_error (CLIB_ERROR_WARNING, (char *) __FUNCTION__, 0, (char *) s);
98 }
99
100 /**
101  * @brief copy src to dest, at most n bytes, up to dmax
102  *
103  *        ISO/IEC 9899:2017(C11), Porgramming languages -- C
104  *        Annex K; Bounds-checking interfaces
105  *
106  * @param *dest  pointer to memory to copy to
107  * @param dmax   maximum length of resulting dest
108  * @param *src   pointer to memory to copy from
109  * @param n      maximum number of characters to copy from src
110  *
111  * @constraints  No null pointers
112  *               n shall not be greater than dmax
113  *               no memory overlap between src and dest
114  *
115  * @return EOK        success
116  *         EINVAL     runtime constraint error
117  *
118  */
119 errno_t
120 memcpy_s (void *__restrict__ dest, rsize_t dmax,
121           const void *__restrict__ src, rsize_t n)
122 {
123   return memcpy_s_inline (dest, dmax, src, n);
124 }
125
126 /**
127  * @brief set n bytes starting at s to the specified c value
128  *
129  *        ISO/IEC 9899:2017(C11), Porgramming languages -- C
130  *        Annex K; Bounds-checking interfaces
131  *
132  * @param *s     pointer to memory to set the c value
133  * @param smax   maximum length of resulting s
134  * @param c      byte value
135  * @param n      maximum number of characters to set in s
136  *
137  * @constraints  No null pointers
138  *               n shall not be greater than smax
139  *
140  * @return EOK        success
141  *         EINVAL     runtime constraint error
142  *
143  */
144 errno_t
145 memset_s (void *s, rsize_t smax, int c, rsize_t n)
146 {
147   return memset_s_inline (s, smax, c, n);
148 }
149
150 /**
151  * @brief compare memory until they differ, and their difference is returned in
152  *        diff
153  *
154  *        ISO/IEC 9899:2017(C11), Porgramming languages -- C
155  *        Annex K; Bounds-checking interfaces
156  *
157  * @param *s1     pointer to memory to compare against
158  * @param s1max   maximum length of s1
159  * @param *s2     pointer to memory to compare with s1
160  * @param s2max   length of s2
161  * @param *diff   pointer to the diff which is an integer greater than, equal to,
162  *                or less than zero according to s1 is greater than, equal to,
163  *                or less than s2.
164  *
165  * @constraints   No null pointers
166  *                s1max and s2max shall not be zero
167  *                s2max shall not be greater than s1max
168  *
169  * @return EOK    success
170  *         diff   when the return code is EOK
171  *         >0     s1 greater s2
172  *          0     s1 == s2
173  *         <0     s1 < s2
174  *         EINVAL runtime constraint error
175  *
176  */
177 errno_t
178 memcmp_s (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
179           int *diff)
180 {
181   return memcmp_s_inline (s1, s1max, s2, s2max, diff);
182 }
183
184 /**
185  * @brief compare string s2 to string s1, and their difference is returned in
186  *        indicator
187  *
188  *        ISO/IEC 9899:2017(C11), Porgramming languages -- C
189  *        Annex K; Bounds-checking interfaces
190  *
191  * @param *s1     pointer to string to compare against
192  * @param s1max   maximum length of s1, excluding null
193  * @param *s2     pointer to string to compare with s1
194  * @param *indicator  pointer to the comparison result, which is an integer
195  *                    greater than, equal to, or less than zero according to
196  *                    s1 is greater than, equal to, or less than s2.
197  *
198  * @constraints   No null pointers
199  *                s1max shall not be zero
200  *                s1 shall be null terminated
201  *                n shall not be greater than the smaller of s1max and strlen
202  *                of s1
203  *
204  * @return EOK        success
205  *         indicator  when the return code is EOK
206  *         >0         s1 greater s2
207  *          0         s1 == s2
208  *         <0         s1 < s2
209  *         EINVAL     runtime constraint error
210  *
211  */
212 errno_t
213 strcmp_s (const char *s1, rsize_t s1max, const char *s2, int *indicator)
214 {
215   return strcmp_s_inline (s1, s1max, s2, indicator);
216 }
217
218 /**
219  * @brief compare string s2 to string s1, no more than n characters, and their
220  *        difference is returned in indicator
221  *
222  *        ISO/IEC 9899:2017(C11), Porgramming languages -- C
223  *        Annex K; Bounds-checking interfaces
224  *
225  * @param *s1     pointer to string to compare against
226  * @param s1max   maximum length of s1, excluding null
227  * @param *s2     pointer to string to compare with s1
228  * @param n       maximum number of characters to compare
229  * @param *indicator  pointer to the comparison result, which is an integer
230  *                    greater than, equal to, or less than zero according to
231  *                    s1 is greater than, equal to, or less than s2.
232  *
233  * @constraints   No null pointers
234  *                s1max shall not be zero
235  *                s1 shall be null terminated
236  *
237  * @return EOK        success
238  *         indicator  when the return code is EOK
239  *         >0         s1 greater s2
240  *          0         s1 == s2
241  *         <0         s1 < s2
242  *         EINVAL     runtime constraint error
243  *
244  */
245 errno_t
246 strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
247            int *indicator)
248 {
249   return strncmp_s_inline (s1, s1max, s2, n, indicator);
250 }
251
252 /**
253  * @brief copy src string to dest string
254  *
255  *        ISO/IEC 9899:2017(C11), Porgramming languages -- C
256  *        Annex K; Bounds-checking interfaces
257  *
258  * @param *dest  pointer to string to copy to
259  * @param dmax   maximum length of resulting dest string, including null
260  * @param *src   pointer to string to copy from
261  *
262  * @constraints  No null pointers
263  *               dmax shall not be zero
264  *               dmax shall be greater than string length of src
265  *               no memory overlap between src and dest
266  *
267  * @return EOK        success
268  *         EINVAL     runtime constraint error
269  *
270  */
271 errno_t
272 strcpy_s (char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src)
273 {
274   return strcpy_s_inline (dest, dmax, src);
275 }
276
277 /**
278  * @brief copy src string to dest string, no more than n characters
279  *
280  *        ISO/IEC 9899:2017(C11), Porgramming languages -- C
281  *        Annex K; Bounds-checking interfaces
282  *
283  * @param *dest  pointer to string to copy to
284  * @param dmax   maximum length of resulting dest string, including null
285  * @param *src   pointer to string to copy from
286  * @param n      maximum number of characters to copy from src, excluding null
287  *
288  * @constraints  No null pointers
289  *               dmax shall not be zero
290  *               no memory overlap between src and dest
291  *
292  * @return EOK        success
293  *         EINVAL     runtime constraint error
294  *         EOVERFLOW  truncated operation. dmax - 1 characters were copied.
295  *                    dest is null terminated.
296  *
297  */
298 errno_t
299 strncpy_s (char *__restrict__ dest, rsize_t dmax,
300            const char *__restrict__ src, rsize_t n)
301 {
302   return strncpy_s_inline (dest, dmax, src, n);
303 }
304
305 /**
306  * @brief append src string to dest string, including null
307  *
308  *        ISO/IEC 9899:2017(C11), Porgramming languages -- C
309  *        Annex K; Bounds-checking interfaces
310  *
311  * @param *dest  pointer to string to append to
312  * @param dmax   maximum length of resulting dest string, including null
313  * @param *src   pointer to string to append from
314  *
315  * @constraints  No null pointers
316  *               dmax shall not be zero
317  *               dest shall be null terminated
318  *               given m = dmax - strnlen (dest, dmax)
319  *                     n = strnlen (src, m)
320  *                        n shall not be >= m
321  *               no memory overlap between src and dest
322  *
323  * @return EOK        success
324  *         EINVAL     runtime constraint error
325  *
326  */
327 errno_t
328 strcat_s (char *__restrict__ dest, rsize_t dmax, const char *__restrict__ src)
329 {
330   return strcat_s_inline (dest, dmax, src);
331 }
332
333 /**
334  * @brief append src string to dest string, including null, no more than n
335  *        characters
336  *
337  *        ISO/IEC 9899:2017(C11), Porgramming languages -- C
338  *        Annex K; Bounds-checking interfaces
339  *
340  * @param *dest  pointer to string to append to
341  * @param dmax   maximum length of resulting dest string, including null
342  * @param *src   pointer to string to append from
343  * @param n      maximum characters to append (excluding null)
344  *
345  * @constraints  No null pointers
346  *               dmax shall not be zero
347  *               dest shall be null terminated
348  *               dmax - strnlen (dest, dmax) shall not be zero
349  *               no memory overlap between src and dest
350  *
351  * @return EOK        success
352  *         EINVAL     runtime constraint error
353  *         EOVERFLOW  truncated operation. dmax - 1 characters were appended.
354  *                    dest is null terminated.
355  *
356  */
357 errno_t
358 strncat_s (char *__restrict__ dest, rsize_t dmax,
359            const char *__restrict__ src, rsize_t n)
360 {
361   return strncat_s_inline (dest, dmax, src, n);
362 }
363
364 /**
365  * @brief tokenize string s1 with delimiter specified in s2. This is a stateful
366  *        API when it is iterately called, it returns the next token from s1
367  *        which is delimited by s2. s1max and ptr maintain the stateful
368  *        information for the same caller and must not be altered by the
369  *        caller during the iteration for the correct result
370  *
371  *        ISO/IEC 9899:2017(C11), Porgramming languages -- C
372  *        Annex K; Bounds-checking interfaces
373  *
374  * @param *s1         pointer to string to be searched for substring
375  * @param *s1max      restricted maximum length of s1
376  * @param *s2         pointer to substring to search (16 characters max,
377  *                    including null)
378  * @param **ptr       in/out pointer which maintains the stateful information
379  *
380  * @constraints  s2, s1max, and ptr shall not be null
381  *               if s1 is null, contents of ptr shall not be null
382  *               s1 and s2 shall be null terminated
383  *
384  * @return non-null  pointer to the first character of a token
385  *         s1max and ptr are modified to contain the state
386  *         null      runtime constraint error or token is not found
387  *
388  * @example
389  *   char *str2 = " ";
390  *   char str1[100];
391  *   uword len;
392  *   char *p2str = 0;
393  *   char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7;
394  *
395  *   strncpy (str1, "brevity is the soul of wit", sizeof (str1));
396  *   len = strlen (str1);
397  *   tok1 = strtok_s (str1, &len, str2, &p2str);
398  *   tok2 = strtok_s (0, &len, str2, &p2str);
399  *   tok3 = strtok_s (0, &len, str2, &p2str);
400  *   tok4 = strtok_s (0, &len, str2, &p2str);
401  *   tok5 = strtok_s (0, &len, str2, &p2str);
402  *   tok6 = strtok_s (0, &len, str2, &p2str);
403  *   tok7 = strtok_s (0, &len, str2, &p2str);
404  *
405  * After the above series of calls,
406  *   tok1 = "brevity", tok2 = "is", tok3 = "the", tok4 = "soul", tok5 = "of",
407  *   tok6 = "wit", tok7 = null
408  */
409 char *
410 strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
411           const char *__restrict__ s2, char **__restrict__ ptr)
412 {
413   return strtok_s_inline (s1, s1max, s2, ptr);
414 }
415
416 /**
417  * @brief compute the length in s, no more than maxsize
418  *
419  *        ISO/IEC 9899:2017(C11), Porgramming languages -- C
420  *        Annex K; Bounds-checking interfaces
421  *
422  * @param *s      pointer to string
423  * @param maxsize restricted maximum length
424  *
425  * @constraints   No null pointers
426  *                maxsize shall not be zero
427  *
428  * @return size_t the string length in s, excluding null character, and no
429  *                more than maxsize or 0 if there is a constraint error
430  *
431  */
432 size_t
433 strnlen_s (const char *s, size_t maxsize)
434 {
435   return strnlen_s_inline (s, maxsize);
436 }
437
438 /**
439  * @brief locate the first occurrence of the substring s2 in s1
440  *
441  *        ISO/IEC 9899:2017(C11), Porgramming languages -- C
442  *        Annex K; Bounds-checking interfaces
443  *
444  * @param *s1         pointer to string to be searched for substring
445  * @param s1max       restricted maximum length of s1
446  * @param *s2         pointer to substring to search
447  * @param s2max       restricted maximum length of s2
448  * @param **substring pointer to pointer substring to be returned
449  *
450  * @constraints  No null pointers
451  *               s1max and s2max shall not be zero
452  *               s1 and s2 shall be null terminated
453  *
454  * @return EOK    success
455  *         substring when the return code is EOK, it contains the pointer which
456  *         points to s1 that matches s2
457  *         EINVAL runtime constraint error
458  *         ESRCH  no match
459  *
460  * @example
461  *   char *sub = 0;
462  *   char *s1 = "success is not final, failure is not fatal.";
463  *
464  *   strstr_s (s1, strlen (s1), "failure", strlen ("failure"), &sub);
465  *
466  * After the above call,
467  *   sub = "failure is not fatal."
468  */
469 errno_t
470 strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
471           char **substring)
472 {
473   return strstr_s_inline (s1, s1max, s2, s2max, substring);
474 }
475
476 /*
477  * fd.io coding-style-patch-verification: ON
478  *
479  * Local Variables:
480  * eval: (c-set-style "gnu")
481  * End:
482  */