safec  2.1
Safe C Library - ISO TR24731 Bounds Checking Interface
strncpy_s.c
Go to the documentation of this file.
1 /*------------------------------------------------------------------
2  * strncpy_s.c
3  *
4  * October 2008, Bo Berry
5  *
6  * Copyright (c) 2008-2011 by Cisco Systems, Inc
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 
87 errno_t
88 strncpy_s (char * restrict dest, rsize_t dmax, const char * restrict src, rsize_t slen)
89 {
90  rsize_t orig_dmax;
91  char *orig_dest;
92  const char *overlap_bumper;
93 
94  if (dest == NULL) {
95  invoke_safe_str_constraint_handler("strncpy_s: dest is null",
96  NULL, ESNULLP);
97  return RCNEGATE(ESNULLP);
98  }
99 
100  if (dmax == 0) {
101  invoke_safe_str_constraint_handler("strncpy_s: dmax is 0",
102  NULL, ESZEROL);
103  return RCNEGATE(ESZEROL);
104  }
105 
106  if (dmax > RSIZE_MAX_STR) {
107  invoke_safe_str_constraint_handler("strncpy_s: dmax exceeds max",
108  NULL, ESLEMAX);
109  return RCNEGATE(ESLEMAX);
110  }
111 
112  /* hold base in case src was not copied */
113  orig_dmax = dmax;
114  orig_dest = dest;
115 
116  if (src == NULL) {
117  handle_error(orig_dest, orig_dmax, "strncpy_s: "
118  "src is null",
119  ESNULLP);
120  return RCNEGATE(ESNULLP);
121  }
122 
123  if (slen == 0) {
124  handle_error(orig_dest, orig_dmax, "strncpy_s: "
125  "slen is zero",
126  ESZEROL);
127  return RCNEGATE(ESZEROL);
128  }
129 
130  if (slen > RSIZE_MAX_STR) {
131  handle_error(orig_dest, orig_dmax, "strncpy_s: "
132  "slen exceeds max",
133  ESLEMAX);
134  return RCNEGATE(ESLEMAX);
135  }
136 
137 
138  if (dest < src) {
139  overlap_bumper = src;
140 
141  while (dmax > 0) {
142  if (dest == overlap_bumper) {
143  handle_error(orig_dest, orig_dmax, "strncpy_s: "
144  "overlapping objects",
145  ESOVRLP);
146  return RCNEGATE(ESOVRLP);
147  }
148 
149  if (slen == 0) {
150  /*
151  * Copying truncated to slen chars. Note that the TR says to
152  * copy slen chars plus the null char. We null the slack.
153  */
154 #ifdef SAFECLIB_STR_NULL_SLACK
155  while (dmax) { *dest = '\0'; dmax--; dest++; }
156 #else
157  *dest = '\0';
158 #endif
159  return RCNEGATE(EOK);
160  }
161 
162  *dest = *src;
163  if (*dest == '\0') {
164 #ifdef SAFECLIB_STR_NULL_SLACK
165  /* null slack */
166  while (dmax) { *dest = '\0'; dmax--; dest++; }
167 #endif
168  return RCNEGATE(EOK);
169  }
170 
171  dmax--;
172  slen--;
173  dest++;
174  src++;
175  }
176 
177  } else {
178  overlap_bumper = dest;
179 
180  while (dmax > 0) {
181  if (src == overlap_bumper) {
182  handle_error(orig_dest, orig_dmax, "strncpy_s: "
183  "overlapping objects",
184  ESOVRLP);
185  return RCNEGATE(ESOVRLP);
186  }
187 
188  if (slen == 0) {
189  /*
190  * Copying truncated to slen chars. Note that the TR says to
191  * copy slen chars plus the null char. We null the slack.
192  */
193 #ifdef SAFECLIB_STR_NULL_SLACK
194  while (dmax) { *dest = '\0'; dmax--; dest++; }
195 #else
196  *dest = '\0';
197 #endif
198  return RCNEGATE(EOK);
199  }
200 
201  *dest = *src;
202  if (*dest == '\0') {
203 #ifdef SAFECLIB_STR_NULL_SLACK
204  /* null slack */
205  while (dmax) { *dest = '\0'; dmax--; dest++; }
206 #endif
207  return RCNEGATE(EOK);
208  }
209 
210  dmax--;
211  slen--;
212  dest++;
213  src++;
214  }
215  }
216 
217  /*
218  * the entire src was not copied, so zero the string
219  */
220  handle_error(orig_dest, orig_dmax, "strncpy_s: not enough "
221  "space for src",
222  ESNOSPC);
223  return RCNEGATE(ESNOSPC);
224 }
225 EXPORT_SYMBOL(strncpy_s)
void invoke_safe_str_constraint_handler(const char *msg, void *ptr, errno_t error)
Invokes the currently set constraint handler or the default.
errno_t strncpy_s(char *restrict dest, rsize_t dmax, const char *restrict src, rsize_t slen)
The strncpy_s function copies not more than slen successive characters (characters that follow a null...
Definition: strncpy_s.c:88