blocxx
SafeCString.cpp
Go to the documentation of this file.
1/*******************************************************************************
2* Copyright (C) 2005, Vintela, Inc. All rights reserved.
3* Copyright (C) 2006, Novell, Inc. All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7*
8* * Redistributions of source code must retain the above copyright notice,
9* this list of conditions and the following disclaimer.
10* * Redistributions in binary form must reproduce the above copyright
11* notice, this list of conditions and the following disclaimer in the
12* documentation and/or other materials provided with the distribution.
13* * Neither the name of
14* Vintela, Inc.,
15* nor Novell, Inc.,
16* nor the names of its contributors or employees may be used to
17* endorse or promote products derived from this software without
18* specific prior written permission.
19*
20* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30* POSSIBILITY OF SUCH DAMAGE.
31*******************************************************************************/
32
33
38#include "blocxx/BLOCXX_config.h"
40#include <cstring>
41#include <new>
42
43using namespace blocxx;
44using namespace blocxx::SafeCString;
45
46namespace
47{
48 inline char const * strend(char const * s, std::size_t n)
49 {
50 return static_cast<char const *>(std::memchr(s, '\0', n));
51 }
52
53 inline char * strend(char * s, std::size_t n)
54 {
55 return const_cast<char *>(strend(static_cast<char const *>(s), n));
56 }
57
58 char * strend_checked(char * s, std::size_t n)
59 {
60 char * retval = strend(s, n);
61 if (retval)
62 {
63 return retval;
64 }
65 else
66 {
68 OverflowException,
69 "cstring catenation first operand unterminated",
70 DEST_UNTERMINATED
71 );
72 }
73 }
74
75 // PROMISE: Copies first min(n, strlen(src) + 1) chars of src to dst.
76 // RETURNS: dst + strlen(src) if strlen(src) < n, NULL otherwise.
77 //
78 inline char * safe_strcpy(char * dst, char const * src, std::size_t n)
79 {
80#ifdef BLOCXX_HAS_MEMCCPY
81 char * rv = static_cast<char *>(std::memccpy(dst, src, '\0', n));
82 return rv ? rv - 1 : 0;
83#else
84 char const * end = strend(src, n);
85 if (end) // '\0' found
86 {
87 size_t len = end - src;
88 std::memcpy(dst, src, len + 1); // include terminating '\0'
89 return dst + len;
90 }
91 else
92 {
93 std::memcpy(dst, src, n);
94 return 0;
95 }
96#endif
97 }
98}
99
100namespace BLOCXX_NAMESPACE
101{
102namespace SafeCString
103{
104
106
107char * str_dup(char const * s)
108{
109 char * retval = new char[std::strlen(s) + 1];
110 return std::strcpy(retval, s);
111}
112
113char * str_dup_nothrow(char const * s)
114{
115 char * retval = new (std::nothrow) char[std::strlen(s)];
116 if (retval)
117 {
118 std::strcpy(retval, s);
119 }
120 return retval;
121}
122
123char * strcpy_trunc(char * dst, std::size_t dstsize, char const * src)
124{
125 std::size_t n = dstsize - 1;
126 char * retval = safe_strcpy(dst, src, n);
127 if (retval)
128 {
129 return retval;
130 }
131 else
132 {
133 dst[n] = '\0';
134 return dst + n;
135 }
136}
137
139 char * dst, std::size_t dstsize, char const * src, std::size_t srclen
140)
141{
142 std::size_t n = (srclen < dstsize ? srclen : dstsize - 1);
143 char * retval = safe_strcpy(dst, src, n);
144 if (retval)
145 {
146 return retval;
147 }
148 else
149 {
150 dst[n] = '\0';
151 return dst + n;
152 }
153}
154
155char * strcpy_check(char * dst, std::size_t dstsize, char const * src)
156{
157 char * retval = safe_strcpy(dst, src, dstsize);
158 if (retval)
159 {
160 return retval;
161 }
162 else
163 {
164 dst[dstsize - 1] = '\0';
166 OverflowException, "cstring copy overflow", RESULT_TRUNCATED);
167 }
168}
169
171 char * dst, std::size_t dstsize, char const * src, std::size_t srclen
172)
173{
174 if (srclen >= dstsize)
175 {
176 return strcpy_check(dst, dstsize, src);
177 }
178 else // srclen < dstsize
179 {
180 return strcpy_trunc(dst, srclen + 1, src);
181 }
182}
183
184char * strcat_trunc(char * dst, std::size_t dstsize, char const * src)
185{
186 char * dstend = strend_checked(dst, dstsize);
187 return strcpy_trunc(dstend, (dst + dstsize) - dstend, src);
188}
189
191 char * dst, std::size_t dstsize, char const * src, std::size_t srclen
192)
193{
194 char * dstend = strend_checked(dst, dstsize);
195 return strcpy_trunc(dstend, (dst + dstsize) - dstend, src, srclen);
196}
197
198char * strcat_check(char * dst, std::size_t dstsize, char const * src)
199{
200 char * dstend = strend_checked(dst, dstsize);
201 return strcpy_check(dstend, (dst + dstsize) - dstend, src);
202}
203
205 char * dst, std::size_t dstsize, char const * src, std::size_t srclen
206)
207{
208 char * dstend = strend_checked(dst, dstsize);
209 return strcpy_check(dstend, (dst + dstsize) - dstend, src, srclen);
210}
211
212namespace Impl
213{
214 std::size_t nchars_check(int retval, std::size_t dstsize)
215 {
216 if (retval < 0 || retval >= static_cast<int>(dstsize))
217 {
219 OverflowException, "sprintf overflow", RESULT_TRUNCATED);
220 }
221 return static_cast<std::size_t>(retval);
222 }
223}
224
225} // namespace SafeCString
226} // namespace BLOCXX_NAMESPACE
#define BLOCXX_DEFINE_EXCEPTION(NAME)
Define a new exception class named <NAME>Exception that derives from Exception.
#define BLOCXX_THROW_ERR(exType, msg, err)
Throw an exception using FILE and LINE.
std::size_t nchars_check(int retval, std::size_t dstsize)
char * str_dup_nothrow(char const *s)
Like std::strdup, except that no-throw new is used to allocate memory and NULL is returned on allocat...
char * strcpy_trunc(char *dst, std::size_t dstsize, char const *src)
PROMISE: copies the first n = min(strlen(src), dstsize - 1) characters of C-string src to dst,...
char * str_dup(char const *s)
Like std::strdup, except that new is used to allocate memory.
char * strcpy_check(char *dst, std::size_t dstsize, char const *src)
PROMISE: copies the first n = min(strlen(src), dstsize - 1) chars of the C-string src to dst and appe...
char * strcat_check(char *dst, std::size_t dstsize, char const *src)
PROMISE: If dst[0..dstsize-1] contains a '\0', appends to C-string dst the first min(strlen(src),...
int const RESULT_TRUNCATED
Error codes for use with OverflowException class.
char * strcat_trunc(char *dst, std::size_t dstsize, char const *src)
PROMISE: If dst[0..dstsize-1] contains a '\0', appends to C-string dst the first min(strlen(src),...
Taken from RFC 1321.