enewhuis / liquibook

Modern C++ order matching engine

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Incorrect behaviour with orderbook::find_bid and orderbook::find_ask

thakkarparth007 opened this issue · comments

This is a rather subtle bug, but can cause a lot of trouble. The find_bid and ask_bid methods are similar and both have the same bug. Consider the code for find_bid:

template <class OrderPtr>
inline void
OrderBook<OrderPtr>::find_bid(
  const OrderPtr& order,
  typename Bids::iterator& result)
{
  // Find the order search price
  Price search_price = sort_price(order);
  for (result = bids_.find(search_price); result != bids_.end(); ++result) {
    // If this is the correct bid
    if (result->second.ptr() == order) {
      break;
    // Else if this bid's price is too low to match the search price
    } else if (result->first < search_price) {
      // Here lies that bug.
      break; // No more possible
    }
  }
}

If you see carefully, then the value of result is not set to bid_.end() if the loop breaks in the else condition. This can happen if, for example, there are 2 bids of same price (100, 100) and another bid of 101. Now, if by mistake someone cancels 101 twice (which is possible if one isn't careful), or someone cancels an order that doesn't exist (which is again possible, but less probably than the first case), then one of the 100-bid would be cancelled too.

I've checked only the cancel part, but find_bid is also used in replace and similar situation can arise over there.

The tests don't consider this situation, and hence the code builds fine. The solution is to set result = bids_.end() in the else before breaking. The same thing needs to be done in find_ask.