Bug Summary

File:src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c
Location:line 522, column 5
Description:Undefined or garbage value returned to caller

Annotated Source Code

1#include "xmlrpc_config.h"
2
3#define _XOPEN_SOURCE700 600 /* Make sure strdup() is in <string.h> */
4
5#include <time.h>
6#include <stdlib.h>
7#include <string.h>
8#include <ctype.h>
9#include <assert.h>
10#include <stdio.h>
11#if MSVCRT0
12#include <windows.h>
13#endif
14
15#include "bool.h"
16#include "mallocvar.h"
17
18#include "xmlrpc-c/c_util.h"
19#include "xmlrpc-c/base.h"
20#include "xmlrpc-c/base_int.h"
21#include "xmlrpc-c/string_int.h"
22#include "xmlrpc-c/time_int.h"
23
24
25#if HAVE_REGEX1
26#include <regex.h>
27#endif
28
29#if MSVCRT0
30
31static const __int64 SECS_BETWEEN_EPOCHS = 11644473600;
32static const __int64 SECS_TO_100NS = 10000000; /* 10^7 */
33
34
35void
36UnixTimeToFileTime(time_t const t,
37 LPFILETIME const pft) {
38
39 int64_t const ll =
40 Int32x32To64(t, SECS_TO_100NS) + SECS_BETWEEN_EPOCHS * SECS_TO_100NS;
41
42 pft->dwLowDateTime = (DWORD)ll;
43 pft->dwHighDateTime = (DWORD)(ll >> 32);
44}
45
46
47
48void
49UnixTimeToSystemTime(time_t const t,
50 LPSYSTEMTIME const pst) {
51 FILETIME ft;
52
53 UnixTimeToFileTime(t, &ft);
54 FileTimeToSystemTime(&ft, pst);
55}
56
57
58
59static void
60UnixTimeFromFileTime(xmlrpc_env * const envP,
61 LPFILETIME const pft,
62 time_t * const timeValueP) {
63
64 int64_t const WinEpoch100Ns =
65 ((int64_t)pft->dwHighDateTime << 32) + pft->dwLowDateTime;
66 int64_t const unixEpoch100Ns =
67 WinEpoch100Ns - (SECS_BETWEEN_EPOCHS * SECS_TO_100NS);
68 int64_t const unixEpochSeconds =
69 unixEpoch100Ns / SECS_TO_100NS;
70
71 if ((time_t)unixEpochSeconds != unixEpochSeconds) {
72 /* Value is too big for a time_t; fail. */
73 xmlrpc_faultf(envP, "Does not indicate a valid date");
74 *timeValueP = (time_t)(-1);
75 } else
76 *timeValueP = (time_t)unixEpochSeconds;
77}
78
79
80
81static void
82UnixTimeFromSystemTime(xmlrpc_env * const envP,
83 LPSYSTEMTIME const pst,
84 time_t * const timeValueP) {
85 FILETIME filetime;
86
87 SystemTimeToFileTime(pst, &filetime);
88 UnixTimeFromFileTime(envP, &filetime, timeValueP);
89}
90
91#endif /* MSVCRT */
92
93
94
95static void
96validateDatetimeType(xmlrpc_env * const envP,
97 const xmlrpc_value * const valueP) {
98
99 if (valueP->_type != XMLRPC_TYPE_DATETIME) {
100 xmlrpc_env_set_fault_formatted(
101 envP, XMLRPC_TYPE_ERROR(-501), "Value of type %s supplied where "
102 "type %s was expected.",
103 xmlrpc_type_name(valueP->_type),
104 xmlrpc_type_name(XMLRPC_TYPE_DATETIME));
105 }
106}
107
108
109
110void
111xmlrpc_read_datetime(xmlrpc_env * const envP,
112 const xmlrpc_value * const valueP,
113 xmlrpc_datetime * const dtP) {
114
115 validateDatetimeType(envP, valueP);
116 if (!envP->fault_occurred) {
117 *dtP = valueP->_value.dt;
118 }
119}
120
121
122
123void
124xmlrpc_read_datetime_str(xmlrpc_env * const envP,
125 const xmlrpc_value * const valueP,
126 const char ** const stringValueP) {
127/*----------------------------------------------------------------------------
128 This exists for backward compatibility. No normal modern program would
129 want to see a datetime value in this format. Note that the format isn't
130 even ISO 8601 -- it's a bizarre hybrid of two ISO 8601 formats.
131
132 Do not extend this.
133
134 This exists because Xmlrpc-c was at one time lazy and this was the only way
135 to extract the value. An xmlrpc_value in those days represented a datetime
136 with the actual XML-RPC wire format of a datetime, and this function simply
137 returned a copy of it.
138-----------------------------------------------------------------------------*/
139 validateDatetimeType(envP, valueP);
140 if (!envP->fault_occurred) {
141 time_t secs;
142 unsigned int usecs;
143
144 xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs);
145
146 if (!envP->fault_occurred) {
147 struct tm brokenTime;
148 char dtString[64];
149
150 xmlrpc_gmtime(secs, &brokenTime);
151
152 /* Note that this format is NOT ISO 8601 -- it's a bizarre
153 hybrid of two ISO 8601 formats.
154 */
155 strftime(dtString, sizeof(dtString), "%Y%m%dT%H:%M:%S",
156 &brokenTime);
157
158 if (usecs != 0) {
159 char usecString[64];
160 assert(usecs < 1000000)((usecs < 1000000) ? (void) (0) : __assert_fail ("usecs < 1000000"
, "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 160, __PRETTY_FUNCTION__
))
;
161 snprintf(usecString, sizeof(usecString), ".%06u", usecs);
162 STRSCAT(dtString, usecString)(__builtin_strncat ((dtString), (usecString), sizeof(dtString
)-strlen(dtString)), *((dtString)+sizeof(dtString)-1) = '\0')
;
163 }
164
165 *stringValueP = strdup(dtString)(__extension__ (__builtin_constant_p (dtString) && ((
size_t)(const void *)((dtString) + 1) - (size_t)(const void *
)(dtString) == 1) ? (((const char *) (dtString))[0] == '\0' ?
(char *) calloc ((size_t) 1, (size_t) 1) : ({ size_t __len =
strlen (dtString) + 1; char *__retval = (char *) malloc (__len
); if (__retval != ((void*)0)) __retval = (char *) memcpy (__retval
, dtString, __len); __retval; })) : __strdup (dtString)))
;
166 if (*stringValueP == NULL((void*)0))
167 xmlrpc_faultf(envP,
168 "Unable to allocate memory for datetime string");
169 }
170 }
171}
172
173
174
175void
176xmlrpc_read_datetime_str_old(xmlrpc_env * const envP,
177 const xmlrpc_value * const valueP,
178 const char ** const stringValueP) {
179
180 assert(valueP->_cache)((valueP->_cache) ? (void) (0) : __assert_fail ("valueP->_cache"
, "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 180, __PRETTY_FUNCTION__
))
;
181
182 validateDatetimeType(envP, valueP);
183 if (!envP->fault_occurred) {
184 const char ** const readBufferP = valueP->_cache;
185
186 if (!*readBufferP)
187 /* Nobody's asked for the internal buffer before. Set it up. */
188 xmlrpc_read_datetime_str(envP, valueP, readBufferP);
189
190 *stringValueP = *readBufferP;
191 }
192}
193
194
195
196void
197xmlrpc_read_datetime_usec(xmlrpc_env * const envP,
198 const xmlrpc_value * const valueP,
199 time_t * const secsP,
200 unsigned int * const usecsP) {
201
202 validateDatetimeType(envP, valueP);
203
204 if (!envP->fault_occurred) {
205 if (valueP->_value.dt.Y < 1970)
206 xmlrpc_faultf(envP, "Year (%u) is too early to represent as "
207 "a standard Unix time",
208 valueP->_value.dt.Y);
209 else {
210 struct tm brokenTime;
211 const char * error;
212
213 brokenTime.tm_sec = valueP->_value.dt.s;
214 brokenTime.tm_min = valueP->_value.dt.m;
215 brokenTime.tm_hour = valueP->_value.dt.h;
216 brokenTime.tm_mday = valueP->_value.dt.D;
217 brokenTime.tm_mon = valueP->_value.dt.M - 1;
218 brokenTime.tm_year = valueP->_value.dt.Y - 1900;
219
220 xmlrpc_timegm(&brokenTime, secsP, &error);
221
222 if (error) {
223 /* Ideally, this wouldn't be possible - it wouldn't be
224 possible to create an xmlrpc_value that doesn't actually
225 represent a real datetime. But today, we're lazy and
226 don't fully validate incoming XML-RPC <dateTime.iso8601>
227 elements, and we also have the legacy
228 xmlrpc_datetime_new_str() constructor to which the user
229 may feed garbage.
230
231 We should tighten that up and then simply assert here that
232 xmlrpc_timegm() succeeded.
233 */
234 xmlrpc_env_set_fault_formatted(envP, XMLRPC_PARSE_ERROR(-503),
235 "A datetime received in an XML-RPC message "
236 "or generated with legacy Xmlrpc-c facilities "
237 "does not validly describe a datetime. %s",
238 error);
239 xmlrpc_strfree(error);
240 } else
241 *usecsP = valueP->_value.dt.u;
242 }
243 }
244}
245
246
247
248void
249xmlrpc_read_datetime_sec(xmlrpc_env * const envP,
250 const xmlrpc_value * const valueP,
251 time_t * const timeValueP) {
252
253 unsigned int usecs;
254
255 xmlrpc_read_datetime_usec(envP, valueP, timeValueP, &usecs);
256}
257
258
259
260#if XMLRPC_HAVE_TIMEVAL1
261
262void
263xmlrpc_read_datetime_timeval(xmlrpc_env * const envP,
264 const xmlrpc_value * const valueP,
265 struct timeval * const timeValueP) {
266
267 time_t secs;
268 unsigned int usecs;
269
270 xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs);
271
272 timeValueP->tv_sec = secs;
273 timeValueP->tv_usec = usecs;
274}
275#endif
276
277
278
279#if XMLRPC_HAVE_TIMESPEC1
280
281void
282xmlrpc_read_datetime_timespec(xmlrpc_env * const envP,
283 const xmlrpc_value * const valueP,
284 struct timespec * const timeValueP) {
285
286 time_t secs;
287 unsigned int usecs;
288
289 xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs);
290
291 timeValueP->tv_sec = secs;
292 timeValueP->tv_nsec = usecs * 1000;
293}
294#endif
295
296
297
298xmlrpc_value *
299xmlrpc_datetime_new(xmlrpc_env * const envP,
300 xmlrpc_datetime const dt) {
301
302 xmlrpc_value * valP;
303
304 const char ** readBufferP;
305
306 MALLOCVAR(readBufferP)readBufferP = malloc(sizeof(*readBufferP));
307
308 if (!readBufferP)
309 xmlrpc_faultf(envP, "Couldn't get memory for the cache part of the "
310 "XML-RPC datetime value object");
311
312 else {
313 *readBufferP = NULL((void*)0);
314
315 xmlrpc_createXmlrpcValue(envP, &valP);
316
317 if (!envP->fault_occurred) {
318 valP->_type = XMLRPC_TYPE_DATETIME;
319
320 valP->_value.dt = dt;
321
322 valP->_cache = readBufferP;
323 }
324 if (envP->fault_occurred)
325 free(readBufferP);
326 }
327 return valP;
328}
329
330
331
332static void
333parseDatetimeString(const char * const datetimeString,
334 xmlrpc_datetime * const dtP) {
335
336 size_t const dtStrlen = strlen(datetimeString);
337
338 char year[4+1];
339 char month[2+1];
340 char day[2+1];
341 char hour[2+1];
342 char minute[2+1];
343 char second[2+1];
344
345 /* Because we require input to be valid: */
346 assert(dtStrlen >= 17 && dtStrlen != 18 && dtStrlen <= 24)((dtStrlen >= 17 && dtStrlen != 18 && dtStrlen
<= 24) ? (void) (0) : __assert_fail ("dtStrlen >= 17 && dtStrlen != 18 && dtStrlen <= 24"
, "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 346, __PRETTY_FUNCTION__
))
;
347
348 year[0] = datetimeString[ 0];
349 year[1] = datetimeString[ 1];
350 year[2] = datetimeString[ 2];
351 year[3] = datetimeString[ 3];
352 year[4] = '\0';
353
354 month[0] = datetimeString[ 4];
355 month[1] = datetimeString[ 5];
356 month[2] = '\0';
357
358 day[0] = datetimeString[ 6];
359 day[1] = datetimeString[ 7];
360 day[2] = '\0';
361
362 assert(datetimeString[ 8] == 'T')((datetimeString[ 8] == 'T') ? (void) (0) : __assert_fail ("datetimeString[ 8] == 'T'"
, "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 362, __PRETTY_FUNCTION__
))
;
363
364 hour[0] = datetimeString[ 9];
365 hour[1] = datetimeString[10];
366 hour[2] = '\0';
367
368 assert(datetimeString[11] == ':')((datetimeString[11] == ':') ? (void) (0) : __assert_fail ("datetimeString[11] == ':'"
, "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 368, __PRETTY_FUNCTION__
))
;
369
370 minute[0] = datetimeString[12];
371 minute[1] = datetimeString[13];
372 minute[2] = '\0';
373
374 assert(datetimeString[14] == ':')((datetimeString[14] == ':') ? (void) (0) : __assert_fail ("datetimeString[14] == ':'"
, "../../../../libs/xmlrpc-c/src/xmlrpc_datetime.c", 374, __PRETTY_FUNCTION__
))
;
375
376 second[0] = datetimeString[15];
377 second[1] = datetimeString[16];
378 second[2] = '\0';
379
380 if (dtStrlen > 17) {
381 size_t const pad = 24 - dtStrlen;
382 size_t i;
383
384 dtP->u = atoi(&datetimeString[18]);
385 for (i = 0; i < pad; ++i)
386 dtP->u *= 10;
387 } else
388 dtP->u = 0;
389
390 dtP->Y = atoi(year);
391 dtP->M = atoi(month);
392 dtP->D = atoi(day);
393 dtP->h = atoi(hour);
394 dtP->m = atoi(minute);
395 dtP->s = atoi(second);
396}
397
398
399
400static void
401validateFirst17(xmlrpc_env * const envP,
402 const char * const dt) {
403/*----------------------------------------------------------------------------
404 Assuming 'dt' is at least 17 characters long, validate that the first
405 17 characters are a valid XML-RPC datetime, e.g.
406 "20080628T16:35:02"
407-----------------------------------------------------------------------------*/
408 unsigned int i;
409
410 for (i = 0; i < 8 && !envP->fault_occurred; ++i)
411 if (!isdigit(dt[i])((*__ctype_b_loc ())[(int) ((dt[i]))] & (unsigned short int
) _ISdigit)
)
412 xmlrpc_faultf(envP, "Not a digit: '%c'", dt[i]);
413
414 if (dt[8] != 'T')
415 xmlrpc_faultf(envP, "9th character is '%c', not 'T'", dt[8]);
416 if (!isdigit(dt[9])((*__ctype_b_loc ())[(int) ((dt[9]))] & (unsigned short int
) _ISdigit)
)
417 xmlrpc_faultf(envP, "Not a digit: '%c'", dt[9]);
418 if (!isdigit(dt[10])((*__ctype_b_loc ())[(int) ((dt[10]))] & (unsigned short int
) _ISdigit)
)
419 xmlrpc_faultf(envP, "Not a digit: '%c'", dt[10]);
420 if (dt[11] != ':')
421 xmlrpc_faultf(envP, "Not a colon: '%c'", dt[11]);
422 if (!isdigit(dt[12])((*__ctype_b_loc ())[(int) ((dt[12]))] & (unsigned short int
) _ISdigit)
)
423 xmlrpc_faultf(envP, "Not a digit: '%c'", dt[12]);
424 if (!isdigit(dt[13])((*__ctype_b_loc ())[(int) ((dt[13]))] & (unsigned short int
) _ISdigit)
)
425 xmlrpc_faultf(envP, "Not a digit: '%c'", dt[13]);
426 if (dt[14] != ':')
427 xmlrpc_faultf(envP, "Not a colon: '%c'", dt[14]);
428 if (!isdigit(dt[15])((*__ctype_b_loc ())[(int) ((dt[15]))] & (unsigned short int
) _ISdigit)
)
429 xmlrpc_faultf(envP, "Not a digit: '%c'", dt[15]);
430 if (!isdigit(dt[16])((*__ctype_b_loc ())[(int) ((dt[16]))] & (unsigned short int
) _ISdigit)
)
431 xmlrpc_faultf(envP, "Not a digit: '%c'", dt[16]);
432}
433
434
435
436static void
437validateFractionalSeconds(xmlrpc_env * const envP,
438 const char * const dt) {
439/*----------------------------------------------------------------------------
440 Validate the fractional seconds part of the XML-RPC datetime string
441 'dt', if any. That's the decimal point and everything following
442 it.
443-----------------------------------------------------------------------------*/
444 if (strlen(dt) > 17) {
445 if (dt[17] != '.') {
446 xmlrpc_faultf(envP, "'%c' where only a period is valid", dt[17]);
447 } else {
448 if (dt[18] == '\0')
449 xmlrpc_faultf(envP, "Nothing after decimal point");
450 else {
451 unsigned int i;
452 for (i = 18; dt[i] != '\0' && !envP->fault_occurred; ++i) {
453 if (!isdigit(dt[i])((*__ctype_b_loc ())[(int) ((dt[i]))] & (unsigned short int
) _ISdigit)
)
454 xmlrpc_faultf(envP,
455 "Non-digit in fractional seconds: '%c'",
456 dt[i]);
457 }
458 }
459 }
460 }
461}
462
463
464
465static void
466validateFormat(xmlrpc_env * const envP,
467 const char * const dt) {
468
469 if (strlen(dt) < 17)
470 xmlrpc_faultf(envP,
471 "Invalid length of %u of datetime string. "
472 "Must be at least 17 characters",
473 (unsigned)strlen(dt));
474 else {
475 validateFirst17(envP, dt);
476
477 if (!envP->fault_occurred)
478 validateFractionalSeconds(envP, dt);
479 }
480}
481
482
483
484/* Microsoft Visual C in debug mode produces code that complains about
485 returning an undefined value from xmlrpc_datetime_new_str(). It's a bogus
486 complaint, because this function is defined to return nothing meaningful
487 those cases. So we disable the check.
488*/
489#pragma runtime_checks("u", off)
490
491
492
493xmlrpc_value *
494xmlrpc_datetime_new_str(xmlrpc_env * const envP,
495 const char * const datetimeString) {
496/*----------------------------------------------------------------------------
497 This exists only for backward compatibility. Originally, this was the
498 only way to create a datetime XML-RPC value, because we had a really
499 lazy implementation of XML-RPC serialization and parsing (basically, the
500 user did it!).
501
502 Do not extend this. The user should use more normal C representations
503 of datetimes.
504-----------------------------------------------------------------------------*/
505 xmlrpc_value * retval;
1
'retval' declared without an initial value
506
507 validateFormat(envP, datetimeString);
508 if (!envP->fault_occurred) {
2
Taking false branch
509 xmlrpc_datetime dt;
510
511 parseDatetimeString(datetimeString, &dt);
512
513 /* Note that parseDatetimeString() can generate an invalid datetime
514 value, e.g. Hour 25 or February 30. Ideally, we would catch that
515 here, but due to laziness, we simply accept the possibility of
516 invalid xmlrpc_datetime in xmlrpc_value and whoever uses the the
517 xmlrpc_value has to deal with it.
518 */
519 retval = xmlrpc_datetime_new(envP, dt);
520 }
521
522 return retval;
3
Undefined or garbage value returned to caller
523}
524
525
526
527#pragma runtime_checks("u", restore)
528
529
530
531xmlrpc_value *
532xmlrpc_datetime_new_usec(xmlrpc_env * const envP,
533 time_t const secs,
534 unsigned int const usecs) {
535
536 xmlrpc_value * valueP;
537
538 if (usecs >= 1000000)
539 xmlrpc_faultf(envP, "Number of fractional microseconds must be less "
540 "than one million. You specified %u", usecs);
541 else {
542 struct tm brokenTime;
543 xmlrpc_datetime dt;
544
545 xmlrpc_gmtime(secs, &brokenTime);
546
547 dt.s = brokenTime.tm_sec;
548 dt.m = brokenTime.tm_min;
549 dt.h = brokenTime.tm_hour;
550 dt.D = brokenTime.tm_mday;
551 dt.M = brokenTime.tm_mon + 1;
552 dt.Y = 1900 + brokenTime.tm_year;
553 dt.u = usecs;
554
555 valueP = xmlrpc_datetime_new(envP, dt);
556 }
557 return valueP;
558}
559
560
561
562xmlrpc_value *
563xmlrpc_datetime_new_sec(xmlrpc_env * const envP,
564 time_t const value) {
565
566 return xmlrpc_datetime_new_usec(envP, value, 0);
567}
568
569
570
571#if XMLRPC_HAVE_TIMEVAL1
572
573xmlrpc_value *
574xmlrpc_datetime_new_timeval(xmlrpc_env * const envP,
575 struct timeval const value) {
576
577 return xmlrpc_datetime_new_usec(envP, value.tv_sec, value.tv_usec);
578}
579#endif
580
581
582
583#if XMLRPC_HAVE_TIMESPEC1
584
585xmlrpc_value *
586xmlrpc_datetime_new_timespec(xmlrpc_env * const envP,
587 struct timespec const value) {
588
589 return xmlrpc_datetime_new_usec(envP, value.tv_sec, value.tv_nsec/1000);
590}
591#endif
592
593
594
595void
596xmlrpc_destroyDatetime(xmlrpc_value * const datetimeP) {
597
598 const char ** const readBufferP = datetimeP->_cache;
599
600 if (*readBufferP)
601 xmlrpc_strfree(*readBufferP);
602
603 free(datetimeP->_cache);
604}