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 break
ing. The same thing needs to be done in find_ask
.