From 385c5936bd4bfab93068880d09e479a13c6ca6bd Mon Sep 17 00:00:00 2001 From: g0dil <g0dil@wiback.org> Date: Tue, 13 Nov 2007 14:58:50 +0000 Subject: [PATCH] Socket/Protocols/Inet: Fix off-by-one error in INet6Address PPI: Fix cloneSource unit-test packet construction Scheduler: BUGFIX: uninitialized loop variable Scheduler: BUGFIX: delay deletions in fdTable_ (can't change map while iterating over it) Add global 'valgrind' target Add 'valgrind.sup' suppressions file to suppress custom benign valgrind errors Fix all unit-tests to run correcly under valgrind (mostly timing adjustments) --- PPI/CloneSource.test.cc | 2 +- PPI/IntervalTimer.test.cc | 2 +- SConstruct | 8 +- Scheduler/ClockService.test.cc | 7 +- Scheduler/Scheduler.cc | 33 +++--- Scheduler/Scheduler.hh | 2 + Scheduler/Scheduler.test.cc | 16 +-- Socket/FileHandle.test.cc | 1 + Socket/Protocols/INet/INet6Address.cc | 2 +- Socket/Protocols/INet/TCPSocketHandle.test.cc | 1 + valgrind.sup | 103 ++++++++++++++++++ 11 files changed, 146 insertions(+), 31 deletions(-) create mode 100644 valgrind.sup diff --git a/PPI/CloneSource.test.cc b/PPI/CloneSource.test.cc index 1b47375de..14aeab5bf 100644 --- a/PPI/CloneSource.test.cc +++ b/PPI/CloneSource.test.cc @@ -40,7 +40,7 @@ BOOST_AUTO_UNIT_TEST(cloneSource) { - char data[] = { 0xAB }; + senf::PacketData::byte data[] = { 0xAB }; senf::Packet p (senf::DataPacket::create(data)); senf::ppi::module::CloneSource source (p); diff --git a/PPI/IntervalTimer.test.cc b/PPI/IntervalTimer.test.cc index f2e92e6a9..9aca3db54 100644 --- a/PPI/IntervalTimer.test.cc +++ b/PPI/IntervalTimer.test.cc @@ -65,7 +65,7 @@ namespace { }; bool is_close_clock(senf::ClockService::clock_type a, senf::ClockService::clock_type b, - unsigned long delta = 50000000ul) + unsigned long delta = senf::ClockService::milliseconds(100)) { return (a<b ? b-a : a-b ) < delta; } diff --git a/SConstruct b/SConstruct index 478cfdf97..b501151c8 100644 --- a/SConstruct +++ b/SConstruct @@ -8,8 +8,8 @@ import SENFSCons # This hack is needed for SCons V 0.96.1 compatibility. In current SCons versions # we can just use 'env.AlwaysBuild(env.Alias(target), [], action)' -def PhonyTarget(env, target, action): - env.AlwaysBuild(env.Command(target + '.phony', 'SConstruct', env.Action(action))) +def PhonyTarget(env, target, action, sources=[]): + env.AlwaysBuild(env.Command(target + '.phony', [ 'SConstruct' ] + sources, env.Action(action))) env.Alias(target, target + '.phony') def updateRevision(target, source, env): @@ -239,6 +239,10 @@ PhonyTarget(env, 'fixlinks', [ PhonyTarget(env, 'prepare', []) +PhonyTarget(env, 'valgrind', [ + 'find -name .test.bin | while read test; do echo; echo "Running $$test"; echo; valgrind --tool=memcheck --error-exitcode=99 --suppressions=valgrind.sup $$test $BOOSTTESTARGS; [ $$? -ne 99 ] || exit 1; done' + ], [ 'all_tests' ]) + env.Clean('all', env.Dir('linklint')) env.Clean('all','.prepare-stamp') diff --git a/Scheduler/ClockService.test.cc b/Scheduler/ClockService.test.cc index 1231e5d8f..2484d74a7 100644 --- a/Scheduler/ClockService.test.cc +++ b/Scheduler/ClockService.test.cc @@ -52,13 +52,13 @@ namespace detail { namespace { bool is_close_clock(senf::ClockService::clock_type a, senf::ClockService::clock_type b, - unsigned long delta = 50000000ul) + unsigned long delta = senf::ClockService::milliseconds(100)) { return (a<b ? b-a : a-b ) < delta; } bool is_close_pt(boost::posix_time::ptime a, boost::posix_time::ptime b, - boost::posix_time::time_duration delta = boost::posix_time::milliseconds(50) ) + boost::posix_time::time_duration delta = boost::posix_time::milliseconds(100) ) { return (a<b ? b-a : a-b ) < delta; } @@ -105,7 +105,8 @@ BOOST_AUTO_UNIT_TEST(clockService) t2 = senf::ClockService::now(); BOOST_CHECK_PREDICATE( is_close_clock, (t1 + senf::ClockService::seconds(senf::ClockService::CheckInterval)) - (t2) ); + (t2) + (senf::ClockService::milliseconds(500)) ); t1 = t2; diff --git a/Scheduler/Scheduler.cc b/Scheduler/Scheduler.cc index c720c5509..41708511e 100644 --- a/Scheduler/Scheduler.cc +++ b/Scheduler/Scheduler.cc @@ -150,7 +150,7 @@ prefix_ void senf::Scheduler::do_remove(int fd, int eventMask) bool file (i->second.file); if (ev.events==0) { action = EPOLL_CTL_DEL; - fdTable_.erase(i); + fdErase_.push_back(fd); } if (! file && epoll_ctl(epollFd_, action, fd, &ev) < 0) @@ -161,7 +161,7 @@ prefix_ void senf::Scheduler::do_remove(int fd, int eventMask) prefix_ void senf::Scheduler::registerSigHandlers() { - for (unsigned signal; signal < sigHandlers_.size(); ++signal) + for (unsigned signal (1); signal < sigHandlers_.size(); ++signal) { if (sigHandlers_[signal]) { struct ::sigaction sa; sa.sa_sigaction = & Scheduler::sigHandler; @@ -172,6 +172,7 @@ prefix_ void senf::Scheduler::registerSigHandlers() if (::sigaction(signal, &sa, 0) < 0) throw SystemException(errno); } + } } prefix_ void senf::Scheduler::sigHandler(int signal, ::siginfo_t * siginfo, void *) @@ -214,6 +215,10 @@ prefix_ void senf::Scheduler::process() timerQueue_.pop(); } + for (FdEraseList::iterator i (fdErase_.begin()); i != fdErase_.end(); ++i) + fdTable_.erase(*i); + fdErase_.clear(); + int timeout (-1); if (files_ > 0) timeout = 0; @@ -258,11 +263,8 @@ prefix_ void senf::Scheduler::process() timerMap_.erase(i); } - if (events <= 0) - continue; - // Check the signal queue - if (ev.data.fd == sigpipe_[0]) { + if (events > 0 && ev.data.fd == sigpipe_[0]) { ::siginfo_t siginfo; if (::read(sigpipe_[0], &siginfo, sizeof(siginfo)) < int(sizeof(siginfo))) { // We ignore truncated records which may only occur if the signal @@ -276,25 +278,26 @@ prefix_ void senf::Scheduler::process() } for (FdTable::iterator i = fdTable_.begin(); i != fdTable_.end(); ++i) { - EventSpec spec (i->second); - unsigned extraFlags (0); - unsigned events (spec.file ? spec.epollMask() : ev.events); + EventSpec & spec (i->second); - if (! (spec.file || i->first == ev.data.fd)) + if (! (spec.file || (events > 0 && i->first == ev.data.fd))) continue; - if (events & EPOLLHUP) extraFlags |= EV_HUP; - if (events & EPOLLERR) extraFlags |= EV_ERR; + unsigned extraFlags (0); + unsigned mask (spec.file ? spec.epollMask() : ev.events); + + if (mask & EPOLLHUP) extraFlags |= EV_HUP; + if (mask & EPOLLERR) extraFlags |= EV_ERR; - if (events & EPOLLIN) { + if (mask & EPOLLIN) { BOOST_ASSERT(spec.cb_read); spec.cb_read(EventId(EV_READ | extraFlags)); } - else if (events & EPOLLPRI) { + else if (mask & EPOLLPRI) { BOOST_ASSERT(spec.cb_prio); spec.cb_prio(EventId(EV_PRIO | extraFlags)); } - else if (events & EPOLLOUT) { + else if (mask & EPOLLOUT) { BOOST_ASSERT(spec.cb_write); spec.cb_write(EventId(EV_WRITE | extraFlags)); } diff --git a/Scheduler/Scheduler.hh b/Scheduler/Scheduler.hh index 4691e4aa4..94918af13 100644 --- a/Scheduler/Scheduler.hh +++ b/Scheduler/Scheduler.hh @@ -351,6 +351,7 @@ namespace senf { typedef std::map<int,EventSpec> FdTable; typedef std::map<unsigned,TimerSpec> TimerMap; // sorted by id + typedef std::vector<unsigned> FdEraseList; # ifndef DOXYGEN @@ -371,6 +372,7 @@ namespace senf { typedef std::vector<SimpleCallback> SigHandlers; FdTable fdTable_; + FdEraseList fdErase_; unsigned files_; unsigned timerIdCounter_; diff --git a/Scheduler/Scheduler.test.cc b/Scheduler/Scheduler.test.cc index c26b64072..2bc2a323a 100644 --- a/Scheduler/Scheduler.test.cc +++ b/Scheduler/Scheduler.test.cc @@ -186,7 +186,7 @@ namespace { bool is_close(ClockService::clock_type a, ClockService::clock_type b) { - return (a<b ? b-a : a-b) < ClockService::milliseconds(15); + return (a<b ? b-a : a-b) < ClockService::milliseconds(100); } ClockService::clock_type sigtime (0); @@ -239,15 +239,15 @@ BOOST_AUTO_UNIT_TEST(scheduler) buffer[size]=0; BOOST_CHECK_EQUAL( buffer, "READ" ); - BOOST_CHECK_NO_THROW( Scheduler::instance().timeout( - ClockService::now()+ClockService::milliseconds(100),&timeout) ); BOOST_CHECK_NO_THROW( Scheduler::instance().timeout( ClockService::now()+ClockService::milliseconds(200),&timeout) ); + BOOST_CHECK_NO_THROW( Scheduler::instance().timeout( + ClockService::now()+ClockService::milliseconds(400),&timeout) ); ClockService::clock_type t (ClockService::now()); BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); - BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (t+ClockService::milliseconds(100)) ); - BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (t+ClockService::milliseconds(200)) ); + BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); + BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (t+ClockService::milliseconds(400)) ); HandleWrapper handle(sock,"TheTag"); BOOST_CHECK_NO_THROW( Scheduler::instance().add(handle, @@ -270,14 +270,14 @@ BOOST_AUTO_UNIT_TEST(scheduler) BOOST_CHECK_NO_THROW( Scheduler::instance().remove(handle) ); unsigned tid (Scheduler::instance().timeout( - ClockService::now()+ClockService::milliseconds(200),&timeout)); + ClockService::now()+ClockService::milliseconds(400),&timeout)); BOOST_CHECK_NO_THROW( Scheduler::instance().registerSignal(SIGUSR1, &sigusr) ); t = ClockService::now(); ::kill(::getpid(), SIGUSR1); delay(100); BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); - BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (t+ClockService::milliseconds(100)) ); - BOOST_CHECK_PREDICATE( is_close, (sigtime) (t+ClockService::milliseconds(100)) ); + BOOST_CHECK_PREDICATE( is_close, (ClockService::now()) (t+ClockService::milliseconds(200)) ); + BOOST_CHECK_PREDICATE( is_close, (sigtime) (t+ClockService::milliseconds(200)) ); Scheduler::instance().cancelTimeout(tid); BOOST_CHECK_NO_THROW( Scheduler::instance().unregisterSignal(SIGUSR1) ); diff --git a/Socket/FileHandle.test.cc b/Socket/FileHandle.test.cc index 014d07233..2b9395b9e 100644 --- a/Socket/FileHandle.test.cc +++ b/Socket/FileHandle.test.cc @@ -97,6 +97,7 @@ BOOST_AUTO_UNIT_TEST(fileHandle) if (fcntl(fds[1],F_SETFL,flags|O_NONBLOCK) == -1) BOOST_FAIL(strerror(errno)); char buffer[1024]; + ::memset(buffer, 0, sizeof(buffer)); while (write(fds[1],buffer,1024) == 1024) ; FHandle fh2(fds[1]); diff --git a/Socket/Protocols/INet/INet6Address.cc b/Socket/Protocols/INet/INet6Address.cc index d330abad8..93f59638e 100644 --- a/Socket/Protocols/INet/INet6Address.cc +++ b/Socket/Protocols/INet/INet6Address.cc @@ -97,7 +97,7 @@ prefix_ std::ostream & senf::operator<<(std::ostream & os, INet6Address const & char buffer[5*8]; std::copy(addr.begin(),addr.end(),&ina.s6_addr[0]); ::inet_ntop(AF_INET6,&ina,buffer,sizeof(buffer)); - buffer[5*8] = 0; + buffer[sizeof(buffer)-1] = 0; os << buffer; return os; } diff --git a/Socket/Protocols/INet/TCPSocketHandle.test.cc b/Socket/Protocols/INet/TCPSocketHandle.test.cc index 3b4d0494f..8896f716d 100644 --- a/Socket/Protocols/INet/TCPSocketHandle.test.cc +++ b/Socket/Protocols/INet/TCPSocketHandle.test.cc @@ -64,6 +64,7 @@ namespace { (*fn)(); _exit(0); } + ::sleep(1); } void wait() diff --git a/valgrind.sup b/valgrind.sup new file mode 100644 index 000000000..4146e3ee4 --- /dev/null +++ b/valgrind.sup @@ -0,0 +1,103 @@ +{ + gethostbyname2_r-suppression-1 + Memcheck:Addr4 + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:__libc_dlopen_mode + fun:__nss_lookup_function + obj:/lib/tls/i686/cmov/libc-2.3.6.so + fun:__nss_hosts_lookup + fun:gethostbyname2_r +} +{ + gethostbyname2_r-suppression-2 + Memcheck:Cond + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:__libc_dlopen_mode + fun:__nss_lookup_function + obj:/lib/tls/i686/cmov/libc-2.3.6.so + fun:__nss_hosts_lookup + fun:gethostbyname2_r +} +{ + gethostbyname2_r-suppression-3 + Memcheck:Cond + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:__libc_dlopen_mode + fun:__nss_lookup_function + fun:__nss_next + fun:gethostbyname2_r +} +{ + gethostbyname2_r-suppression-4 + Memcheck:Addr4 + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:__libc_dlopen_mode + fun:__nss_lookup_function + fun:__nss_next + fun:gethostbyname2_r +} +{ + gethostbyname2_r-suppression-5 + Memcheck:Addr4 + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:__libc_dlopen_mode + fun:__nss_lookup_function + fun:__nss_next + fun:gethostbyname2_r +} +{ + gethostbyname2_r-suppression-4 + Memcheck:Cond + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:__libc_dlopen_mode + fun:__nss_lookup_function + fun:__nss_next + fun:gethostbyname2_r +} + +{ + inet_ntop-suppression-1 + Memcheck:Cond + fun:inet_ntop +} -- GitLab