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