[ace-bugs] ACE_Time_Value: set(double) hangs when setting large values

Markus Hossner markus.hossner at innovative-navigation.de
Mon Feb 22 10:49:01 CST 2016


    ACE VERSION: 6.3.3

    HOST MACHINE and OPERATING SYSTEM:
Red Hat Enterprise Linux Server release 6.5 (Santiago) 64 Bit

    TARGET MACHINE and OPERATING SYSTEM, if different from HOST:
Red Hat Enterprise Linux Server release 6.5 (Santiago) 64 Bit
gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC)

    THE $ACE_ROOT/ace/config.h FILE
#include "ace/config-linux.h"

    THE $ACE_ROOT/include/makeinclude/platform_macros.GNU FILE
include $(ACE_ROOT)/include/makeinclude/platform_linux.GNU
INSTALL_PREFIX=/usr/local/ACE+TAO-6.3.1
LD_RPATH_FLAGS += -Wl,-rpath,/usr/local/in/lib

    CONTENTS OF $ACE_ROOT/bin/MakeProjectCreator/config/default.features
does not exist

    AREA/CLASS/EXAMPLE AFFECTED:
ACE_Time_Value

    DOES THE PROBLEM AFFECT:
        EXECUTION

    SYNOPSIS:
ACE_Time_Value: set(double) hangs when setting large values (e.g. DBL_MAX) on 64 bit platform

    DESCRIPTION:
Through an error in our code an ACE_Time_Value was set to DBL_MAX which resulted in the program hanging in 
ACE_Time_Value::normalize(). I looked at the code and found out that the cast from double to t_time went wrong
which results in a very large usec value (64 bit). Then normalize() is called and normalize() uses a loop to adjust the
 sec and usec values. For large usec values this needs very long time.

Problematic usec values can also be set directly by the constructor or a set method.

    REPEAT BY:
In a 64 Bit environment, where suseconds_t is defined as 64 Bit value.

  cout << sizeof(suseconds_t) << endl;  // 8
  ACE_Time_Value a(0, LONG_MAX); // hangs

  ACE_Time_Value b;
  b.set(0, LONG_MAX); // hangs

  ACE_Time_Value c;
  c.set(DBL_MAX); //hangs

(For repeating the problem I used extreme values but this also happens for other large numbers)

Best regards

Markus Hossner


    SAMPLE FIX/WORKAROUND:

ACE_Time_Value::set (double d): ace/Time_Value.inl
- Handle big positiv and negativ double values by limiting them to possible values for sec and usec
- Correct round for negativ double values: -10.5 => -10 -500000 (not -10 -499999)
- no normalize needed cause result is already normalized

ACE_INLINE void
ACE_Time_Value::set (double d)
{
  // ACE_OS_TRACE ("ACE_Time_Value::set");
  if (d < ACE_Numeric_Limits<time_t>::min())
    {
      this->tv_.tv_sec = ACE_Numeric_Limits<time_t>::min();
      this->tv_.tv_usec = -ACE_ONE_SECOND_IN_USECS + 1;
    }
  else if (d > ACE_Numeric_Limits<time_t>::max())
    {
      this->tv_.tv_sec = ACE_Numeric_Limits<time_t>::max();
      this->tv_.tv_usec = ACE_ONE_SECOND_IN_USECS - 1;
    }
  else
    {
      time_t l = (time_t) d;
      this->tv_.tv_sec = l;
      this->tv_.tv_usec = (suseconds_t) ((d - (double) l) * ACE_ONE_SECOND_IN_USECS + (d < 0 ? -0.5 : 0.5));
    }
}


ACE_Time_Value::normalize (bool saturate): ace/Time_Value.cpp
- Better performance by not using a loop for adjusting time values

void
ACE_Time_Value::normalize (bool saturate)
{
  // ACE_OS_TRACE ("ACE_Time_Value::normalize");
  if (this->tv_.tv_usec >= ACE_ONE_SECOND_IN_USECS ||
      this->tv_.tv_usec <= -ACE_ONE_SECOND_IN_USECS)
    {
      time_t sec = abs(this->tv_.tv_usec) / ACE_ONE_SECOND_IN_USECS * (this->tv_.tv_usec > 0 ? 1 : -1);
      suseconds_t usec = this->tv_.tv_usec - sec * ACE_ONE_SECOND_IN_USECS;

      if (saturate && this->tv_.tv_sec > 0 && sec > 0 &&
          ACE_Numeric_Limits<time_t>::max() - this->tv_.tv_sec < sec)
        {
          this->tv_.tv_sec = ACE_Numeric_Limits<time_t>::max();
          this->tv_.tv_usec = ACE_ONE_SECOND_IN_USECS - 1;
        }
      else if (saturate && this->tv_.tv_sec < 0 && sec < 0 &&
               ACE_Numeric_Limits<time_t>::min() - this->tv_.tv_sec > sec)
        {
          this->tv_.tv_sec = ACE_Numeric_Limits<time_t>::min();
          this->tv_.tv_usec = -ACE_ONE_SECOND_IN_USECS + 1;
        }
      else
        {
          this->tv_.tv_sec += sec;
          this->tv_.tv_usec = usec;
        }
    }

  if (this->tv_.tv_sec >= 1 && this->tv_.tv_usec < 0)
    {
      --this->tv_.tv_sec;
      this->tv_.tv_usec += ACE_ONE_SECOND_IN_USECS;
    }
  // tv_sec in qnxnto is unsigned
#if !defined ( __QNX__)
  else if (this->tv_.tv_sec < 0 && this->tv_.tv_usec > 0)
    {
      ++this->tv_.tv_sec;
      this->tv_.tv_usec -= ACE_ONE_SECOND_IN_USECS;
    }
#endif /* __QNX__  */
}



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://list.isis.vanderbilt.edu/pipermail/ace-bugs/attachments/20160222/71cc43f3/attachment.html>


More information about the ace-bugs mailing list