• 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
SecDoStrncat(char * strDest,size_t destMax,const char * strSrc,size_t count)19 static errno_t SecDoStrncat(char *strDest, size_t destMax, const char *strSrc, size_t count)
20 {
21     size_t destLen = strnlen(strDest, destMax);
22     /* The strSrc is no longer optimized. The reason is that when count is small,
23      * the efficiency of strnlen is higher than that of self realization.
24      */
25     size_t srcLen = strnlen(strSrc, count);
26 
27     if ((strDest < strSrc && strDest + destLen + srcLen >= strSrc) || \
28         (strSrc < strDest && strSrc + srcLen >= strDest)) {
29         strDest[0] = '\0';
30         if (strDest + destLen <= strSrc && destLen == destMax) {
31             SECUREC_ERROR_INVALID_PARAMTER("strncat_s");
32             return EINVAL_AND_RESET;
33         }
34         SECUREC_ERROR_BUFFER_OVERLAP("strncat_s");
35         return EOVERLAP_AND_RESET;
36     }
37     if (srcLen + destLen >= destMax || strDest == strSrc) {
38         strDest[0] = '\0';
39         if (destLen == destMax) {
40             SECUREC_ERROR_INVALID_PARAMTER("strncat_s");
41             return EINVAL_AND_RESET;
42         }
43         SECUREC_ERROR_INVALID_RANGE("strncat_s");
44         return ERANGE_AND_RESET;
45     }
46     (void)memcpy(strDest + destLen, strSrc, srcLen);    /* no  terminator */
47     *(strDest + destLen + srcLen) = '\0';
48     return EOK;
49 }
50 #else
SecDoStrncat(char * strDest,size_t destMax,const char * strSrc,size_t count)51 static errno_t SecDoStrncat(char *strDest, size_t destMax, const char *strSrc, size_t count)
52 {
53     char *tmpDest = strDest;
54     const char *tmpSrc = strSrc;
55     size_t availableSize = destMax;
56     size_t maxCount = count;
57     SECUREC_IN_REGISTER const char *overlapGuard = NULL;
58 
59     if (tmpDest < tmpSrc) {
60         overlapGuard = tmpSrc;
61         while (availableSize > 0 && *tmpDest != '\0') {
62             if (tmpDest == overlapGuard) {
63                 strDest[0] = '\0';
64                 SECUREC_ERROR_BUFFER_OVERLAP("strncat_s");
65                 return EOVERLAP_AND_RESET;
66             }
67             ++tmpDest;
68             --availableSize;
69         }
70 
71         /* strDestination unterminated, return error. */
72         if (availableSize == 0) {
73             strDest[0] = '\0';
74             SECUREC_ERROR_INVALID_PARAMTER("strncat_s");
75             return EINVAL_AND_RESET;
76         }
77         while (maxCount > 0 && (*tmpDest++ = *tmpSrc++) != '\0' && --availableSize > 0) {
78             if (tmpDest == overlapGuard) {
79                 strDest[0] = '\0';
80                 SECUREC_ERROR_BUFFER_OVERLAP("strncat_s");
81                 return EOVERLAP_AND_RESET;
82             }
83             --maxCount;
84         }
85     } else {
86         overlapGuard = tmpDest;
87         while (availableSize > 0 && *tmpDest != '\0') {
88             /* seek to string end, and no need to check overlap */
89             ++tmpDest;
90             --availableSize;
91         }
92 
93         /* strDest unterminated, return error. */
94         if (availableSize == 0) {
95             strDest[0] = '\0';
96             SECUREC_ERROR_INVALID_PARAMTER("strncat_s");
97             return EINVAL_AND_RESET;
98         }
99         while (maxCount > 0 && (*tmpDest++ = *tmpSrc++) != '\0' && --availableSize > 0) {
100             if (tmpSrc == overlapGuard) {
101                 strDest[0] = '\0';
102                 SECUREC_ERROR_BUFFER_OVERLAP("strncat_s");
103                 return EOVERLAP_AND_RESET;
104             }
105             --maxCount;
106         }
107     }
108     if (maxCount == 0) {
109         *tmpDest = 0;           /* add terminator to strDest */
110     }
111 
112     /* strDest have not enough space,return error */
113     if (availableSize == 0) {
114         strDest[0] = '\0';
115         SECUREC_ERROR_INVALID_RANGE("strncat_s");
116         return ERANGE_AND_RESET;
117     }
118 
119     return EOK;
120 }
121 #endif
122 
123 /*******************************************************************************
124  * <FUNCTION DESCRIPTION>
125  *    The strncat_s function appends not more than n successive  characters
126  *    (not including the terminating null  character)
127  *     from the array pointed to by strSrc to the end of the  string pointed to by strDest
128  *    The strncat_s function try to append the first D characters of strSrc to
129  *    the end of strDest, where D is the lesser of count and the length of strSrc.
130  *    If appending those D characters will fit within strDest (whose size is given
131  *    as destMax) and still leave room for a null terminator, then those characters
132  *    are appended, starting at the original terminating null of strDest, and a
133  *    new terminating null is appended; otherwise, strDest[0] is set to the null
134  *    character.
135  *
136  * <INPUT PARAMETERS>
137  *    strDest            Null-terminated destination string.
138  *    destMax            Size of the destination buffer.
139  *    strSrc             Null-terminated source string.
140  *    count              Number of character to append, or truncate.
141  *
142  * <OUTPUT PARAMETERS>
143  *    strDest            is updated
144  *
145  * <RETURN VALUE>
146  *    EOK                Success
147  *    EINVAL             strDest is  NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
148  *    EINVAL_AND_RESET      (strDest unterminated  and all other parameters are valid)or
149  *                        (strDest !=  NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN)
150  *    ERANGE                         destMax is 0 and destMax > SECUREC_STRING_MAX_LEN
151  *    ERANGE_AND_RESET      strDest have not enough space  and all other parameters are valid  and not overlap
152  *    EOVERLAP_AND_RESET   dest buffer and source buffer are overlapped and all  parameters are valid
153  *
154  *    If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
155  ********************************************************************************
156  */
strncat_s(char * strDest,size_t destMax,const char * strSrc,size_t count)157 errno_t strncat_s(char *strDest, size_t destMax, const char *strSrc, size_t count)
158 {
159     if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) {
160         SECUREC_ERROR_INVALID_RANGE("strncat_s");
161         return ERANGE;
162     }
163 
164     if (strDest == NULL || strSrc == NULL) {
165         SECUREC_ERROR_INVALID_PARAMTER("strncat_s");
166         if (strDest != NULL) {
167             strDest[0] = '\0';
168             return EINVAL_AND_RESET;
169         }
170         return EINVAL;
171     }
172 #ifdef  SECUREC_COMPATIBLE_WIN_FORMAT
173     if (count > SECUREC_STRING_MAX_LEN && count != (size_t)-1) {
174         strDest[0] = '\0';
175         SECUREC_ERROR_INVALID_RANGE("strncat_s");
176         return ERANGE_AND_RESET;
177     }
178 #else
179     if (count > SECUREC_STRING_MAX_LEN) {
180         strDest[0] = '\0';
181         SECUREC_ERROR_INVALID_RANGE("strncat_s");
182         return ERANGE_AND_RESET;
183     }
184 #endif
185 
186     return SecDoStrncat(strDest, destMax, strSrc, count);
187 }
188 
189 #if SECUREC_IN_KERNEL
190 EXPORT_SYMBOL(strncat_s);
191 #endif
192 
193