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