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 */
264SECUREC_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 */
284errno_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 */
327errno_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
351EXPORT_SYMBOL(strcpy_s);
352#endif
353
354