# HG changeset patch # User Mario de Sousa # Date 1545825733 0 # Node ID fc23bca885f81e363fbdcbb9b604a4c9c98e0dbb # Parent 903e2782e4059a8383754468111796aeda2e82df# Parent 54445dfc28ec2d9eee2ec3c81b75623e4e5df782 merge diff -r 54445dfc28ec -r fc23bca885f8 stage4/generate_c/generate_c.cc --- a/stage4/generate_c/generate_c.cc Wed Dec 26 11:45:27 2018 +0000 +++ b/stage4/generate_c/generate_c.cc Wed Dec 26 12:02:13 2018 +0000 @@ -544,11 +544,27 @@ /***********************************************************************/ /***********************************************************************/ -#define MILLISECOND 1000000 +#define MILLISECOND ((unsigned long long)1000000) #define SECOND 1000 * MILLISECOND #define ULL_MAX std::numeric_limits::max() +/* unsigned long long -> multiply and add : time_var += interval * multiplier */ +/* note: multiplier must be <> 0 due to overflow test */ +#define ULL_MUL_ADD(time_var, interval, multiplier, overflow_flag) { \ + /* Test overflow on MUL by pre-condition: If (ULL_MAX / a) < b => overflow! */ \ + overflow_flag |= ((ULL_MAX / (multiplier)) < GET_CVALUE(uint64, interval)); \ + /* Test overflow on ADD by pre-condition: If (ULL_MAX - a) < b => overflow! */ \ + overflow_flag |= ((ULL_MAX - (GET_CVALUE(uint64, interval) * multiplier)) < time_var); \ + time_var += GET_CVALUE(uint64, interval) * (multiplier); \ +} + +/* long double -> multiply and add : time_var += interval * multiplier */ +#define LDB_MUL_ADD(time_var, interval, multiplier) { \ + time_var += GET_CVALUE(real64, interval) * (multiplier); \ +} + + unsigned long long calculate_time(symbol_c *symbol) { if (NULL == symbol) return 0; @@ -569,48 +585,54 @@ /* SYM_REF5(interval_c, days, hours, minutes, seconds, milliseconds) */ unsigned long long int time_ull = 0; long double time_ld = 0; + bool ovflow = false; if (NULL != interval->milliseconds) { if (VALID_CVALUE( int64, interval->milliseconds) && GET_CVALUE( int64, interval->milliseconds) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->milliseconds)) time_ull += GET_CVALUE( int64, interval->milliseconds) * MILLISECOND; - else if (VALID_CVALUE(uint64, interval->milliseconds)) time_ull += GET_CVALUE(uint64, interval->milliseconds) * MILLISECOND; - else if (VALID_CVALUE(real64, interval->milliseconds)) time_ld += GET_CVALUE(real64, interval->milliseconds) * MILLISECOND; + if (VALID_CVALUE(uint64, interval->milliseconds)) ULL_MUL_ADD(time_ull, interval->milliseconds, MILLISECOND, ovflow) + else if (VALID_CVALUE(real64, interval->milliseconds)) LDB_MUL_ADD(time_ld , interval->milliseconds, MILLISECOND) else ERROR; // if (NULL != interval->milliseconds) is true, then it must have a valid constant value! } if (NULL != interval->seconds ) { if (VALID_CVALUE( int64, interval->seconds ) && GET_CVALUE( int64, interval->seconds ) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->seconds )) time_ull += GET_CVALUE( int64, interval->seconds ) * SECOND; - else if (VALID_CVALUE(uint64, interval->seconds )) time_ull += GET_CVALUE(uint64, interval->seconds ) * SECOND; - else if (VALID_CVALUE(real64, interval->seconds )) time_ld += GET_CVALUE(real64, interval->seconds ) * SECOND; + if (VALID_CVALUE(uint64, interval->seconds )) ULL_MUL_ADD(time_ull, interval->seconds, SECOND, ovflow) + else if (VALID_CVALUE(real64, interval->seconds )) LDB_MUL_ADD(time_ld , interval->seconds, SECOND) else ERROR; // if (NULL != interval->seconds) is true, then it must have a valid constant value! } if (NULL != interval->minutes ) { if (VALID_CVALUE( int64, interval->minutes ) && GET_CVALUE( int64, interval->minutes ) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->minutes )) time_ull += GET_CVALUE( int64, interval->minutes ) * SECOND * 60; - else if (VALID_CVALUE(uint64, interval->minutes )) time_ull += GET_CVALUE(uint64, interval->minutes ) * SECOND * 60; - else if (VALID_CVALUE(real64, interval->minutes )) time_ld += GET_CVALUE(real64, interval->minutes ) * SECOND * 60; + if (VALID_CVALUE(uint64, interval->minutes )) ULL_MUL_ADD(time_ull, interval->minutes, SECOND * 60, ovflow) + else if (VALID_CVALUE(real64, interval->minutes )) LDB_MUL_ADD(time_ld , interval->minutes, SECOND * 60) else ERROR; // if (NULL != interval->minutes) is true, then it must have a valid constant value! } if (NULL != interval->hours ) { if (VALID_CVALUE( int64, interval->hours ) && GET_CVALUE( int64, interval->hours ) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->hours )) time_ull += GET_CVALUE( int64, interval->hours ) * SECOND * 60 * 60; - else if (VALID_CVALUE(uint64, interval->hours )) time_ull += GET_CVALUE(uint64, interval->hours ) * SECOND * 60 * 60; - else if (VALID_CVALUE(real64, interval->hours )) time_ld += GET_CVALUE(real64, interval->hours ) * SECOND * 60 * 60; + if (VALID_CVALUE(uint64, interval->hours )) ULL_MUL_ADD(time_ull, interval->hours, SECOND * 60 * 60, ovflow) + else if (VALID_CVALUE(real64, interval->hours )) LDB_MUL_ADD(time_ld , interval->hours, SECOND * 60 * 60) else ERROR; // if (NULL != interval->hours) is true, then it must have a valid constant value! } if (NULL != interval->days ) { if (VALID_CVALUE( int64, interval->days ) && GET_CVALUE( int64, interval->days ) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->days )) time_ull += GET_CVALUE( int64, interval->days ) * SECOND * 60 * 60 * 24; - else if (VALID_CVALUE(uint64, interval->days )) time_ull += GET_CVALUE(uint64, interval->days ) * SECOND * 60 * 60 * 24; - else if (VALID_CVALUE(real64, interval->days )) time_ld += GET_CVALUE(real64, interval->days ) * SECOND * 60 * 60 * 24; + if (VALID_CVALUE(uint64, interval->days )) ULL_MUL_ADD(time_ull, interval->days, SECOND * 60 * 60 * 24, ovflow) + else if (VALID_CVALUE(real64, interval->days )) LDB_MUL_ADD(time_ld , interval->days, SECOND * 60 * 60 * 24) else ERROR; // if (NULL != interval->days) is true, then it must have a valid constant value! } + /* Test overflow on ADD by pre-condition: If (ULL_MAX - a) < b => overflow! */ + ovflow |= ((ULL_MAX - time_ull) < (unsigned long long)time_ld); time_ull += time_ld; + + if (ovflow) { + /* time is being stored in ns resolution (MILLISECOND #define is set to 1000000) */ + /* time is being stored in unsigned long long (ISO C99 guarantees at least 64 bits) */ + /* 2⁶64ns works out to around 584.5 years, assuming 365.25 days per year */ + STAGE4_ERROR(symbol, symbol, "Internal overflow calculating task interval (must be < 584 years)."); + } + return time_ull; }; ERROR; // should never reach this point!