Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 41 additions & 12 deletions src/flb_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -1165,26 +1165,47 @@ int flb_parser_time_lookup(const char *time_str, size_t tsize,
time_t time_now;
char *p = NULL;
char *fmt;
int time_len = tsize;
char *buf;
char *time_buf = NULL;
int time_len;
const char *time_ptr = time_str;
char tmp[64];
size_t buf_size = sizeof(tmp);
struct tm tmy;

*ns = 0;

if (tsize > sizeof(tmp) - 1) {
flb_error("[parser] time string length is too long");
if (tsize > INT_MAX) {
flb_error("[parser] time string length exceeds supported range");
return -1;
}

time_len = (int) tsize;
buf = tmp;

if (tsize > sizeof(tmp) - 1) {
if (tsize > (SIZE_MAX - 8)) {
flb_error("[parser] time string length is too long");
return -1;
}
buf_size = tsize + 8;
time_buf = flb_malloc(buf_size);
if (time_buf == NULL) {
flb_errno();
return -1;
}
buf = time_buf;
}

/*
* Some records coming from old Syslog messages do not contain the
* year, so it's required to ingest this information in the value
* to be parsed.
*/
if (parser->time_with_year == FLB_FALSE) {
/* Given time string is too long */
if (time_len + 6 >= sizeof(tmp)) {
if (time_len + 6 >= buf_size) {
flb_free(time_buf);
return -1;
}

Expand Down Expand Up @@ -1212,7 +1233,7 @@ int flb_parser_time_lookup(const char *time_str, size_t tsize,

uint64_t t = tmy.tm_year + 1900;

fmt = tmp;
fmt = buf;
u64_to_str(t, fmt);
fmt += 4;
*fmt++ = ' ';
Expand All @@ -1221,8 +1242,8 @@ int flb_parser_time_lookup(const char *time_str, size_t tsize,
fmt += time_len;
*fmt++ = '\0';

time_ptr = tmp;
time_len = strlen(tmp);
time_ptr = buf;
time_len = strlen(buf);
p = flb_strptime(time_ptr, parser->time_fmt_year, tm);
}
else {
Expand All @@ -1231,23 +1252,26 @@ int flb_parser_time_lookup(const char *time_str, size_t tsize,
* null-terminated, which time_ptr is not guaranteed
* to be. So we use tmp to hold our string.
*/
if (time_len >= sizeof(tmp)) {
if (time_len >= buf_size) {
flb_free(time_buf);
return -1;
}
memcpy(tmp, time_ptr, time_len);
tmp[time_len] = '\0';
time_ptr = tmp;
time_len = strlen(tmp);
memcpy(buf, time_ptr, time_len);
buf[time_len] = '\0';
time_ptr = buf;
time_len = strlen(buf);

p = flb_strptime(time_ptr, parser->time_fmt, tm);
}

if (p == NULL) {
if (parser->time_strict) {
flb_error("[parser] cannot parse '%.*s'", (int)tsize, time_str);
flb_free(time_buf);
return -1;
}
flb_debug("[parser] non-exact match '%.*s'", (int)tsize, time_str);
flb_free(time_buf);
return 0;
}

Expand All @@ -1256,9 +1280,11 @@ int flb_parser_time_lookup(const char *time_str, size_t tsize,
if (ret < 0) {
if (parser->time_strict) {
flb_error("[parser] cannot parse %%L for '%.*s'", (int)tsize, time_str);
flb_free(time_buf);
return -1;
}
flb_debug("[parser] non-exact match on %%L '%.*s'", (int)tsize, time_str);
flb_free(time_buf);
return 0;
}
p += ret;
Expand All @@ -1268,9 +1294,11 @@ int flb_parser_time_lookup(const char *time_str, size_t tsize,
if (p == NULL) {
if (parser->time_strict) {
flb_error("[parser] cannot parse '%.*s' after %%L", (int)tsize, time_str);
flb_free(time_buf);
return -1;
}
flb_debug("[parser] non-exact match after %%L '%.*s'", (int)tsize, time_str);
flb_free(time_buf);
return 0;
}
}
Expand All @@ -1279,6 +1307,7 @@ int flb_parser_time_lookup(const char *time_str, size_t tsize,
flb_tm_gmtoff(tm) = parser->time_offset;
}

flb_free(time_buf);
return 0;
}

Expand Down
63 changes: 63 additions & 0 deletions tests/internal/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

#include <time.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include "flb_tests_internal.h"

/* Parsers configuration */
Expand Down Expand Up @@ -588,13 +591,73 @@ void test_parser_time_system_timezone_midnight()
flb_config_exit(config);
}

void test_parser_time_lookup_long_fraction()
{
int ret;
double ns;
time_t epoch;
struct flb_tm tm;
struct flb_parser *parser;
struct flb_config *config;
const char *time_string = "10/03/2016 12:21:08.123456789123456789123456789123456789123456789123456789";

config = flb_config_init();
load_json_parsers(config);

parser = flb_parser_get("generic_N", config);
TEST_CHECK(parser != NULL);
if (parser == NULL) {
flb_parser_exit(config);
flb_config_exit(config);
return;
}

ret = flb_parser_time_lookup(time_string, strlen(time_string), 0, parser, &tm, &ns);
TEST_CHECK(ret == 0);

epoch = flb_parser_tm2time(&tm, FLB_FALSE);
TEST_CHECK(epoch == 1475497268);
TEST_CHECK(fabs(ns - 0.123456789) <= DBL_EPSILON);

flb_parser_exit(config);
flb_config_exit(config);
}

void test_parser_time_lookup_reject_oversized_length()
{
int ret;
double ns;
struct flb_tm tm;
struct flb_parser *parser;
struct flb_config *config;

config = flb_config_init();
load_json_parsers(config);

parser = flb_parser_get("generic_N", config);
TEST_CHECK(parser != NULL);
if (parser == NULL) {
flb_parser_exit(config);
flb_config_exit(config);
return;
}

ret = flb_parser_time_lookup("x", (size_t) INT_MAX + 1, 0, parser, &tm, &ns);
TEST_CHECK(ret == -1);

flb_parser_exit(config);
flb_config_exit(config);
}


TEST_LIST = {
{ "tzone_offset", test_parser_tzone_offset},
{ "time_lookup", test_parser_time_lookup},
{ "json_time_lookup", test_json_parser_time_lookup},
{ "regex_time_lookup", test_regex_parser_time_lookup},
{ "time_system_timezone_midnight", test_parser_time_system_timezone_midnight},
{ "time_lookup_long_fraction", test_parser_time_lookup_long_fraction},
{ "time_lookup_reject_oversized_length", test_parser_time_lookup_reject_oversized_length},
{ "mysql_unquoted" , test_mysql_unquoted },
{ 0 }
};
Loading