• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "securecutil.h"
17 
18 #if SECUREC_HAVE_STRNLEN
19 #define SECUREC_STRCAT_LEN_THRESHOLD 8
20 
21 #define SECUREC_CALC_STR_LEN(str,maxLen,len) do { \
22             if (*((str) + 0) == '\0') { \
23                 len = 0; \
24             } else if (*((str) + 1) == '\0') { \
25                 len = 1; \
26             } else if (*((str) + 2) == '\0') { \
27                 len = 2; \
28             } else if (*((str) + 3) == '\0') { \
29                 len = 3; \
30             } else if (*((str) + 4) == '\0') { \
31                 len = 4; \
32             } else if (*((str) + 5) == '\0') { \
33                 len = 5; \
34             } else if (*((str) + 6) == '\0') { \
35                 len = 6; \
36             } else if (*((str) + 7) == '\0') { \
37                 len = 7; \
38             } else if (*((str) + 8) == '\0') { \
39                 /* Optimization with a length of 8 */ \
40                 len = 8; \
41             } else { \
42                 /* The offset is 8 because the performance of 8 byte alignment is high */ \
43                 len = SECUREC_STRCAT_LEN_THRESHOLD + \
44                       strnlen((str) + SECUREC_STRCAT_LEN_THRESHOLD, \
45                       (maxLen) - SECUREC_STRCAT_LEN_THRESHOLD); \
46             } \
47         } SECUREC_WHILE_ZERO
48 
49 /* The function compiler will be inlined and not placed in other files */
SecMinStrLenOpt(const char * str,size_t maxLen)50 static size_t SecMinStrLenOpt(const char *str, size_t maxLen)
51 {
52     size_t len;
53     if (maxLen > SECUREC_STRCAT_LEN_THRESHOLD) {
54         /* Just to reduce the code complexity */
55         SECUREC_CALC_STR_LEN(str, maxLen, len);
56     } else {
57         const char *strEnd = str;
58         len = 0;
59         /* use count  as boundary checker */
60         while (len < maxLen && *(strEnd) != '\0') {
61             ++strEnd;
62             ++len;              /* no ending terminator */
63         }
64     }
65     return len;
66 }
67 
SecDoStrcat(char * strDest,size_t destMax,const char * strSrc)68 static errno_t SecDoStrcat(char *strDest, size_t destMax, const char *strSrc)
69 {
70     size_t destLen = strnlen(strDest, destMax);
71     /* Only optimize strSrc, do not apply this function to strDest */
72     size_t srcLen = SecMinStrLenOpt(strSrc, destMax - destLen);
73 
74     if ((strDest < strSrc && strDest + destLen + srcLen >= strSrc) || \
75         (strSrc < strDest && strSrc + srcLen >= strDest)) {
76         strDest[0] = '\0';
77         if (strDest + destLen <= strSrc && destLen == destMax) {
78             SECUREC_ERROR_INVALID_PARAMTER("strcat_s");
79             return EINVAL_AND_RESET;
80         }
81         SECUREC_ERROR_BUFFER_OVERLAP("strcat_s");
82         return EOVERLAP_AND_RESET;
83     }
84     if (srcLen + destLen >= destMax || strDest == strSrc) {
85         strDest[0] = '\0';
86         if (destLen == destMax) {
87             SECUREC_ERROR_INVALID_PARAMTER("strcat_s");
88             return EINVAL_AND_RESET;
89         }
90         SECUREC_ERROR_INVALID_RANGE("strcat_s");
91         return ERANGE_AND_RESET;
92     }
93     (void)memcpy(strDest + destLen, strSrc, srcLen + 1);    /* copy terminator */
94     return EOK;
95 }
96 #else
SecDoStrcat(char * strDest,size_t destMax,const char * strSrc)97 static errno_t SecDoStrcat(char *strDest, size_t destMax, const char *strSrc)
98 {
99     char *tmpDest = strDest;
100     const char *tmpSrc = strSrc;
101     size_t availableSize = destMax;
102     SECUREC_IN_REGISTER const char *overlapGuard = NULL;
103 
104     if (tmpDest < tmpSrc) {
105         overlapGuard = tmpSrc;
106         while (availableSize > 0 && *tmpDest != 0) {
107             if (tmpDest == overlapGuard) {
108                 strDest[0] = '\0';
109                 SECUREC_ERROR_BUFFER_OVERLAP("strcat_s");
110                 return EOVERLAP_AND_RESET;
111             }
112             /* seek to string end */
113             ++tmpDest;
114             --availableSize;
115         }
116 
117         /* strDest unterminated, return error. */
118         if (availableSize == 0) {
119             strDest[0] = '\0';
120             SECUREC_ERROR_INVALID_PARAMTER("strcat_s");
121             return EINVAL_AND_RESET;
122         }
123         /* if availableSize > 0, then execute the strcat operation */
124         while ((*tmpDest++ = *tmpSrc++) != 0 && --availableSize > 0) {
125             if (tmpDest == overlapGuard) {
126                 strDest[0] = '\0';
127                 SECUREC_ERROR_BUFFER_OVERLAP("strcat_s");
128                 return EOVERLAP_AND_RESET;
129             }
130         }
131     } else {
132         overlapGuard = tmpDest;
133         while (availableSize > 0 && *tmpDest != '\0') {
134             /* seek to string end, and no need to check overlap */
135             ++tmpDest;
136             --availableSize;
137         }
138 
139         /* strDest unterminated, return error. */
140         if (availableSize == 0) {
141             strDest[0] = '\0';
142             SECUREC_ERROR_INVALID_PARAMTER("strcat_s");
143             return EINVAL_AND_RESET;
144         }
145         while ((*tmpDest++ = *tmpSrc++) != '\0' && --availableSize > 0) {
146             if (tmpSrc == overlapGuard) {
147                 strDest[0] = '\0';
148                 SECUREC_ERROR_BUFFER_OVERLAP("strcat_s");
149                 return EOVERLAP_AND_RESET;
150             }
151         }
152     }
153 
154     /* strDest have not enough space, return error */
155     if (availableSize == 0) {
156         strDest[0] = '\0';
157         SECUREC_ERROR_INVALID_RANGE("strcat_s");
158         return ERANGE_AND_RESET;
159     }
160     return EOK;
161 }
162 #endif
163 /*******************************************************************************
164  * <FUNCTION DESCRIPTION>
165  *    The strcat_s function appends a copy of the string pointed to by strSrc (including the terminating null character)
166  *    to the end of the  string pointed to by strDest.
167  *    The initial character of strSrc overwrites the terminating null character of strDest.
168  *    strcat_s will return EOVERLAP_AND_RESET if the source and destination strings overlap.
169  *
170  *    Note that the second parameter is the total size of the buffer, not the
171  *    remaining size.
172  *
173  * <INPUT PARAMETERS>
174  *    strDest             Null-terminated destination string buffer.
175  *    destMax             Size of the destination string buffer.
176  *    strSrc              Null-terminated source string buffer.
177  *
178  * <OUTPUT PARAMETERS>
179  *    strDest             is updated
180  *
181  * <RETURN VALUE>
182  *    EOK                 Success
183  *    EINVAL              strDest is  NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
184  *    EINVAL_AND_RESET    (strDest unterminated  and all other parameters are valid)or
185  *                         (strDest !=  NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN)
186  *    ERANGE              destMax is 0 and destMax > SECUREC_STRING_MAX_LEN
187  *    ERANGE_AND_RESET      strDest have not enough space  and all other parameters are valid  and not overlap
188  *    EOVERLAP_AND_RESET   dest buffer and source buffer are overlapped and all  parameters are valid
189  *
190  *    If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
191  *******************************************************************************
192  */
193 
strcat_s(char * strDest,size_t destMax,const char * strSrc)194 errno_t strcat_s(char *strDest, size_t destMax, const char *strSrc)
195 {
196 
197     if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) {
198         SECUREC_ERROR_INVALID_RANGE("strcat_s");
199         return ERANGE;
200     }
201 
202     if (strDest == NULL || strSrc == NULL) {
203         SECUREC_ERROR_INVALID_PARAMTER("strcat_s");
204         if (strDest != NULL) {
205             strDest[0] = '\0';
206             return EINVAL_AND_RESET;
207         }
208         return EINVAL;
209     }
210 
211     return SecDoStrcat(strDest, destMax, strSrc);
212 }
213 
214 #if SECUREC_IN_KERNEL
215 EXPORT_SYMBOL(strcat_s);
216 #endif
217 
218