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 "vsnprintf_s_p.h"
17
18 #include <cstdlib>
19 #include <cstring>
20 #include <stdio.h>
21
22 /* Define the max length of the string */
23 #ifndef SECUREC_STRING_MAX_LEN
24 #define SECUREC_STRING_MAX_LEN 0x7fffffffUL
25 #endif
26
27 #if SECUREC_STRING_MAX_LEN > 0x7fffffffUL
28 #error "max string is 2G"
29 #endif
30
31 #if defined(_DEBUG) || defined(DEBUG)
32 #if defined(SECUREC_ERROR_HANDLER_BY_ASSERT)
33 #define SECUREC_ERROR_INVALID_PARAMTER(msg) assert( msg "invalid argument" == NULL)
34 #define SECUREC_ERROR_INVALID_RANGE(msg) assert( msg "invalid dest buffer size" == NULL)
35 #elif defined(SECUREC_ERROR_HANDLER_BY_PRINTF)
36 #if SECUREC_IN_KERNEL
37 #define SECUREC_ERROR_INVALID_PARAMTER(msg) printk( "%s invalid argument\n",msg)
38 #define SECUREC_ERROR_INVALID_RANGE(msg) printk( "%s invalid dest buffer size\n", msg)
39 #else
40 #define SECUREC_ERROR_INVALID_PARAMTER(msg) printf( "%s invalid argument\n",msg)
41 #define SECUREC_ERROR_INVALID_RANGE(msg) printf( "%s invalid dest buffer size\n", msg)
42 #endif
43 #elif defined(SECUREC_ERROR_HANDLER_BY_FILE_LOG)
44 #define SECUREC_ERROR_INVALID_PARAMTER(msg) LogSecureCRuntimeError(msg " EINVAL\n")
45 #define SECUREC_ERROR_INVALID_RANGE(msg) LogSecureCRuntimeError(msg " ERANGE\n")
46 #else
47 #define SECUREC_ERROR_INVALID_PARAMTER(msg) ((void)0)
48 #define SECUREC_ERROR_INVALID_RANGE(msg) ((void)0)
49 #endif
50
51 #else
52 #define SECUREC_ERROR_INVALID_PARAMTER(msg) ((void)0)
53 #define SECUREC_ERROR_INVALID_RANGE(msg) ((void)0)
54 #define SECUREC_ERROR_BUFFER_OVERLAP(msg) ((void)0)
55 #endif
56
57 #define SECUREC_PRINTF_TRUNCATE (-2)
58 typedef struct {
59 int count;
60 char *cur;
61 } SecPrintfStream;
62
63 #ifdef SECUREC_STACK_SIZE_LESS_THAN_1K
64 /* SECUREC_BUFFER_SIZE Can not be less than 23 ,
65 *the length of the octal representation of 64-bit integers with zero lead
66 */
67 #define SECUREC_BUFFER_SIZE 256
68 #else
69 #define SECUREC_BUFFER_SIZE 512
70 #endif
71 #define SECUREC_MAX_PRECISION SECUREC_BUFFER_SIZE
72 /* max. # bytes in multibyte char ,see MB_LEN_MAX */
73 #define SECUREC_MB_LEN 16
74
75 #if (defined(_MSC_VER)) && (_MSC_VER >= 1400)
76 #define SECUREC_MASK_MSVC_CRT_WARNING __pragma(warning(push)) \
77 __pragma(warning(disable:4996 4127))
78 #define SECUREC_END_MASK_MSVC_CRT_WARNING __pragma(warning(pop))
79 #else
80 #define SECUREC_MASK_MSVC_CRT_WARNING
81 #define SECUREC_END_MASK_MSVC_CRT_WARNING
82 #endif
83
84 #define SECUREC_WHILE_ZERO SECUREC_MASK_MSVC_CRT_WARNING while (0) SECUREC_END_MASK_MSVC_CRT_WARNING
85
86 /* flag definitions */
87 /* Using macros instead of enumerations is because some of the enumerated types under the compiler are 16bit. */
88 #define SECUREC_FLAG_SIGN 0x00001U
89 #define SECUREC_FLAG_SIGN_SPACE 0x00002U
90 #define SECUREC_FLAG_LEFT 0x00004U
91 #define SECUREC_FLAG_LEADZERO 0x00008U
92 #define SECUREC_FLAG_LONG 0x00010U
93 #define SECUREC_FLAG_SHORT 0x00020U
94 #define SECUREC_FLAG_SIGNED 0x00040U
95 #define SECUREC_FLAG_ALTERNATE 0x00080U
96 #define SECUREC_FLAG_NEGATIVE 0x00100U
97 #define SECUREC_FLAG_FORCE_OCTAL 0x00200U
98 #define SECUREC_FLAG_LONG_DOUBLE 0x00400U
99 #define SECUREC_FLAG_WIDECHAR 0x00800U
100 #define SECUREC_FLAG_LONGLONG 0x01000U
101 #define SECUREC_FLAG_CHAR 0x02000U
102 #define SECUREC_FLAG_POINTER 0x04000U
103 #define SECUREC_FLAG_I64 0x08000U
104 #define SECUREC_FLAG_PTRDIFF 0x10000U
105 #define SECUREC_FLAG_SIZE 0x20000U
106 #ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
107 #define SECUREC_FLAG_INTMAX 0x40000U
108 #endif
109
110 /* put a char to output */
111 #define SECUREC_PUTC(_c,_stream) ((--(_stream)->count >= 0) ? ((*(_stream)->cur++ = (char)(_c)) & 0xff) : EOF)
112 /* to clear e835 */
113 #define SECUREC_PUTC_ZERO(_stream) ((--(_stream)->count >= 0) ? ((*(_stream)->cur++ = (char)('\0'))) : EOF)
114
115 /* state definitions */
116 typedef enum {
117 STAT_NORMAL,
118 STAT_PERCENT,
119 STAT_FLAG,
120 STAT_WIDTH,
121 STAT_DOT,
122 STAT_PRECIS,
123 STAT_SIZE,
124 STAT_TYPE,
125 STAT_INVALID
126 } SecFmtState;
127
128 #ifndef HILOG_PROHIBIT_ALLOCATION
129 #ifndef SECUREC_MALLOC
130 #define SECUREC_MALLOC(x) malloc((size_t)(x))
131 #endif
132
133 #ifndef SECUREC_FREE
134 #define SECUREC_FREE(x) free((void *)(x))
135 #endif
136
137 #else
138 #define SECUREC_MALLOC(x) (nullptr)
139 #define SECUREC_FREE(x) { printf("Malloc is not allowed, so free should not be possible to execute!"); std::abort(); }
140 #endif
141
142 #if (defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)) || defined(__ARMCC_VERSION)
143 typedef __int64 SecInt64;
144 typedef unsigned __int64 SecUnsignedInt64;
145 #if defined(__ARMCC_VERSION)
146 typedef int SecInt32;
147 typedef unsigned int SecUnsignedInt32;
148 #else
149 typedef __int32 SecInt32;
150 typedef unsigned __int32 SecUnsignedInt32;
151 #endif
152 #else
153 typedef int SecInt32;
154 typedef unsigned int SecUnsignedInt32;
155 typedef long long SecInt64;
156 typedef unsigned long long SecUnsignedInt64;
157 #endif
158
SecWriteString(const char * string,int len,SecPrintfStream * f,int * pnumwritten)159 static inline void SecWriteString(const char *string, int len, SecPrintfStream *f, int *pnumwritten)
160 {
161 const char *str = string;
162 int count = len;
163 while (count-- > 0) {
164 if (SECUREC_PUTC(*str, f) == EOF) {
165 *pnumwritten = -1;
166 break;
167 } else {
168 ++(*pnumwritten);
169 ++str;
170 }
171 }
172 }
173
SecWriteMultiChar(char ch,int num,SecPrintfStream * f,int * pnumwritten)174 static inline void SecWriteMultiChar(char ch, int num, SecPrintfStream *f, int *pnumwritten)
175 {
176 int count = num;
177 while (count-- > 0) {
178 if (SECUREC_PUTC(ch, f) == EOF) {
179 *pnumwritten = -1;
180 break;
181 } else {
182 ++(*pnumwritten);
183 }
184 }
185 }
186
187 static inline int SecVsnprintfPImpl(char *string, size_t count, int priv, const char *format, va_list arglist);
188
189 /*******************************************************************************
190 * <FUNCTION DESCRIPTION>
191 * The vsnprintf_s function is equivalent to the vsnprintf function
192 * except for the parameter destMax/count and the explicit runtime-constraints violation
193 * The vsnprintf_s function takes a pointer to an argument list, then formats
194 * and writes up to count characters of the given data to the memory pointed
195 * to by strDest and appends a terminating null.
196 *
197 * <INPUT PARAMETERS>
198 * strDest Storage location for the output.
199 * destMax The size of the strDest for output.
200 * count Maximum number of character to write(not including
201 * the terminating NULL)
202 * priv_on whether print <private> for not-public args
203 * format Format-control string.
204 * arglist pointer to list of arguments.
205 *
206 * <OUTPUT PARAMETERS>
207 * strDest is updated
208 *
209 * <RETURN VALUE>
210 * return the number of characters written, not including the terminating null
211 * return -1 if an error occurs.
212 * return -1 if count < destMax and the output string has been truncated
213 *
214 * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
215 *******************************************************************************
216 */
217 HILOG_LOCAL_API
vsnprintfp_s(char * strDest,size_t destMax,size_t count,int priv,const char * format,va_list arglist)218 int vsnprintfp_s(char *strDest, size_t destMax, size_t count, int priv, const char *format, va_list arglist)
219 {
220 int retVal;
221
222 if (format == NULL || strDest == NULL || destMax == 0 || destMax > SECUREC_STRING_MAX_LEN ||
223 (count > (SECUREC_STRING_MAX_LEN - 1) && count != (size_t)-1)) {
224 if (strDest != NULL && destMax > 0) {
225 strDest[0] = '\0';
226 }
227 SECUREC_ERROR_INVALID_PARAMTER("vsnprintfp_s");
228 return -1;
229 }
230
231 if (destMax > count) {
232 retVal = SecVsnprintfPImpl(strDest, count + 1, priv, format, arglist);
233 if (retVal == SECUREC_PRINTF_TRUNCATE) { /* lsd add to keep dest buffer not destroyed 2014.2.18 */
234 /* the string has been truncated, return -1 */
235 return -1; /* to skip error handler, return strlen(strDest) or -1 */
236 }
237 } else { /* destMax <= count */
238 retVal = SecVsnprintfPImpl(strDest, destMax, priv, format, arglist);
239 #ifdef SECUREC_COMPATIBLE_WIN_FORMAT
240 if (retVal == SECUREC_PRINTF_TRUNCATE && count == (size_t)-1) {
241 return -1;
242 }
243 #endif
244 }
245
246 if (retVal < 0) {
247 strDest[0] = '\0'; /* empty the dest strDest */
248
249 if (retVal == SECUREC_PRINTF_TRUNCATE) {
250 /* Buffer too small */
251 SECUREC_ERROR_INVALID_RANGE("vsnprintfp_s");
252 }
253
254 SECUREC_ERROR_INVALID_PARAMTER("vsnprintfp_s");
255 return -1;
256 }
257
258 return retVal;
259 }
260
261 #ifdef SECUREC_FOR_WCHAR
262 #undef SECUREC_FOR_WCHAR
263 #endif
264
265 typedef char SecChar;
266 #define SECUREC_CHAR(x) x
267
268 #define SECUREC_WRITE_MULTI_CHAR SecWriteMultiChar
269 #define SECUREC_WRITE_STRING SecWriteString
270 #include "output_p.inl"
271
SecVsnprintfPImpl(char * string,size_t count,int priv,const char * format,va_list arglist)272 static inline int SecVsnprintfPImpl(char *string, size_t count, int priv, const char *format, va_list arglist)
273 {
274 SecPrintfStream str;
275 int retVal;
276
277 str.count = (int)count; /* this count include \0 character */
278 str.cur = string;
279
280 retVal = SecOutputPS(&str, priv, format, arglist);
281 if ((retVal >= 0) && (SECUREC_PUTC_ZERO(&str) != EOF)) {
282 return (retVal);
283 } else if (str.count < 0) {
284 /* the buffer was too small; we return truncation */
285 string[count - 1] = 0;
286 return SECUREC_PRINTF_TRUNCATE;
287 }
288
289 return -1;
290 }
291