1 /*------------------------------------------------------------------
2  * wcsncpy_s.c
3  *
4  * August 2014, D Wheeler
5  *
6  * Copyright (c) 2014 by Intel Corp
7  * All rights reserved.
8  *
9  * Permission is hereby granted, free of charge, to any person
10  * obtaining a copy of this software and associated documentation
11  * files (the "Software"), to deal in the Software without
12  * restriction, including without limitation the rights to use,
13  * copy, modify, merge, publish, distribute, sublicense, and/or
14  * sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following
16  * conditions:
17  *
18  * The above copyright notice and this permission notice shall be
19  * included in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28  * OTHER DEALINGS IN THE SOFTWARE.
29  *------------------------------------------------------------------
30  */
31 
32 #include "safeclib_private.h"
33 #include "safe_str_constraint.h"
34 #include "safe_str_lib.h"
35 
36 
37 /*
38  * NAME
39  *    wcsncpy_s
40  *
41  * SYNOPSIS
42  *    #include "safe_str_lib.h"
43  *    errno_t
44  *    wcsncpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src, rsize_t slen)
45  *
46  * DESCRIPTION
47  *    The wcsncpy_s function copies not more than slen successive characters
48  *    (characters that follow a null character are not copied) from the
49  *    array pointed to by src to the array pointed to by dest. If no null
50  *    character was copied from src, then dest[slen] is set to a null character.
51  *
52  *    All elements following the terminating null character (if any)
53  *    written by wcsncpy_s in the array of dmax characters pointed to
54  *    by dest take on the null value when wcsncpy_s returns.
55  *
56  *    When SAFECLIB_STR_NULL_SLACK is defined to be true (#DEFINE), then
57  *    the dest array is filled with NULL characters following the end of
58  *    the last non-NULL character from src. While this is more secure, it
59  *    is also incurs a performance penalty, especially when the same dest
60  *    array is used multiple times to string manipulation routines in this
61  *    library. If this extra security is not required, ensure that the
62  *    library is compiled without #DEFINE SAFECLIB_STR_NULL_SLACK.
63  *
64  * Specicified in:
65  *    ISO/IEC TR 24731-1, Programming languages, environments
66  *    and system software interfaces, Extensions to the C Library,
67  *    Part I: Bounds-checking interfaces
68  *
69  * INPUT PARAMETERS
70  *    dest      pointer to string that will be replaced by src.
71  *              The resulting string is null terminated.
72  *
73  *    dmax      restricted maximum length of the resulting dest,
74  *              including the null
75  *
76  *    src       pointer to the string that will be copied
77  *              to string dest
78  *
79  *    slen      the maximum number of characters to copy from src
80  *
81  * OUTPUT PARAMETERS
82  *    dest      updated with src string
83  *
84  * RUNTIME CONSTRAINTS
85  *    Neither dmax nor slen shall be equal to zero.
86  *    Neither dmax nor slen shall be equal zero.
87  *    Neither dmax nor slen shall be greater than RSIZE_MAX_STR.
88  *    If slen is either greater than or equal to dmax, then dmax
89  *     should be more than strnlen_s(src,dmax)
90  *    Copying shall not take place between objects that overlap.
91  *    If there is a runtime-constraint violation, then if dest
92  *       is not a null pointer and dmax greater than RSIZE_MAX_STR,
93  *       then strncpy_s nulls dest.
94  *
95  * RETURN VALUE
96  *    EOK        successful operation, the characters in src were copied
97  *                  to dest and the result is null terminated.
98  *    ESNULLP    NULL pointer
99  *    ESZEROL    zero length
100  *    ESLEMAX    length exceeds max limit
101  *    ESOVRLP    strings overlap
102  *    ESNOSPC    not enough space to copy src
103  *
104  * ALSO SEE
105  *    strcat_s(), strncat_s(), strcpy_s()
106  *    wcscat_s(), wcsncat_s(), wcscpy_s()
107  *-
108  */
109 errno_t
wcsncpy_s(wchar_t * dest,rsize_t dmax,const wchar_t * src,rsize_t slen)110 wcsncpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src, rsize_t slen)
111 {
112     rsize_t orig_dmax;
113     wchar_t *orig_dest;
114     const wchar_t *overlap_bumper;
115 
116     if (dest == NULL) {
117         invoke_safe_str_constraint_handler("wcsncpy_s: dest is null",
118                    NULL, ESNULLP);
119         return RCNEGATE(ESNULLP);
120     }
121 
122     if (dmax == 0) {
123         invoke_safe_str_constraint_handler("wcsncpy_s: dmax is 0",
124                    NULL, ESZEROL);
125         return RCNEGATE(ESZEROL);
126     }
127 
128     if (dmax*sizeof(wchar_t) > RSIZE_MAX_STR) {
129         invoke_safe_str_constraint_handler("wcsncpy_s: dmax exceeds max",
130                    NULL, ESLEMAX);
131         return RCNEGATE(ESLEMAX);
132     }
133 
134     /* hold base in case src was not copied */
135     orig_dmax = dmax;
136     orig_dest = dest;
137 
138     if (src == NULL) {
139         handle_wc_error(orig_dest, orig_dmax, "wcsncpy_s: src is null",
140                      ESNULLP);
141         return RCNEGATE(ESNULLP);
142     }
143 
144     if (slen == 0) {
145         handle_wc_error(orig_dest, orig_dmax, "wcsncpy_s: slen is zero",
146                      ESZEROL);
147         return RCNEGATE(ESZEROL);
148     }
149 
150     if (slen*sizeof(wchar_t) > RSIZE_MAX_STR) {
151         handle_wc_error(orig_dest, orig_dmax, "wcsncpy_s: slen exceeds max",
152                      ESLEMAX);
153         return RCNEGATE(ESLEMAX);
154     }
155 
156 
157    if (dest < src) {
158        overlap_bumper = src;
159 
160         while (dmax > 0) {
161             if (dest == overlap_bumper) {
162                 handle_wc_error(orig_dest, orig_dmax, "wcsncpy_s: overlapping objects",
163                         ESOVRLP);
164                 return RCNEGATE(ESOVRLP);
165             }
166 
167 	    if (slen == 0) {
168                 /*
169                  * Copying truncated to slen chars.  Note that the TR says to
170                  * copy slen chars plus the null char.  We null the slack.
171                  */
172 #ifdef SAFECLIB_STR_NULL_SLACK
173                 while (dmax) { *dest = '\0'; dmax--; dest++; }
174 #else
175                 *dest = '\0';
176 #endif
177                 return RCNEGATE(EOK);
178             }
179 
180             *dest = *src;
181             if (*dest == '\0') {
182 #ifdef SAFECLIB_STR_NULL_SLACK
183                 /* null slack */
184                 while (dmax) { *dest = '\0'; dmax--; dest++; }
185 #endif
186                 return RCNEGATE(EOK);
187             }
188 
189             dmax--;
190             slen--;
191             dest++;
192             src++;
193         }
194 
195     } else {
196         overlap_bumper = dest;
197 
198         while (dmax > 0) {
199             if (src == overlap_bumper) {
200                 handle_wc_error(orig_dest, orig_dmax, "wcsncpy_s: overlapping objects",
201                         ESOVRLP);
202                 return RCNEGATE(ESOVRLP);
203             }
204 
205 	    if (slen == 0) {
206                 /*
207                  * Copying truncated to slen chars.  Note that the TR says to
208                  * copy slen chars plus the null char.  We null the slack.
209                  */
210 #ifdef SAFECLIB_STR_NULL_SLACK
211                 while (dmax) { *dest = '\0'; dmax--; dest++; }
212 #else
213                 *dest = '\0';
214 #endif
215                 return RCNEGATE(EOK);
216             }
217 
218             *dest = *src;
219             if (*dest == '\0') {
220 #ifdef SAFECLIB_STR_NULL_SLACK
221                 /* null slack */
222                 while (dmax) { *dest = '\0'; dmax--; dest++; }
223 #endif
224                 return RCNEGATE(EOK);
225             }
226 
227             dmax--;
228             slen--;
229             dest++;
230             src++;
231         }
232     }
233 
234     /*
235      * the entire src was not copied, so zero the string
236      */
237     handle_wc_error(orig_dest, orig_dmax, "wcsncpy_s: not enough space for src",
238                  ESNOSPC);
239     return RCNEGATE(ESNOSPC);
240 }
241 EXPORT_SYMBOL(wcsncpy_s)
242