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