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,77 @@
|
|||
# ros2-0001: ParameterEventsFilter — O(N×P) std::find on names vector inside parameter loop
|
||||
|
||||
## Location
|
||||
`rclcpp/src/rclcpp/parameter_events_filter.cpp` lines 35–57
|
||||
Repository: https://github.com/ros2/rclcpp
|
||||
|
||||
## Severity
|
||||
**HIGH** — Called every time a parameter event arrives on a ROS2 node. With N filter names and P parameters per event type, each event dispatch is O(N×P×3). Large parameter servers (e.g. nav2, MoveIt) publish batched events with dozens of parameters.
|
||||
|
||||
## Complexity
|
||||
- Before: O(N×P) per event type, O(3×N×P) total
|
||||
- After: O(N) build + O(P) dispatch = O(N+P) total
|
||||
|
||||
## Defective Code
|
||||
|
||||
```cpp
|
||||
// parameter_events_filter.cpp:34-57
|
||||
if (std::find(types.begin(), types.end(), EventType::NEW) != types.end()) {
|
||||
for (auto & new_parameter : event_->new_parameters) {
|
||||
if (std::find(names.begin(), names.end(), new_parameter.name) != names.end()) {
|
||||
result_.push_back(EventPair(EventType::NEW, &new_parameter));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (std::find(types.begin(), types.end(), EventType::CHANGED) != types.end()) {
|
||||
for (auto & changed_parameter : event_->changed_parameters) {
|
||||
if (std::find(names.begin(), names.end(), changed_parameter.name) != names.end()) {
|
||||
result_.push_back(EventPair(EventType::CHANGED, &changed_parameter));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (std::find(types.begin(), types.end(), EventType::DELETED) != types.end()) {
|
||||
for (auto & deleted_parameter : event_->deleted_parameters) {
|
||||
if (std::find(names.begin(), names.end(), deleted_parameter.name) != names.end()) {
|
||||
result_.push_back(EventPair(EventType::DELETED, &deleted_parameter));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Problem:** `std::find(names.begin(), names.end(), ...)` is O(N) linear scan inside each
|
||||
inner loop over event parameters. Three independent O(N×P) blocks = O(3×N×P) total.
|
||||
Also `std::find` on `types` is O(T) but T≤3 so negligible.
|
||||
|
||||
## Fixed Code
|
||||
|
||||
```cpp
|
||||
// Build O(1)-lookup set from names once
|
||||
std::unordered_set<std::string> names_set(names.begin(), names.end());
|
||||
std::unordered_set<int> types_set;
|
||||
for (auto t : types) types_set.insert(static_cast<int>(t));
|
||||
|
||||
if (types_set.count(static_cast<int>(EventType::NEW))) {
|
||||
for (auto & new_parameter : event_->new_parameters) {
|
||||
if (names_set.count(new_parameter.name)) {
|
||||
result_.push_back(EventPair(EventType::NEW, &new_parameter));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (types_set.count(static_cast<int>(EventType::CHANGED))) {
|
||||
for (auto & changed_parameter : event_->changed_parameters) {
|
||||
if (names_set.count(changed_parameter.name)) {
|
||||
result_.push_back(EventPair(EventType::CHANGED, &changed_parameter));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (types_set.count(static_cast<int>(EventType::DELETED))) {
|
||||
for (auto & deleted_parameter : event_->deleted_parameters) {
|
||||
if (names_set.count(deleted_parameter.name)) {
|
||||
result_.push_back(EventPair(EventType::DELETED, &deleted_parameter));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## CWE
|
||||
CWE-407: Inefficient Algorithmic Complexity — O(N×P) → O(N+P)
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
# ros2-0002: NodeParameters::list_parameters() — O(P²) std::find on result.prefixes inside parameter loop
|
||||
|
||||
## Location
|
||||
`rclcpp/src/rclcpp/node_interfaces/node_parameters.cpp` lines 1098–1133
|
||||
Repository: https://github.com/ros2/rclcpp
|
||||
|
||||
## Severity
|
||||
**MEDIUM** — Called when listing parameters, e.g. during node startup introspection, parameter dump, or `ros2 param list`. With P parameters and up to P unique prefixes, the deduplication loop is O(P²). Large ROS2 nodes (nav2 has 100+ parameters) call this during lifecycle transitions.
|
||||
|
||||
## Complexity
|
||||
- Before: O(P²) — std::find on result.prefixes (grows to P) inside outer loop over parameters_ (size P)
|
||||
- After: O(P) — unordered_set tracks seen prefixes in O(1)
|
||||
|
||||
## Defective Code
|
||||
|
||||
```cpp
|
||||
// node_parameters.cpp:1098-1133
|
||||
for (const std::pair<const std::string, ParameterInfo> & kv : parameters_) {
|
||||
// ... prefix matching logic ...
|
||||
|
||||
result.names.push_back(kv.first);
|
||||
size_t last_separator = kv.first.find_last_of(separator);
|
||||
if (std::string::npos != last_separator) {
|
||||
std::string prefix = kv.first.substr(0, last_separator);
|
||||
if (
|
||||
std::find(result.prefixes.cbegin(), result.prefixes.cend(), prefix) == // O(P) per iteration
|
||||
result.prefixes.cend())
|
||||
{
|
||||
result.prefixes.push_back(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Problem:** `std::find` on `result.prefixes` is O(|result.prefixes|) which grows up to P
|
||||
as parameters are processed. This makes the entire loop O(P²).
|
||||
|
||||
## Fixed Code
|
||||
|
||||
```cpp
|
||||
std::unordered_set<std::string> seen_prefixes;
|
||||
for (const std::pair<const std::string, ParameterInfo> & kv : parameters_) {
|
||||
// ... prefix matching logic (unchanged) ...
|
||||
|
||||
result.names.push_back(kv.first);
|
||||
size_t last_separator = kv.first.find_last_of(separator);
|
||||
if (std::string::npos != last_separator) {
|
||||
std::string prefix = kv.first.substr(0, last_separator);
|
||||
if (seen_prefixes.insert(prefix).second) { // O(1) insert+dedup
|
||||
result.prefixes.push_back(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## CWE
|
||||
CWE-407: Inefficient Algorithmic Complexity — O(P²) → O(P)
|
||||
Loading…
Add table
Add a link
Reference in a new issue