Bug Summary

File:src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/parse_datetime.c
Location:line 464, column 24
Description:Passed-by-value struct argument contains uninitialized data (e.g., field: 'Y')

Annotated Source Code

1#include "xmlrpc_config.h"
2
3#include <stdlib.h>
4#include <assert.h>
5#include <ctype.h>
6#include <string.h>
7
8#if HAVE_REGEX1
9#include <sys/types.h> /* Missing from regex.h in GNU libc */
10#include <regex.h>
11#endif
12
13#include "bool.h"
14
15#include "xmlrpc-c/base.h"
16#include "xmlrpc-c/base_int.h"
17#include "xmlrpc-c/util.h"
18
19#include "parse_datetime.h"
20
21
22
23#if HAVE_REGEX1
24
25static unsigned int
26digitStringValue(const char * const string,
27 regmatch_t const match) {
28/*----------------------------------------------------------------------------
29 Return the numerical value of the decimal whole number substring of
30 'string' identified by 'match'. E.g. if 'string' is 'abc34d' and
31 'match' says start at 3 and end at 5, we return 34.
32-----------------------------------------------------------------------------*/
33 unsigned int i;
34 unsigned int accum;
35
36 assert(match.rm_so >= 0)((match.rm_so >= 0) ? (void) (0) : __assert_fail ("match.rm_so >= 0"
, "../../../../libs/xmlrpc-c/src/parse_datetime.c", 36, __PRETTY_FUNCTION__
))
;
37 assert(match.rm_eo >= 0)((match.rm_eo >= 0) ? (void) (0) : __assert_fail ("match.rm_eo >= 0"
, "../../../../libs/xmlrpc-c/src/parse_datetime.c", 37, __PRETTY_FUNCTION__
))
;
38
39 for (i = match.rm_so, accum = 0; i < (unsigned)match.rm_eo; ++i) {
40 accum *= 10;
41 assert(isdigit(string[i]))((((*__ctype_b_loc ())[(int) ((string[i]))] & (unsigned short
int) _ISdigit)) ? (void) (0) : __assert_fail ("((*__ctype_b_loc ())[(int) ((string[i]))] & (unsigned short int) _ISdigit)"
, "../../../../libs/xmlrpc-c/src/parse_datetime.c", 41, __PRETTY_FUNCTION__
))
;
42 accum += string[i] - '0';
43 }
44 return accum;
45}
46#endif /* HAVE_REGEX */
47
48
49
50#if HAVE_REGEX1
51
52static unsigned int
53digitStringMillionths(const char * const string,
54 regmatch_t const match) {
55/*----------------------------------------------------------------------------
56 Return the number of millionths represented by the digits after the
57 decimal point in a decimal string, where thse digits are the substring
58 of 'string' identified by 'match'. E.g. if the substring is
59 34, we return 340,000.
60-----------------------------------------------------------------------------*/
61 unsigned int i;
62 unsigned int accum;
63
64 assert(match.rm_so >= 0)((match.rm_so >= 0) ? (void) (0) : __assert_fail ("match.rm_so >= 0"
, "../../../../libs/xmlrpc-c/src/parse_datetime.c", 64, __PRETTY_FUNCTION__
))
;
65 assert(match.rm_eo >= 0)((match.rm_eo >= 0) ? (void) (0) : __assert_fail ("match.rm_eo >= 0"
, "../../../../libs/xmlrpc-c/src/parse_datetime.c", 65, __PRETTY_FUNCTION__
))
;
66
67 for (i = match.rm_so, accum = 0; i < (unsigned)match.rm_so+6; ++i) {
68 accum *= 10;
69 if (i < (unsigned)match.rm_eo) {
70 assert(isdigit(string[i]))((((*__ctype_b_loc ())[(int) ((string[i]))] & (unsigned short
int) _ISdigit)) ? (void) (0) : __assert_fail ("((*__ctype_b_loc ())[(int) ((string[i]))] & (unsigned short int) _ISdigit)"
, "../../../../libs/xmlrpc-c/src/parse_datetime.c", 70, __PRETTY_FUNCTION__
))
;
71 accum += string[i] - '0';
72 }
73 }
74 return accum;
75}
76#endif /* HAVE_REGEX */
77
78
79#if HAVE_REGEX1
80
81static void
82subParseDtRegex_standard(regmatch_t * const matches,
83 const char * const datetimeString,
84 xmlrpc_datetime * const dtP) {
85
86 dtP->Y = digitStringValue(datetimeString, matches[1]);
87 dtP->M = digitStringValue(datetimeString, matches[2]);
88 dtP->D = digitStringValue(datetimeString, matches[3]);
89 dtP->h = digitStringValue(datetimeString, matches[4]);
90 dtP->m = digitStringValue(datetimeString, matches[5]);
91 dtP->s = digitStringValue(datetimeString, matches[6]);
92
93 if (matches[7].rm_so == -1)
94 dtP->u = 0;
95 else
96 dtP->u = digitStringMillionths(datetimeString, matches[7]);
97}
98
99
100
101static void
102subParseDtRegex_standardtzd(regmatch_t * const matches,
103 const char * const datetimeString,
104 xmlrpc_datetime * const dtP) {
105
106 dtP->Y = digitStringValue(datetimeString, matches[1]);
107 dtP->M = digitStringValue(datetimeString, matches[2]);
108 dtP->D = digitStringValue(datetimeString, matches[3]);
109 dtP->h = digitStringValue(datetimeString, matches[4]);
110 dtP->m = digitStringValue(datetimeString, matches[5]);
111 dtP->s = digitStringValue(datetimeString, matches[6]);
112}
113
114#endif /* HAVE_REGEX */
115
116
117#if HAVE_REGEX1
118
119typedef void (*regparsefunc_t)(regmatch_t * const matches,
120 const char * const datetimeString,
121 xmlrpc_datetime * const dtP);
122
123
124struct regexParser {
125 const char * const regex;
126 regparsefunc_t func;
127};
128
129static const struct regexParser iso8601Regex[]
130
131 /* Each entry of this table is instructions for recognizing and parsing
132 some form of a "dateTime.iso8601" XML element.
133
134 (Note that we recognize far more than just the XML-RPC standard
135 dateTime.iso8601).
136 */
137
138 = {
139 {
140 /* Examples:
141 YYYYMMDD[T]HHMMSS
142 YYYY-MM-DD[T]HH:MM:SS
143 YYYY-MM-DD[T]HH:MM:SS.ssss
144 */
145
146 "^([0-9]{4})\\-?([0-9]{2})\\-?([0-9]{2})T"
147 "([0-9]{2}):?([0-9]{2}):?([0-9]{2})\\.?([0-9]+)?$",
148 subParseDtRegex_standard
149 },
150
151 {
152 /* Examples:
153 YYYYMMDD[T]HHMMSS[Z]
154 YYYYMMDD[T]HHMMSS[+-]hh
155 YYYYMMDD[T]HHMMSS[+-]hhmm
156 */
157
158 "^([0-9]{4})\\-?([0-9]{2})\\-?([0-9]{2})T"
159 "([0-9]{2}):?([0-9]{2}):?([0-9]{2})[Z\\+\\-]([0-9]{2,4})?$",
160 subParseDtRegex_standardtzd
161 },
162 { NULL((void*)0), NULL((void*)0) }
163 };
164#endif /* HAVE_REGEX */
165
166
167
168#if HAVE_REGEX1
169static void
170parseDtRegex(xmlrpc_env * const envP,
171 const char * const datetimeString,
172 xmlrpc_datetime * const dtP) {
173
174 unsigned int i;
175 const struct regexParser * parserP;
176 /* The parser that matches 'datetimeString'. Null if no match yet
177 found.
178 */
179 regmatch_t matches[1024];
180
181 for (i = 0, parserP = NULL((void*)0); iso8601Regex[i].regex && !parserP; ++i) {
182 const struct regexParser * const thisParserP = &iso8601Regex[i];
183
184 regex_t re;
185 int status;
186
187 status = regcomp(&re, thisParserP->regex, REG_ICASE(1 << 1) | REG_EXTENDED1);
188
189 /* Our regex is valid, so it must have compiled: */
190 assert(status == 0)((status == 0) ? (void) (0) : __assert_fail ("status == 0", "../../../../libs/xmlrpc-c/src/parse_datetime.c"
, 190, __PRETTY_FUNCTION__))
;
191 {
192 int status;
193
194 status = regexec(&re, datetimeString, ARRAY_SIZE(matches)(sizeof(matches)/sizeof(matches[0])),
195 matches, 0);
196
197 if (status == 0) {
198 assert(matches[0].rm_so != -1)((matches[0].rm_so != -1) ? (void) (0) : __assert_fail ("matches[0].rm_so != -1"
, "../../../../libs/xmlrpc-c/src/parse_datetime.c", 198, __PRETTY_FUNCTION__
))
; /* Match of whole regex */
199
200 parserP = thisParserP;
201 }
202 regfree(&re);
203 }
204 }
205
206 if (parserP) {
207 parserP->func(matches, datetimeString, dtP);
208 } else {
209 xmlrpc_env_set_fault_formatted(
210 envP, XMLRPC_PARSE_ERROR(-503),
211 "value '%s' is not of any form we recognize "
212 "for a <dateTime.iso8601> element",
213 datetimeString);
214 }
215
216}
217#endif /* HAVE_REGEX */
218
219
220
221static __inline__ void
222parseDtNoRegex(xmlrpc_env * const envP,
223 const char * const datetimeString,
224 xmlrpc_datetime * const dtP) {
225
226 unsigned int const dtStrlen = strlen(datetimeString);
227
228 char year[4+1];
229 char month[2+1];
230 char day[2+1];
231 char hour[2+1];
232 char minute[2+1];
233 char second[2+1];
234
235 if (dtStrlen < 17 || dtStrlen == 18 || dtStrlen > 24)
236 xmlrpc_faultf(envP, "could not parse date, size incompatible: '%d'",
237 dtStrlen);
238 else {
239 year[0] = datetimeString[ 0];
240 year[1] = datetimeString[ 1];
241 year[2] = datetimeString[ 2];
242 year[3] = datetimeString[ 3];
243 year[4] = '\0';
244
245 month[0] = datetimeString[ 4];
246 month[1] = datetimeString[ 5];
247 month[2] = '\0';
248
249 day[0] = datetimeString[ 6];
250 day[1] = datetimeString[ 7];
251 day[2] = '\0';
252
253 assert(datetimeString[ 8] == 'T')((datetimeString[ 8] == 'T') ? (void) (0) : __assert_fail ("datetimeString[ 8] == 'T'"
, "../../../../libs/xmlrpc-c/src/parse_datetime.c", 253, __PRETTY_FUNCTION__
))
;
254
255 hour[0] = datetimeString[ 9];
256 hour[1] = datetimeString[10];
257 hour[2] = '\0';
258
259 assert(datetimeString[11] == ':')((datetimeString[11] == ':') ? (void) (0) : __assert_fail ("datetimeString[11] == ':'"
, "../../../../libs/xmlrpc-c/src/parse_datetime.c", 259, __PRETTY_FUNCTION__
))
;
260
261 minute[0] = datetimeString[12];
262 minute[1] = datetimeString[13];
263 minute[2] = '\0';
264
265 assert(datetimeString[14] == ':')((datetimeString[14] == ':') ? (void) (0) : __assert_fail ("datetimeString[14] == ':'"
, "../../../../libs/xmlrpc-c/src/parse_datetime.c", 265, __PRETTY_FUNCTION__
))
;
266
267 second[0] = datetimeString[15];
268 second[1] = datetimeString[16];
269 second[2] = '\0';
270
271 if (dtStrlen > 17) {
272 unsigned int const pad = 24 - dtStrlen;
273 unsigned int i;
274
275 dtP->u = atoi(&datetimeString[18]);
276 for (i = 0; i < pad; ++i)
277 dtP->u *= 10;
278 } else
279 dtP->u = 0;
280
281 dtP->Y = atoi(year);
282 dtP->M = atoi(month);
283 dtP->D = atoi(day);
284 dtP->h = atoi(hour);
285 dtP->m = atoi(minute);
286 dtP->s = atoi(second);
287 }
288}
289
290
291
292static void
293validateFirst17(xmlrpc_env * const envP,
294 const char * const dt) {
295/*----------------------------------------------------------------------------
296 Assuming 'dt' is at least 17 characters long, validate that the first
297 17 characters are a valid XML-RPC datetime, e.g.
298 "20080628T16:35:02"
299-----------------------------------------------------------------------------*/
300 unsigned int i;
301
302 for (i = 0; i < 8 && !envP->fault_occurred; ++i)
303 if (!isdigit(dt[i])((*__ctype_b_loc ())[(int) ((dt[i]))] & (unsigned short int
) _ISdigit)
)
304 xmlrpc_env_set_fault_formatted(
305 envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[i]);
306
307 if (dt[8] != 'T')
308 xmlrpc_env_set_fault_formatted(
309 envP, XMLRPC_PARSE_ERROR(-503), "9th character is '%c', not 'T'",
310 dt[8]);
311 if (!isdigit(dt[9])((*__ctype_b_loc ())[(int) ((dt[9]))] & (unsigned short int
) _ISdigit)
)
312 xmlrpc_env_set_fault_formatted(
313 envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[9]);
314 if (!isdigit(dt[10])((*__ctype_b_loc ())[(int) ((dt[10]))] & (unsigned short int
) _ISdigit)
)
315 xmlrpc_env_set_fault_formatted(
316 envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[10]);
317 if (dt[11] != ':')
318 xmlrpc_env_set_fault_formatted(
319 envP, XMLRPC_PARSE_ERROR(-503), "Not a colon: '%c'", dt[11]);
320 if (!isdigit(dt[12])((*__ctype_b_loc ())[(int) ((dt[12]))] & (unsigned short int
) _ISdigit)
)
321 xmlrpc_env_set_fault_formatted(
322 envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[12]);
323 if (!isdigit(dt[13])((*__ctype_b_loc ())[(int) ((dt[13]))] & (unsigned short int
) _ISdigit)
)
324 xmlrpc_env_set_fault_formatted(
325 envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[13]);
326 if (dt[14] != ':')
327 xmlrpc_env_set_fault_formatted(
328 envP, XMLRPC_PARSE_ERROR(-503), "Not a colon: '%c'", dt[14]);
329 if (!isdigit(dt[15])((*__ctype_b_loc ())[(int) ((dt[15]))] & (unsigned short int
) _ISdigit)
)
330 xmlrpc_env_set_fault_formatted(
331 envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[15]);
332 if (!isdigit(dt[16])((*__ctype_b_loc ())[(int) ((dt[16]))] & (unsigned short int
) _ISdigit)
)
333 xmlrpc_env_set_fault_formatted(
334 envP, XMLRPC_PARSE_ERROR(-503), "Not a digit: '%c'", dt[16]);
335}
336
337
338
339static void
340validateFractionalSeconds(xmlrpc_env * const envP,
341 const char * const dt) {
342/*----------------------------------------------------------------------------
343 Validate the fractional seconds part of the XML-RPC datetime string
344 'dt', if any. That's the decimal point and everything following
345 it.
346-----------------------------------------------------------------------------*/
347 if (strlen(dt) > 17) {
348 if (dt[17] != '.') {
349 xmlrpc_env_set_fault_formatted(
350 envP, XMLRPC_PARSE_ERROR(-503),
351 "'%c' where only a period is valid", dt[17]);
352 } else {
353 if (dt[18] == '\0')
354 xmlrpc_env_set_fault_formatted(
355 envP, XMLRPC_PARSE_ERROR(-503), "Nothing after decimal point");
356 else {
357 unsigned int i;
358 for (i = 18; dt[i] != '\0' && !envP->fault_occurred; ++i) {
359 if (!isdigit(dt[i])((*__ctype_b_loc ())[(int) ((dt[i]))] & (unsigned short int
) _ISdigit)
)
360 xmlrpc_env_set_fault_formatted(
361 envP, XMLRPC_PARSE_ERROR(-503),
362 "Non-digit in fractional seconds: '%c'", dt[i]);
363 }
364 }
365 }
366 }
367}
368
369
370
371static __inline__ void
372validateFormatNoRegex(xmlrpc_env * const envP,
373 const char * const dt) {
374
375 if (strlen(dt) < 17)
376 xmlrpc_env_set_fault_formatted(
377 envP, XMLRPC_PARSE_ERROR(-503),
378 "Invalid length of %u of datetime. "
379 "Must be at least 17 characters",
380 (unsigned)strlen(dt));
381 else {
382 validateFirst17(envP, dt);
383
384 validateFractionalSeconds(envP, dt);
385 }
386}
387
388
389
390static void
391validateXmlrpcDatetimeSome(xmlrpc_env * const envP,
392 xmlrpc_datetime const dt) {
393/*----------------------------------------------------------------------------
394 Type xmlrpc_datetime is defined such that it can represent a nonexistent
395 datetime such as February 30.
396
397 Validate that 'dt' doesn't have glaring invalidities such as Hour 25.
398 We leave the possibility of more subtle invalidity such as February 30.
399-----------------------------------------------------------------------------*/
400
401 if (dt.M < 1 || dt.M > 12)
402 xmlrpc_env_set_fault_formatted(
403 envP, XMLRPC_PARSE_ERROR(-503),
404 "Month of year value %u is not in the range 1-12", dt.M);
405 else if (dt.D < 1 || dt.D > 31)
406 xmlrpc_env_set_fault_formatted(
407 envP, XMLRPC_PARSE_ERROR(-503),
408 "Day of month value %u is not in the range 1-31", dt.D);
409 else if (dt.h > 23)
410 xmlrpc_env_set_fault_formatted(
411 envP, XMLRPC_PARSE_ERROR(-503),
412 "Hour of day value %u is not in the range 0-23", dt.h);
413 else if (dt.m > 59)
414 xmlrpc_env_set_fault_formatted(
415 envP, XMLRPC_PARSE_ERROR(-503),
416 "Minute of hour value %u is not in the range 0-59", dt.m);
417 else if (dt.s > 59)
418 xmlrpc_env_set_fault_formatted(
419 envP, XMLRPC_PARSE_ERROR(-503),
420 "Second of minute value %u is not in the range 0-59", dt.s);
421 else if (dt.u > 999999)
422 xmlrpc_env_set_fault_formatted(
423 envP, XMLRPC_PARSE_ERROR(-503),
424 "Microsecond of second value %u is not in the range 0-1M", dt.u);
425}
426
427
428
429void
430xmlrpc_parseDatetime(xmlrpc_env * const envP,
431 const char * const datetimeString,
432 xmlrpc_value ** const valuePP) {
433/*----------------------------------------------------------------------------
434 Parse the content of a <datetime.iso8601> XML-RPC XML element, e.g.
435 "20000301T00:00:00".
436
437 'str' is that content.
438
439 Example of the format we parse: "19980717T14:08:55"
440 Note that this is not quite ISO 8601. It's a bizarre combination of
441 two ISO 8601 formats.
442
443 Note that Xmlrpc-c recognizes various extensions of the XML-RPC
444 <datetime.iso8601> element type.
445
446 'str' may not be valid XML-RPC (with extensions). In that case we fail
447 with fault code XMLRPC_PARSE_ERROR.
448-----------------------------------------------------------------------------*/
449 xmlrpc_datetime dt;
450
451#if HAVE_REGEX1
452 parseDtRegex(envP, datetimeString, &dt);
453#else
454 /* Note: validation is not as strong without regex */
455 validateFormatNoRegex(envP, datetimeString);
456 if (!envP->fault_occurred)
457 parseDtNoRegex(envP, datetimeString, &dt);
458#endif
459
460 if (!envP->fault_occurred) {
1
Taking true branch
461 validateXmlrpcDatetimeSome(envP, dt);
462
463 if (!envP->fault_occurred)
2
Taking true branch
464 *valuePP = xmlrpc_datetime_new(envP, dt);
3
Passed-by-value struct argument contains uninitialized data (e.g., field: 'Y')
465 }
466}