[Cron] Fix memory leak

This commit is contained in:
Gijs Noorlander
2020-02-27 19:19:25 +01:00
parent 9ef8fc89e4
commit bec65282de
5 changed files with 91 additions and 70 deletions
+39 -11
View File
@@ -31,6 +31,30 @@
#include "ccronexpr.h"
#define CRON_MAX_SECONDS 60
#define CRON_MAX_MINUTES 60
#define CRON_MAX_HOURS 24
#define CRON_MAX_DAYS_OF_WEEK 8
#define CRON_MAX_DAYS_OF_MONTH 32
#define CRON_MAX_MONTHS 12
#define CRON_MAX_YEARS_DIFF 4
#define CRON_CF_SECOND 0
#define CRON_CF_MINUTE 1
#define CRON_CF_HOUR_OF_DAY 2
#define CRON_CF_DAY_OF_WEEK 3
#define CRON_CF_DAY_OF_MONTH 4
#define CRON_CF_MONTH 5
#define CRON_CF_YEAR 6
#define CRON_CF_ARR_LEN 7
static const char* const DAYS_ARR[] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
#define CRON_DAYS_ARR_LEN 7
static const char* const MONTHS_ARR[] = { "FOO", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
#define CRON_MONTHS_ARR_LEN 13
#define CRON_MAX_STR_LEN_TO_SPLIT 256
#define CRON_MAX_NUM_TO_SRING 1000000000
/* computes number of digits in decimal number */
@@ -60,7 +84,7 @@ void cron_free(void* p);
/* forward declarations for platforms that may need them */
/* can be hidden in time.h */
#if !defined(_WIN32) && !defined(__AVR__) && !(defined(ESP8266) || defined(ESP32)) && !defined(ANDROID)
#if !defined(_WIN32) && !defined(__AVR__) && !defined(ESP8266) && !defined(ESP_PLATFORM) && !defined(ANDROID)
struct tm *gmtime_r(const time_t *timep, struct tm *result);
time_t timegm(struct tm* __tp);
struct tm *localtime_r(const time_t *timep, struct tm *result);
@@ -78,15 +102,16 @@ time_t cron_mktime_gm(struct tm* tm) {
#elif defined(__AVR__)
/* https://www.nongnu.org/avr-libc/user-manual/group__avr__time.html */
return mk_gmtime(tm);
#elif (defined(ESP8266) || defined(ESP32))
#elif defined(ESP8266) || defined(ESP_PLATFORM)
/* https://linux.die.net/man/3/timegm */
/* http://www.catb.org/esr/time-programming/ */
/* portable version of timegm() */
time_t ret;
char *tz;
tz = getenv("TZ");
if (tz)
tz = strdup(tz);
time_t ret = -1;
char *tz_orig = NULL;
char *tz = NULL;
tz_orig = getenv("TZ");
if (tz_orig)
tz = strdup(tz_orig);
setenv("TZ", "UTC+0", 1);
tzset();
ret = mktime(tm);
@@ -257,6 +282,7 @@ static int add_to_field(struct tm* calendar, int field, int val) {
calendar->tm_hour = calendar->tm_hour + val;
break;
case CRON_CF_DAY_OF_WEEK: /* mkgmtime ignores this field */
break;
case CRON_CF_DAY_OF_MONTH:
calendar->tm_mday = calendar->tm_mday + val;
break;
@@ -496,12 +522,12 @@ static int do_next(cron_expr* expr, struct tm* calendar, unsigned int dot) {
if (!resets || !empty_list) {
res = -1;
}
if (resets) {
cron_free(resets);
}
if (empty_list) {
cron_free(empty_list);
}
if (resets) {
cron_free(resets);
}
return res;
}
@@ -624,6 +650,7 @@ static char** split_str(const char* str, char del, size_t* len_out) {
int c = str[i];
if (del == str[i]) {
if (bi > 0) {
if (ri >= len) goto return_error;
tmp = strdupl(buf, bi);
if (!tmp) goto return_error;
res[ri++] = tmp;
@@ -636,6 +663,7 @@ static char** split_str(const char* str, char del, size_t* len_out) {
}
/* tail */
if (bi > 0) {
if (ri >= len) goto return_error;
tmp = strdupl(buf, bi);
if (!tmp) goto return_error;
res[ri++] = tmp;
@@ -645,10 +673,10 @@ static char** split_str(const char* str, char del, size_t* len_out) {
return res;
return_error:
free_splitted(res, len);
if (buf) {
cron_free(buf);
}
free_splitted(res, len);
*len_out = 0;
return NULL;
}
+6 -24
View File
@@ -36,6 +36,12 @@ extern "C" {
#include <stdint.h> /*added for use if uint*_t data types*/
#define CRON_INVALID_INSTANT ((time_t) -1)
// Define to use local time
#define CRON_USE_LOCAL_TIME
/**
* Parsed cron expression
*/
@@ -90,30 +96,6 @@ time_t cron_prev(cron_expr* expr, time_t date);
} /* extern "C"*/
#endif
#define CRON_MAX_SECONDS 60
#define CRON_MAX_MINUTES 60
#define CRON_MAX_HOURS 24
#define CRON_MAX_DAYS_OF_WEEK 8
#define CRON_MAX_DAYS_OF_MONTH 32
#define CRON_MAX_MONTHS 12
#define CRON_MAX_YEARS_DIFF 4
#define CRON_CF_SECOND 0
#define CRON_CF_MINUTE 1
#define CRON_CF_HOUR_OF_DAY 2
#define CRON_CF_DAY_OF_WEEK 3
#define CRON_CF_DAY_OF_MONTH 4
#define CRON_CF_MONTH 5
#define CRON_CF_YEAR 6
#define CRON_CF_ARR_LEN 7
#define CRON_INVALID_INSTANT ((time_t) -1)
static const char* const DAYS_ARR[] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
#define CRON_DAYS_ARR_LEN 7
static const char* const MONTHS_ARR[] = { "FOO", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
#define CRON_MONTHS_ARR_LEN 13
#endif /* CCRONEXPR_H */
+1 -1
View File
@@ -29,7 +29,7 @@ extends = common
board_build.f_cpu = 80000000L
build_flags = ${debug_flags.build_flags} ${mqtt_flags.build_flags} -DHTTPCLIENT_1_1_COMPATIBLE=0
build_unflags = -DDEBUG_ESP_PORT
lib_deps = https://github.com/TD-er/ESPEasySerial.git
lib_deps = https://github.com/TD-er/ESPEasySerial.git#v1.0.14
lib_ignore = ESP32_ping, ESP32WebServer, IRremoteESP8266, HeatpumpIR, SD(esp8266), SDFS
board = esp12e
+1
View File
@@ -32,6 +32,7 @@ else:
"USES_P052", # SenseAir
"USES_P056", # SDS011-Dust
"USES_P059", # Encoder
"USES_P081", # Cron
"USES_P082", # GPS
"USES_P085", # AcuDC24x
"USES_P087", # Serial Proxy
+44 -34
View File
@@ -1,9 +1,7 @@
// #######################################################################################################
// #################################### Plugin 081: CRON tasks Scheduler ###########################
// #######################################################################################################
// FIXME TD-er: There is some kind of memory leak in this cron plugin.
#ifdef USES_P081
@@ -12,7 +10,7 @@
extern "C"
{
#include "ccronexpr.h"
#include "ccronexpr.h"
}
@@ -30,7 +28,7 @@ extern "C"
struct P081_data_struct : public PluginTaskData_base {
P081_data_struct(const String& expression)
explicit P081_data_struct(const String& expression)
{
const char *error;
@@ -97,21 +95,23 @@ time_t P081_computeNextCronTime(taskIndex_t taskIndex, time_t last)
static_cast<P081_data_struct *>(getPluginTaskData(taskIndex));
if ((nullptr != P081_data) && P081_data->isInitialized()) {
int32_t freeHeapStart = ESP.getFreeHeap();
// int32_t freeHeapStart = ESP.getFreeHeap();
time_t res = P081_data->get_cron_next(last);
int32_t freeHeapEnd = ESP.getFreeHeap();
/*
int32_t freeHeapEnd = ESP.getFreeHeap();
if (freeHeapEnd < freeHeapStart) {
String log = F("Cron: Free Heap Decreased: ");
log += String(freeHeapStart - freeHeapEnd);
log += F(" (");
log += freeHeapStart;
log += F(" -> ");
log += freeHeapEnd;
addLog(LOG_LEVEL_INFO, log);
}
if (freeHeapEnd < freeHeapStart) {
String log = F("Cron: Free Heap Decreased: ");
log += String(freeHeapStart - freeHeapEnd);
log += F(" (");
log += freeHeapStart;
log += F(" -> ");
log += freeHeapEnd;
addLog(LOG_LEVEL_INFO, log);
}
*/
return res;
}
return CRON_INVALID_INSTANT;
@@ -144,6 +144,28 @@ time_t P081_getCurrentTime()
return mktime((struct tm *)&current);
}
void P081_check_or_init(struct EventStruct *event)
{
if (systemTimePresent()) {
const time_t current_time = P081_getCurrentTime();
time_t last_exec_time = P081_getCronExecTime(LASTEXECUTION);
time_t next_exec_time = P081_getCronExecTime(NEXTEXECUTION);
// Must check if the values of LASTEXECUTION and NEXTEXECUTION make sense.
// These can be invalid values from a reboot, or simply contain uninitialized values.
if ((last_exec_time > current_time) || (last_exec_time == CRON_INVALID_INSTANT) || (next_exec_time == CRON_INVALID_INSTANT)) {
// Last execution time cannot be correct.
last_exec_time = CRON_INVALID_INSTANT;
const time_t tmp_next = P081_computeNextCronTime(event->TaskIndex, current_time);
if ((tmp_next < next_exec_time) || (next_exec_time == CRON_INVALID_INSTANT)) {
next_exec_time = tmp_next;
}
P081_setCronExecTimes(event, CRON_INVALID_INSTANT, next_exec_time);
}
}
}
boolean Plugin_081(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
@@ -251,6 +273,7 @@ boolean Plugin_081(byte function, struct EventStruct *event, String& string)
}
if (P081_data->isInitialized()) {
P081_check_or_init(event);
success = true;
} else {
clearPluginTaskData(event->TaskIndex);
@@ -277,31 +300,18 @@ boolean Plugin_081(byte function, struct EventStruct *event, String& string)
{
// code to be executed once a second. Tasks which do not require fast response can be added here
if (systemTimePresent()) {
const time_t current_time = P081_getCurrentTime();
time_t last_exec_time = P081_getCronExecTime(LASTEXECUTION);
time_t next_exec_time = P081_getCronExecTime(NEXTEXECUTION);
// Must check if the values of LASTEXECUTION and NEXTEXECUTION make sense.
// These can be invalid values from a reboot, or simply contain uninitialized values.
if ((last_exec_time > current_time) || (last_exec_time == CRON_INVALID_INSTANT) || (next_exec_time == CRON_INVALID_INSTANT)) {
// Last execution time cannot be correct.
last_exec_time = CRON_INVALID_INSTANT;
const time_t tmp_next = P081_computeNextCronTime(event->TaskIndex, current_time);
if ((tmp_next < next_exec_time) || (next_exec_time == CRON_INVALID_INSTANT)) {
next_exec_time = tmp_next;
}
P081_setCronExecTimes(event, CRON_INVALID_INSTANT, next_exec_time);
}
P081_check_or_init(event);
time_t next_exec_time = P081_getCronExecTime(NEXTEXECUTION);
if (next_exec_time != CRON_INVALID_INSTANT) {
const bool cron_elapsed = (next_exec_time <= current_time);
const time_t current_time = P081_getCurrentTime();
const bool cron_elapsed = (next_exec_time <= current_time);
if (cron_elapsed) {
addLog(LOG_LEVEL_DEBUG, F("Cron Elapsed"));
last_exec_time = next_exec_time;
next_exec_time = P081_computeNextCronTime(event->TaskIndex, last_exec_time);
time_t last_exec_time = next_exec_time;
next_exec_time = P081_computeNextCronTime(event->TaskIndex, current_time);
P081_setCronExecTimes(event, last_exec_time, next_exec_time);
addLog(LOG_LEVEL_DEBUG, String(F("Next execution:")) + getDateTimeString(*gmtime(&next_exec_time)));