/** * Copyright 2020 Huawei Technologies Co., Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define SECUREC_INLINE_DO_MEMCPY 1 #include "securecutil.h" #ifndef SECUREC_MEMCOPY_WITH_PERFORMANCE #define SECUREC_MEMCOPY_WITH_PERFORMANCE 0 #endif #if SECUREC_WITH_PERFORMANCE_ADDONS || SECUREC_MEMCOPY_WITH_PERFORMANCE #ifndef SECUREC_MEMCOPY_THRESHOLD_SIZE #define SECUREC_MEMCOPY_THRESHOLD_SIZE 64UL #endif /* * Determine whether the address is 8-byte aligned, use static to increase performance * return 0 is aligned */ static int SecIsAddrAligned8(const void *addr, const void *zeroAddr) { return (int)(((size_t)((const char*)addr - (const char*)zeroAddr)) & 7); /* use 7 to check aligned 8 */ } #define SECUREC_SMALL_MEM_COPY do { \ if (SECUREC_ADDR_ALIGNED_8(dest) && SECUREC_ADDR_ALIGNED_8(src)) { \ /* use struct assignment */ \ switch (count) { \ case 1: \ *(SecStrBuf1 *)dest = *(const SecStrBuf1 *)src; \ break; \ case 2: \ *(SecStrBuf2 *)dest = *(const SecStrBuf2 *)src; \ break; \ case 3: \ *(SecStrBuf3 *)dest = *(const SecStrBuf3 *)src; \ break; \ case 4: \ *(SecStrBuf4 *)dest = *(const SecStrBuf4 *)src; \ break; \ case 5: \ *(SecStrBuf5 *)dest = *(const SecStrBuf5 *)src; \ break; \ case 6: \ *(SecStrBuf6 *)dest = *(const SecStrBuf6 *)src; \ break; \ case 7: \ *(SecStrBuf7 *)dest = *(const SecStrBuf7 *)src; \ break; \ case 8: \ *(SecStrBuf8 *)dest = *(const SecStrBuf8 *)src; \ break; \ case 9: \ *(SecStrBuf9 *)dest = *(const SecStrBuf9 *)src; \ break; \ case 10: \ *(SecStrBuf10 *)dest = *(const SecStrBuf10 *)src; \ break; \ case 11: \ *(SecStrBuf11 *)dest = *(const SecStrBuf11 *)src; \ break; \ case 12: \ *(SecStrBuf12 *)dest = *(const SecStrBuf12 *)src; \ break; \ case 13: \ *(SecStrBuf13 *)dest = *(const SecStrBuf13 *)src; \ break; \ case 14: \ *(SecStrBuf14 *)dest = *(const SecStrBuf14 *)src; \ break; \ case 15: \ *(SecStrBuf15 *)dest = *(const SecStrBuf15 *)src; \ break; \ case 16: \ *(SecStrBuf16 *)dest = *(const SecStrBuf16 *)src; \ break; \ case 17: \ *(SecStrBuf17 *)dest = *(const SecStrBuf17 *)src; \ break; \ case 18: \ *(SecStrBuf18 *)dest = *(const SecStrBuf18 *)src; \ break; \ case 19: \ *(SecStrBuf19 *)dest = *(const SecStrBuf19 *)src; \ break; \ case 20: \ *(SecStrBuf20 *)dest = *(const SecStrBuf20 *)src; \ break; \ case 21: \ *(SecStrBuf21 *)dest = *(const SecStrBuf21 *)src; \ break; \ case 22: \ *(SecStrBuf22 *)dest = *(const SecStrBuf22 *)src; \ break; \ case 23: \ *(SecStrBuf23 *)dest = *(const SecStrBuf23 *)src; \ break; \ case 24: \ *(SecStrBuf24 *)dest = *(const SecStrBuf24 *)src; \ break; \ case 25: \ *(SecStrBuf25 *)dest = *(const SecStrBuf25 *)src; \ break; \ case 26: \ *(SecStrBuf26 *)dest = *(const SecStrBuf26 *)src; \ break; \ case 27: \ *(SecStrBuf27 *)dest = *(const SecStrBuf27 *)src; \ break; \ case 28: \ *(SecStrBuf28 *)dest = *(const SecStrBuf28 *)src; \ break; \ case 29: \ *(SecStrBuf29 *)dest = *(const SecStrBuf29 *)src; \ break; \ case 30: \ *(SecStrBuf30 *)dest = *(const SecStrBuf30 *)src; \ break; \ case 31: \ *(SecStrBuf31 *)dest = *(const SecStrBuf31 *)src; \ break; \ case 32: \ *(SecStrBuf32 *)dest = *(const SecStrBuf32 *)src; \ break; \ case 33: \ *(SecStrBuf33 *)dest = *(const SecStrBuf33 *)src; \ break; \ case 34: \ *(SecStrBuf34 *)dest = *(const SecStrBuf34 *)src; \ break; \ case 35: \ *(SecStrBuf35 *)dest = *(const SecStrBuf35 *)src; \ break; \ case 36: \ *(SecStrBuf36 *)dest = *(const SecStrBuf36 *)src; \ break; \ case 37: \ *(SecStrBuf37 *)dest = *(const SecStrBuf37 *)src; \ break; \ case 38: \ *(SecStrBuf38 *)dest = *(const SecStrBuf38 *)src; \ break; \ case 39: \ *(SecStrBuf39 *)dest = *(const SecStrBuf39 *)src; \ break; \ case 40: \ *(SecStrBuf40 *)dest = *(const SecStrBuf40 *)src; \ break; \ case 41: \ *(SecStrBuf41 *)dest = *(const SecStrBuf41 *)src; \ break; \ case 42: \ *(SecStrBuf42 *)dest = *(const SecStrBuf42 *)src; \ break; \ case 43: \ *(SecStrBuf43 *)dest = *(const SecStrBuf43 *)src; \ break; \ case 44: \ *(SecStrBuf44 *)dest = *(const SecStrBuf44 *)src; \ break; \ case 45: \ *(SecStrBuf45 *)dest = *(const SecStrBuf45 *)src; \ break; \ case 46: \ *(SecStrBuf46 *)dest = *(const SecStrBuf46 *)src; \ break; \ case 47: \ *(SecStrBuf47 *)dest = *(const SecStrBuf47 *)src; \ break; \ case 48: \ *(SecStrBuf48 *)dest = *(const SecStrBuf48 *)src; \ break; \ case 49: \ *(SecStrBuf49 *)dest = *(const SecStrBuf49 *)src; \ break; \ case 50: \ *(SecStrBuf50 *)dest = *(const SecStrBuf50 *)src; \ break; \ case 51: \ *(SecStrBuf51 *)dest = *(const SecStrBuf51 *)src; \ break; \ case 52: \ *(SecStrBuf52 *)dest = *(const SecStrBuf52 *)src; \ break; \ case 53: \ *(SecStrBuf53 *)dest = *(const SecStrBuf53 *)src; \ break; \ case 54: \ *(SecStrBuf54 *)dest = *(const SecStrBuf54 *)src; \ break; \ case 55: \ *(SecStrBuf55 *)dest = *(const SecStrBuf55 *)src; \ break; \ case 56: \ *(SecStrBuf56 *)dest = *(const SecStrBuf56 *)src; \ break; \ case 57: \ *(SecStrBuf57 *)dest = *(const SecStrBuf57 *)src; \ break; \ case 58: \ *(SecStrBuf58 *)dest = *(const SecStrBuf58 *)src; \ break; \ case 59: \ *(SecStrBuf59 *)dest = *(const SecStrBuf59 *)src; \ break; \ case 60: \ *(SecStrBuf60 *)dest = *(const SecStrBuf60 *)src; \ break; \ case 61: \ *(SecStrBuf61 *)dest = *(const SecStrBuf61 *)src; \ break; \ case 62: \ *(SecStrBuf62 *)dest = *(const SecStrBuf62 *)src; \ break; \ case 63: \ *(SecStrBuf63 *)dest = *(const SecStrBuf63 *)src; \ break; \ case 64: \ *(SecStrBuf64 *)dest = *(const SecStrBuf64 *)src; \ break; \ default: \ break; \ } /* END switch */ \ } else { \ char *tmpDest = (char *)dest; \ const char *tmpSrc = (const char *)src; \ switch (count) { \ case 64: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 63: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 62: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 61: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 60: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 59: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 58: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 57: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 56: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 55: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 54: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 53: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 52: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 51: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 50: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 49: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 48: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 47: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 46: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 45: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 44: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 43: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 42: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 41: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 40: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 39: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 38: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 37: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 36: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 35: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 34: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 33: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 32: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 31: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 30: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 29: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 28: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 27: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 26: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 25: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 24: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 23: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 22: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 21: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 20: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 19: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 18: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 17: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 16: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 15: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 14: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 13: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 12: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 11: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 10: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 9: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 8: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 7: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 6: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 5: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 4: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 3: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 2: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ case 1: \ *(tmpDest++) = *(tmpSrc++); \ /* fall-through */ /* FALLTHRU */ \ default: \ break; \ } \ } \ } SECUREC_WHILE_ZERO #endif /* * Handling errors */ static errno_t SecMemcpyError(void *dest, size_t destMax, const void *src, size_t count) { if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) { SECUREC_ERROR_INVALID_RANGE("memcpy_s"); return ERANGE; } if (dest == NULL || src == NULL) { SECUREC_ERROR_INVALID_PARAMTER("memcpy_s"); if (dest != NULL) { (void)memset(dest, 0, destMax); return EINVAL_AND_RESET; } return EINVAL; } if (count > destMax) { (void)memset(dest, 0, destMax); SECUREC_ERROR_INVALID_RANGE("memcpy_s"); return ERANGE_AND_RESET; } if (dest == src) { return EOK; } if ((dest > src && dest < (const void *)((const unsigned char *)src + count)) || \ (src > dest && src < (void *)((unsigned char *)dest + count))) { (void)memset(dest, 0, destMax); SECUREC_ERROR_BUFFER_OVERLAP("memcpy_s"); return EOVERLAP_AND_RESET; } /* count == 0 also return EOK */ return EOK; } #if SECUREC_WITH_PERFORMANCE_ADDONS || SECUREC_MEMCOPY_WITH_PERFORMANCE /* * Performance optimization */ static void SecDoMemcpyOpt(void *dest, const void *src, size_t count) { if (count > SECUREC_MEMCOPY_THRESHOLD_SIZE) { SecDoMemcpy(dest, src, count); } else { SECUREC_SMALL_MEM_COPY; } return; } #endif #if defined(SECUREC_COMPATIBLE_WIN_FORMAT) /* fread API in windows will call memcpy_s and pass 0xffffffff to destMax. * To avoid the failure of fread, we don't check desMax limit. */ #define SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count) (SECUREC_LIKELY((count) <= (destMax) && \ (dest) != NULL && (src) != NULL && \ (count) > 0 && SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count)))) #else #define SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count) (SECUREC_LIKELY((count) <= (destMax) && \ (dest) != NULL && (src) != NULL && \ (destMax) <= SECUREC_MEM_MAX_LEN && \ (count) > 0 && SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count)))) #endif /* * * The memcpy_s function copies n characters from the object pointed to by src into the object pointed to by dest * * * dest Destination buffer. * destMax Size of the destination buffer. * src Buffer to copy from. * count Number of characters to copy * * * dest buffer is updated. * * * EOK Success * EINVAL dest is NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN * EINVAL_AND_RESET dest != NULL and src is NULLL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN * ERANGE destMax > SECUREC_MEM_MAX_LEN or destMax is 0 * ERANGE_AND_RESET count > destMax and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN * and dest != NULL and src != NULL * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and * count <= destMax destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN and dest != NULL * and src != NULL and dest != src * * if an error occured, dest will be filled with 0. * If the source and destination overlap, the behavior of memcpy_s is undefined. * Use memmove_s to handle overlapping regions. */ errno_t memcpy_s(void *dest, size_t destMax, const void *src, size_t count) { if (SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count)) { #if SECUREC_MEMCOPY_WITH_PERFORMANCE SecDoMemcpyOpt(dest, src, count); #else SecDoMemcpy(dest, src, count); #endif return EOK; } /* meet some runtime violation, return error code */ return SecMemcpyError(dest, destMax, src, count); } #if SECUREC_IN_KERNEL EXPORT_SYMBOL(memcpy_s); #endif #if SECUREC_WITH_PERFORMANCE_ADDONS /* * Performance optimization */ errno_t memcpy_sOptAsm(void *dest, size_t destMax, const void *src, size_t count) { if (SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count)) { SecDoMemcpyOpt(dest, src, count); return EOK; } /* meet some runtime violation, return error code */ return SecMemcpyError(dest, destMax, src, count); } /* trim judgement on "destMax <= SECUREC_MEM_MAX_LEN" */ errno_t memcpy_sOptTc(void *dest, size_t destMax, const void *src, size_t count) { if (SECUREC_LIKELY(count <= destMax && dest != NULL && src != NULL && \ count > 0 && \ ((dest > src && (const void *)((const unsigned char *)src + count) <= dest) || \ (src > dest && (void *)((unsigned char *)dest + count) <= src)))) { SecDoMemcpyOpt(dest, src, count); return EOK; } /* meet some runtime violation, return error code */ return SecMemcpyError(dest, destMax, src, count); } #endif