• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
3  * Licensed under Mulan PSL v2.
4  * You can use this software according to the terms and conditions of the Mulan PSL v2.
5  * You may obtain a copy of Mulan PSL v2 at:
6  *          http://license.coscl.org.cn/MulanPSL2
7  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
8  * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
9  * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
10  * See the Mulan PSL v2 for more details.
11  * Description: strcpy_s  function
12  * Create: 2014-02-25
13  */
14 /*
15  * [Standardize-exceptions] Use unsafe function: Performance-sensitive
16  * [reason] Always used in the performance critical path,
17  *          and sufficient input validation is performed before calling
18  */
19 
20 #include "securecutil.h"
21 
22 #ifndef SECUREC_STRCPY_WITH_PERFORMANCE
23 #define SECUREC_STRCPY_WITH_PERFORMANCE 1
24 #endif
25 
26 #define SECUREC_STRCPY_PARAM_OK(strDest, destMax, strSrc) ((destMax) > 0 && \
27     (destMax) <= SECUREC_STRING_MAX_LEN && (strDest) != NULL && (strSrc) != NULL && (strDest) != (strSrc))
28 
29 #if (!SECUREC_IN_KERNEL) && SECUREC_STRCPY_WITH_PERFORMANCE
30 #ifndef SECUREC_STRCOPY_THRESHOLD_SIZE
31 #define SECUREC_STRCOPY_THRESHOLD_SIZE   32UL
32 #endif
33 /* The purpose of converting to void is to clean up the alarm */
34 #define SECUREC_SMALL_STR_COPY(strDest, strSrc, lenWithTerm) do { \
35     if (SECUREC_ADDR_ALIGNED_8(strDest) && SECUREC_ADDR_ALIGNED_8(strSrc)) { \
36         /* Use struct assignment */ \
37         switch (lenWithTerm) { \
38             case 1: \
39                 *(strDest) = *(strSrc); \
40                 break; \
41             case 2: \
42                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 2); \
43                 break; \
44             case 3: \
45                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 3); \
46                 break; \
47             case 4: \
48                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 4); \
49                 break; \
50             case 5: \
51                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 5); \
52                 break; \
53             case 6: \
54                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 6); \
55                 break; \
56             case 7: \
57                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 7); \
58                 break; \
59             case 8: \
60                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 8); \
61                 break; \
62             case 9: \
63                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 9); \
64                 break; \
65             case 10: \
66                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 10); \
67                 break; \
68             case 11: \
69                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 11); \
70                 break; \
71             case 12: \
72                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 12); \
73                 break; \
74             case 13: \
75                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 13); \
76                 break; \
77             case 14: \
78                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 14); \
79                 break; \
80             case 15: \
81                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 15); \
82                 break; \
83             case 16: \
84                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 16); \
85                 break; \
86             case 17: \
87                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 17); \
88                 break; \
89             case 18: \
90                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 18); \
91                 break; \
92             case 19: \
93                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 19); \
94                 break; \
95             case 20: \
96                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 20); \
97                 break; \
98             case 21: \
99                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 21); \
100                 break; \
101             case 22: \
102                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 22); \
103                 break; \
104             case 23: \
105                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 23); \
106                 break; \
107             case 24: \
108                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 24); \
109                 break; \
110             case 25: \
111                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 25); \
112                 break; \
113             case 26: \
114                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 26); \
115                 break; \
116             case 27: \
117                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 27); \
118                 break; \
119             case 28: \
120                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 28); \
121                 break; \
122             case 29: \
123                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 29); \
124                 break; \
125             case 30: \
126                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 30); \
127                 break; \
128             case 31: \
129                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 31); \
130                 break; \
131             case 32: \
132                 SECUREC_COPY_VALUE_BY_STRUCT((strDest), (strSrc), 32); \
133                 break; \
134             default: \
135                 /* Do nothing */ \
136                 break; \
137         } /* END switch */ \
138     } else { \
139         char *tmpStrDest_ = (char *)(strDest); \
140         const char *tmpStrSrc_ = (const char *)(strSrc); \
141         switch (lenWithTerm) { \
142             case 32: \
143                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
144                 /* fall-through */ /* FALLTHRU */ \
145             case 31: \
146                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
147                 /* fall-through */ /* FALLTHRU */ \
148             case 30: \
149                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
150                 /* fall-through */ /* FALLTHRU */ \
151             case 29: \
152                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
153                 /* fall-through */ /* FALLTHRU */ \
154             case 28: \
155                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
156                 /* fall-through */ /* FALLTHRU */ \
157             case 27: \
158                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
159                 /* fall-through */ /* FALLTHRU */ \
160             case 26: \
161                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
162                 /* fall-through */ /* FALLTHRU */ \
163             case 25: \
164                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
165                 /* fall-through */ /* FALLTHRU */ \
166             case 24: \
167                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
168                 /* fall-through */ /* FALLTHRU */ \
169             case 23: \
170                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
171                 /* fall-through */ /* FALLTHRU */ \
172             case 22: \
173                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
174                 /* fall-through */ /* FALLTHRU */ \
175             case 21: \
176                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
177                 /* fall-through */ /* FALLTHRU */ \
178             case 20: \
179                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
180                 /* fall-through */ /* FALLTHRU */ \
181             case 19: \
182                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
183                 /* fall-through */ /* FALLTHRU */ \
184             case 18: \
185                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
186                 /* fall-through */ /* FALLTHRU */ \
187             case 17: \
188                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
189                 /* fall-through */ /* FALLTHRU */ \
190             case 16: \
191                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
192                 /* fall-through */ /* FALLTHRU */ \
193             case 15: \
194                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
195                 /* fall-through */ /* FALLTHRU */ \
196             case 14: \
197                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
198                 /* fall-through */ /* FALLTHRU */ \
199             case 13: \
200                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
201                 /* fall-through */ /* FALLTHRU */ \
202             case 12: \
203                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
204                 /* fall-through */ /* FALLTHRU */ \
205             case 11: \
206                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
207                 /* fall-through */ /* FALLTHRU */ \
208             case 10: \
209                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
210                 /* fall-through */ /* FALLTHRU */ \
211             case 9: \
212                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
213                 /* fall-through */ /* FALLTHRU */ \
214             case 8: \
215                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
216                 /* fall-through */ /* FALLTHRU */ \
217             case 7: \
218                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
219                 /* fall-through */ /* FALLTHRU */ \
220             case 6: \
221                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
222                 /* fall-through */ /* FALLTHRU */ \
223             case 5: \
224                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
225                 /* fall-through */ /* FALLTHRU */ \
226             case 4: \
227                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
228                 /* fall-through */ /* FALLTHRU */ \
229             case 3: \
230                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
231                 /* fall-through */ /* FALLTHRU */ \
232             case 2: \
233                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
234                 /* fall-through */ /* FALLTHRU */ \
235             case 1: \
236                 *(tmpStrDest_++) = *(tmpStrSrc_++); \
237                 /* fall-through */ /* FALLTHRU */ \
238             default: \
239                 /* Do nothing */ \
240                 break; \
241         } \
242     } \
243 } SECUREC_WHILE_ZERO
244 #endif
245 
246 #if SECUREC_IN_KERNEL || (!SECUREC_STRCPY_WITH_PERFORMANCE)
247 #define SECUREC_STRCPY_OPT(dest, src, lenWithTerm) SECUREC_MEMCPY_WARP_OPT((dest), (src), (lenWithTerm))
248 #else
249 /*
250  * Performance optimization. lenWithTerm  include '\0'
251  */
252 #define SECUREC_STRCPY_OPT(dest, src, lenWithTerm) do { \
253     if ((lenWithTerm) > SECUREC_STRCOPY_THRESHOLD_SIZE) { \
254         SECUREC_MEMCPY_WARP_OPT((dest), (src), (lenWithTerm)); \
255     } else { \
256         SECUREC_SMALL_STR_COPY((dest), (src), (lenWithTerm)); \
257     } \
258 } SECUREC_WHILE_ZERO
259 #endif
260 
261 /*
262  * Check Src Range
263  */
CheckSrcRange(char * strDest,size_t destMax,const char * strSrc)264 SECUREC_INLINE errno_t CheckSrcRange(char *strDest, size_t destMax, const char *strSrc)
265 {
266     size_t tmpDestMax = destMax;
267     const char *tmpSrc = strSrc;
268     /* Use destMax as boundary checker and destMax must be greater than zero */
269     while (*tmpSrc != '\0' && tmpDestMax > 0) {
270         ++tmpSrc;
271         --tmpDestMax;
272     }
273     if (tmpDestMax == 0) {
274         strDest[0] = '\0';
275         SECUREC_ERROR_INVALID_RANGE("strcpy_s");
276         return ERANGE_AND_RESET;
277     }
278     return EOK;
279 }
280 
281 /*
282  * Handling errors
283  */
strcpy_error(char * strDest,size_t destMax,const char * strSrc)284 errno_t strcpy_error(char *strDest, size_t destMax, const char *strSrc)
285 {
286     if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) {
287         SECUREC_ERROR_INVALID_RANGE("strcpy_s");
288         return ERANGE;
289     }
290     if (strDest == NULL || strSrc == NULL) {
291         SECUREC_ERROR_INVALID_PARAMTER("strcpy_s");
292         if (strDest != NULL) {
293             strDest[0] = '\0';
294             return EINVAL_AND_RESET;
295         }
296         return EINVAL;
297     }
298     return CheckSrcRange(strDest, destMax, strSrc);
299 }
300 
301 /*
302  * <FUNCTION DESCRIPTION>
303  *    The strcpy_s function copies the string pointed to  strSrc
304  *          (including the terminating null character) into the array pointed to by strDest
305  *    The destination string must be large enough to hold the source string,
306  *    including the terminating null character. strcpy_s will return EOVERLAP_AND_RESET
307  *    if the source and destination strings overlap.
308  *
309  * <INPUT PARAMETERS>
310  *    strDest                          Location of destination string buffer
311  *    destMax                        Size of the destination string buffer.
312  *    strSrc                            Null-terminated source string buffer.
313  *
314  * <OUTPUT PARAMETERS>
315  *    strDest                         is updated.
316  *
317  * <RETURN VALUE>
318  *    EOK                               Success
319  *    EINVAL                          strDest is  NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
320  *    EINVAL_AND_RESET       strDest !=  NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
321  *    ERANGE                         destMax is 0 and destMax > SECUREC_STRING_MAX_LEN
322  *    ERANGE_AND_RESET      strDest have not enough space  and all other parameters are valid  and not overlap
323  *    EOVERLAP_AND_RESET   dest buffer and source buffer are overlapped and all  parameters are valid
324  *
325  *    If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
326  */
strcpy_s(char * strDest,size_t destMax,const char * strSrc)327 errno_t strcpy_s(char *strDest, size_t destMax, const char *strSrc)
328 {
329     if (SECUREC_STRCPY_PARAM_OK(strDest, destMax, strSrc)) {
330         size_t srcStrLen;
331         SECUREC_CALC_STR_LEN(strSrc, destMax, &srcStrLen);
332         ++srcStrLen; /* The length include '\0' */
333 
334         if (srcStrLen <= destMax) {
335             /* Use mem overlap check include '\0' */
336             if (SECUREC_MEMORY_NO_OVERLAP(strDest, strSrc, srcStrLen)) {
337                 /* Performance optimization srcStrLen include '\0' */
338                 SECUREC_STRCPY_OPT(strDest, strSrc, srcStrLen);
339                 return EOK;
340             } else {
341                 strDest[0] = '\0';
342                 SECUREC_ERROR_BUFFER_OVERLAP("strcpy_s");
343                 return EOVERLAP_AND_RESET;
344             }
345         }
346     }
347     return strcpy_error(strDest, destMax, strSrc);
348 }
349 
350 #if SECUREC_EXPORT_KERNEL_SYMBOL
351 EXPORT_SYMBOL(strcpy_s);
352 #endif
353 
354