8000 [BTS-2231] Fix divide-by-zero crash (#22030) (#22040) · arangodb/arangodb@e46c8ed · GitHub
[go: up one dir, main page]

Skip to content

Commit e46c8ed

Browse files
[BTS-2231] Fix divide-by-zero crash (#22030) (#22040)
* Introduce checks to prevent by zero division. * Fixes a divide-by-zero crash when a smart edge collection is used in a collect query.
1 parent 503c71a commit e46c8ed

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
3.12.5.2 (2025-08-01)
22
---------------------
33

4+
* Fix BTS-2231: Fix a divide-by-zero crash in case a smart edge collection is used in a
5+
collect query with a custom index.
6+
47
* Fix BTS-2201: Make aggreate collect queries work again on an empty collection
58
that has an index used in the query.
69

arangod/Aql/Optimizer/Rule/OptimizerRuleCollectWithIndex.cpp

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
#include "Logger/LogMacros.h"
4040
#include "VocBase/LogicalCollection.h"
4141

42+
#if USE_ENTERPRISE
43+
#include "Enterprise/VocBase/VirtualClusterSmartEdgeCollection.h"
44+
#endif
45+
4246
using namespace arangodb;
4347
using namespace arangodb::aql;
4448
using namespace arangodb::containers;
@@ -164,6 +168,13 @@ bool selectivityIsLowEnough(IndexNode const& in) {
164168

165169
double requiredSelectivity;
166170
if (ServerState::instance()->isSingleServer()) {
171+
if (numberOfItems == 1) {
172+
// log(1) is 0 so we are dividing by zero here
173+
// IEEE-754 defines division-by-zero to lead to NaN, +Inf or -Inf
174+
// 1.0 / 0.0 should by definition lead to +Inf, so we skip the calculation
175+
// and return directly.
176+
return true;
177+
}
167178
requiredSelectivity = 1. / log(numberOfItems);
168179
} else {
169180
// in cluster mode, we use the same equation as an approximation, although
@@ -175,8 +186,36 @@ bool selectivityIsLowEnough(IndexNode const& in) {
175186
// TODO compare the total costs of executing the optimized vs. the
176187
// non-optimized execution node, which involves getting the selectivity
177188
// estimate of each shard separately
178-
requiredSelectivity =
179-
1. / log(numberOfItems / index->collection().numberOfShards());
189+
auto numberOfShards = index->collection().numberOfShards();
190+
if (numberOfShards == 0) {
191+
#if USE_ENTERPRISE
192+
// In case of smart edge collections we do have 0 shards,
193+
// this would lead to a SIGFPE(FPE_INTDIV) and crash.
194+
// So we get the number of shards of the underlying collections
195+
// e.g. _local
196+
try {
197+
auto& virtualEdgeCol = dynamic_cast<VirtualClusterSmartEdgeCollection&>(
198+
index->collection());
199+
numberOfShards = virtualEdgeCol.numberOfUnderlyingShards();
200+
} catch (std::bad_cast&) {
201+
}
202+
#endif // USE_ENTERPRISE
203+
if (numberOfShards == 0) {
204+
LOG_RULE << "IndexNode " << in.id()
205+
<< " detected a node with zero shards,"
206+
<< " which is not a virtual smart edge collection";
207+
return false;
208+
}
209+
}
210+
211+
if (numberOfItems == numberOfShards) {
212+
// log(1) is 0 so we are dividing by zero here
213+
// IEEE-754 defines division-by-zero to lead to NaN, +Inf or -Inf
214+
// 1.0 / 0.0 should by definition lead to +Inf, so we skip the calculation
215+
// and return directly.
216+
return true;
217+
}
218+
requiredSelectivity = 1. / log(numberOfItems / numberOfShards);
180219
}
181220

182221
if (index_selectivity > requiredSelectivity) {

0 commit comments

Comments
 (0)
0