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