wave11: 488/227 — ROS2/OpenCV/Open3D/metaflow/kubeflow/optuna/openssl/mbedtls/wolfssl + Kafka Streams/Pulsar
This commit is contained in:
parent
6276aea2e5
commit
19333b378e
36 changed files with 4634 additions and 5 deletions
|
|
@ -0,0 +1,91 @@
|
|||
# open3d-0001: ValidatePoseGraphConnectivity — O(V²×E) std::find on component vector inside BFS×edge scan
|
||||
|
||||
## Location
|
||||
`cpp/open3d/pipelines/registration/GlobalOptimization.cpp` lines 367–404
|
||||
Repository: https://github.com/isl-org/Open3D
|
||||
|
||||
## Severity
|
||||
**HIGH** — Called twice during pose graph validation (for all edges, then certain edges only) before every global optimization run. With V nodes and E edges in the pose graph, the BFS expands V nodes, each scanning all E edges, and for each adjacent node does a O(V) `std::find` on `component`. Total: O(V²×E). For large 3D reconstruction datasets (thousands of frames/cameras), this is a significant pre-optimization bottleneck.
|
||||
|
||||
## Complexity
|
||||
- Before: O(V² × E) — std::find on `component` (O(V)) called inside while-loop (V iters) × edge-scan (E iters)
|
||||
- After: O(V × E) — O(1) unordered_set membership replaces the O(V) linear scan
|
||||
|
||||
## Defective Code
|
||||
|
||||
```cpp
|
||||
// GlobalOptimization.cpp:367-404
|
||||
static bool ValidatePoseGraphConnectivity(const PoseGraph &pose_graph,
|
||||
bool ignore_uncertain_edges = false) {
|
||||
size_t n_nodes = pose_graph.nodes_.size();
|
||||
size_t n_edges = pose_graph.edges_.size();
|
||||
|
||||
std::vector<int> nodes_to_explore{};
|
||||
std::vector<int> component{}; // membership tracked as a vector
|
||||
if (n_nodes > 0) {
|
||||
nodes_to_explore.push_back(0);
|
||||
component.push_back(0);
|
||||
}
|
||||
while (!nodes_to_explore.empty()) {
|
||||
int i = nodes_to_explore.back();
|
||||
nodes_to_explore.pop_back();
|
||||
for (size_t j = 0; j < n_edges; j++) {
|
||||
const PoseGraphEdge &t = pose_graph.edges_[j];
|
||||
if (ignore_uncertain_edges && t.uncertain_) continue;
|
||||
int adjacent_node{-1};
|
||||
if (t.source_node_id_ == i) adjacent_node = t.target_node_id_;
|
||||
else if (t.target_node_id_ == i) adjacent_node = t.source_node_id_;
|
||||
if (adjacent_node != -1) {
|
||||
auto find_result = std::find(component.begin(), component.end(),
|
||||
adjacent_node); // O(V) per call
|
||||
if (find_result == component.end()) {
|
||||
nodes_to_explore.push_back(adjacent_node);
|
||||
component.push_back(adjacent_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return component.size() == n_nodes;
|
||||
}
|
||||
```
|
||||
|
||||
**Problem:** `component` is a `std::vector<int>`. The `std::find` membership check is O(V)
|
||||
called for every edge of every explored node. BFS visits V nodes, each scanning E edges,
|
||||
each doing O(V) find → O(V²×E) total.
|
||||
|
||||
## Fixed Code
|
||||
|
||||
```cpp
|
||||
static bool ValidatePoseGraphConnectivity(const PoseGraph &pose_graph,
|
||||
bool ignore_uncertain_edges = false) {
|
||||
size_t n_nodes = pose_graph.nodes_.size();
|
||||
size_t n_edges = pose_graph.edges_.size();
|
||||
|
||||
std::vector<int> nodes_to_explore{};
|
||||
std::unordered_set<int> component_set; // O(1) membership
|
||||
if (n_nodes > 0) {
|
||||
nodes_to_explore.push_back(0);
|
||||
component_set.insert(0);
|
||||
}
|
||||
while (!nodes_to_explore.empty()) {
|
||||
int i = nodes_to_explore.back();
|
||||
nodes_to_explore.pop_back();
|
||||
for (size_t j = 0; j < n_edges; j++) {
|
||||
const PoseGraphEdge &t = pose_graph.edges_[j];
|
||||
if (ignore_uncertain_edges && t.uncertain_) continue;
|
||||
int adjacent_node{-1};
|
||||
if (t.source_node_id_ == i) adjacent_node = t.target_node_id_;
|
||||
else if (t.target_node_id_ == i) adjacent_node = t.source_node_id_;
|
||||
if (adjacent_node != -1) {
|
||||
if (component_set.insert(adjacent_node).second) { // O(1)
|
||||
nodes_to_explore.push_back(adjacent_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return component_set.size() == n_nodes;
|
||||
}
|
||||
```
|
||||
|
||||
## CWE
|
||||
CWE-407: Inefficient Algorithmic Complexity — O(V²×E) → O(V×E)
|
||||
60
defects/open3d/patch/open3d-0002-ransac-sampler-find.md
Normal file
60
defects/open3d/patch/open3d-0002-ransac-sampler-find.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# open3d-0002: RandomSampler::operator() — O(S²) std::find on samples vector inside rejection-sampling loop
|
||||
|
||||
## Location
|
||||
`cpp/open3d/geometry/PointCloudSegmentation.cpp` lines 31–46
|
||||
Repository: https://github.com/isl-org/Open3D
|
||||
|
||||
## Severity
|
||||
**MEDIUM** — Called `num_iterations` times (typically 100–1000) during RANSAC plane segmentation. Each call uses rejection sampling with std::find on the growing `samples` vector. For a sample_size S, each call is O(S²) expected. The developer comment acknowledges "Well, this is slow." Total: O(num_iterations × S²). For ransac_n=3 (default), S=3 and impact is small, but for custom higher ransac_n values the overhead is measurable.
|
||||
|
||||
## Complexity
|
||||
- Before: O(S²) per sample call — std::find on growing `samples` vector inside while loop
|
||||
- After: O(S) per sample call — unordered_set for O(1) duplicate detection
|
||||
|
||||
## Defective Code
|
||||
|
||||
```cpp
|
||||
// PointCloudSegmentation.cpp:31-46
|
||||
std::vector<T> operator()(size_t sample_size) {
|
||||
std::vector<T> samples;
|
||||
samples.reserve(sample_size);
|
||||
|
||||
size_t valid_sample = 0;
|
||||
while (valid_sample < sample_size) {
|
||||
const size_t idx = utility::random::RandUint32() % total_size_;
|
||||
// Well, this is slow. But typically the sample_size is small.
|
||||
if (std::find(samples.begin(), samples.end(), idx) ==
|
||||
samples.end()) {
|
||||
samples.push_back(idx);
|
||||
valid_sample++;
|
||||
}
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
```
|
||||
|
||||
**Problem:** `std::find` on `samples` is O(valid_sample) inside the while loop. As
|
||||
`valid_sample` grows from 0 to `sample_size`, the total work is 0+1+2+...+(S-1) = O(S²).
|
||||
Called `num_iterations` times, total is O(num_iterations × S²).
|
||||
|
||||
## Fixed Code
|
||||
|
||||
```cpp
|
||||
std::vector<T> operator()(size_t sample_size) {
|
||||
std::vector<T> samples;
|
||||
samples.reserve(sample_size);
|
||||
std::unordered_set<T> seen;
|
||||
seen.reserve(sample_size);
|
||||
|
||||
while (samples.size() < sample_size) {
|
||||
const size_t idx = utility::random::RandUint32() % total_size_;
|
||||
if (seen.insert(idx).second) { // O(1) duplicate detection
|
||||
samples.push_back(idx);
|
||||
}
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
```
|
||||
|
||||
## CWE
|
||||
CWE-407: Inefficient Algorithmic Complexity — O(S²) → O(S) per sample call
|
||||
Loading…
Add table
Add a link
Reference in a new issue