Rainer Keerdo
Rainer Keerdo

Reputation: 35

Boost asio async_write_some leaking?

I've been messing around with an application that uses boost::asio for both UDP and SocketCAN communication. Today, I noticed something weird - it was leaking memory!

So I grabbed my trusty toolkit consisting of

echo 0 $(awk '/Private/ {print "+", $2}' /proc/`pidof main`/smaps) | bc

and Allinea DDT and got to work diagnosing this issue.

What I ended up with was the following snippet, which utilizes boost::asio::posix::basic_stream_descriptor as it's base :

void Can::write(struct can_frame frame) {
  stream_.async_write_some(boost::asio::buffer(&frame, sizeof(frame)),
                           boost::bind(&Can::datSend, this)
  );
}

Here, the datSend is just an empty function that pings a watchdog. I've also tried

void Can::write(struct can_frame frame) {
  stream_.write_some(boost::asio::buffer(&frame, sizeof(frame)));
}

But this gives an exception (invalid data) for some reason.

The rear end of this code looks something like this :

boost::asio::io_service ioService_;
boost::asio::posix::basic_stream_descriptor<> stream_;

Constructor() : stream_(ioService_) {
  socketDescriptor_ = socket(PF_CAN, SOCK_RAW, CAN_RAW);

  struct timeval timeout {
      .tv_sec = 5,
      .tv_usec = 0
  };

  if (setsockopt(socketDescriptor_, SOL_SOCKET, SO_RCVTIMEO,
                 reinterpret_cast<char *>(&timeout),
                 sizeof(timeout)) < 0) {
    throw std::string("Error setting CAN socket timeout");
  }

  strcpy(interfaceRequest_.ifr_name, interfaceName.c_str());
  ioctl(socketDescriptor_, SIOCGIFINDEX, &interfaceRequest_);
  socketAddress_.can_family = AF_CAN;
  socketAddress_.can_ifindex = interfaceRequest_.ifr_ifindex;
  stream_.assign(socketDescriptor_);

  if (bind(socketDescriptor_, (struct sockaddr *)&socketAddress_,
           sizeof(socketAddress_)) < 0) {
    throw std::string("Error in socket bind");
  }

}

Afterwards I just run the ioservice and that's that :

void Can::iosThreadWorker() { ioService_.run(); }

I've gone over quite a few stackoverflow topics as well as boost documentation, but can't seem to find why this function would leak memory.

Boost version - 1.60 G++ - 6.30 OS : Ubuntu 17.04

Upvotes: 1

Views: 385

Answers (1)

Rainer Keerdo
Rainer Keerdo

Reputation: 35

So I dug a bit deeper and found this tidbit about boost.io_service :

io_service.run() completes if it has no work to do - so by running it and then sending more async work to be done, the work was not getting completed.

This stemmed from an issue where someone had flipped the ioservice.run() and async read callback assignment to make to code look better - now there was no work piled up before running and ioservice could just complete it's job and return.

Upvotes: 2

Related Questions