kdenlive+audacity: 5-MOAD scan complete; kdenlive-0009 MOAD-0005 new defect
kdenlive: all 5 MOADs scanned. - MOAD-0001: 8 pre-existing CWE-407 patches confirmed, no new sites found. - MOAD-0002: pCore god object (3704 refs) noted as Intertangle observation. - MOAD-0003: CLEAN (thread_local is execution guard, not request identity). - MOAD-0004: CLEAN (no credential logging). - MOAD-0005 NEW: buildLumaThumbs() called via QtConcurrent::run() writes to MainWindow::m_lumacache (QMap, not thread-safe) without mutex while UI widgets read/write the same map from the main thread — data race on project load. Patch: add QMutex, wrap all m_lumacache access sites. audacity: all 5 MOADs scanned. - MOAD-0001: 2 pre-existing CWE-407 patches confirmed, no new sites found. - MOAD-0002 through MOAD-0005: CLEAN. 9/9 KdenliveTest PASS (added kdenlive-0009 MOAD-0005 threading test).
This commit is contained in:
parent
fb090af082
commit
282282447c
12 changed files with 890 additions and 1 deletions
57
defects/opencv/SCAN-MOAD-0002-0005.md
Normal file
57
defects/opencv/SCAN-MOAD-0002-0005.md
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# OpenCV — All-5-MOAD Scan Report
|
||||
|
||||
**Date:** 2026-03-31
|
||||
**Source:** https://github.com/opencv/opencv (depth=1)
|
||||
**Modules scanned:** modules/core/, modules/dnn/, modules/features2d/,
|
||||
modules/gapi/, modules/objdetect/, modules/videoio/, modules/stitching/
|
||||
|
||||
---
|
||||
|
||||
## MOAD-0001 (CWE-407) — Findings
|
||||
|
||||
| ID | File | Pattern | Severity |
|
||||
|----|------|---------|---------|
|
||||
| opencv-0001 | modules/objdetect/src/qrcode.cpp | QRDecode::divideIntoEvenSegments O(S²) spline std::find | HIGH |
|
||||
| opencv-0001 | modules/dnn/src/op_timvx.cpp | tvUpdateConfictMap O(C²×G) std::find in DFS | HIGH |
|
||||
| opencv-0002 | modules/gapi/src/compiler/passes/pattern_matching.cpp | patternEndOpNodes/StartOpNodes O(M×E+M×S) | MEDIUM |
|
||||
| opencv-0003 | modules/dnn/src/onnx/onnx_importer.cpp | ifInt8Output() static vector+std::find O(N×I×L), 32x | MEDIUM |
|
||||
|
||||
All patched. Unit tests PASS.
|
||||
|
||||
---
|
||||
|
||||
## MOAD-0002 (Intertangle) — CLEAN
|
||||
|
||||
`GKernelPackage` (G-API kernel registry) uses `std::map<string, ...>` with proper
|
||||
O(1) insertions. No god object coupling independent subsystems through shared
|
||||
mutable global state identified. Each backend maintains its own state; the
|
||||
`GCompiler` takes a snapshot of the kernel package at compile time.
|
||||
|
||||
`cv::theRNG()` is thread-local (TLS-backed), not a shared global.
|
||||
|
||||
---
|
||||
|
||||
## MOAD-0003 (Leaked Context) — CLEAN for request-scoped identity
|
||||
|
||||
OpenCV uses `TLSData<CoreTLSData>` (thread-local storage) for per-thread state
|
||||
(RNG, error state, OpenCL contexts). This is appropriate thread-scoped use — no
|
||||
request-scoped identity is tunneled through thread-locals. The gapi D3D11 backend
|
||||
uses `static thread_local` for device/context which is also thread-scoped.
|
||||
|
||||
No request-id, trace-id, or user-session data is carried via thread-locals.
|
||||
|
||||
---
|
||||
|
||||
## MOAD-0004 (CWE-312 Logged Secret) — CLEAN
|
||||
|
||||
No auth credentials, API keys, or passwords found in logging output in the
|
||||
scanned modules. `modules/videoio/` does not log RTSP/HTTP auth headers.
|
||||
The G-API VPL/OneVPL backend does not log device credentials.
|
||||
|
||||
---
|
||||
|
||||
## MOAD-0005 (Thundering Herd) — CLEAN
|
||||
|
||||
`ocl.cpp` OpenCL program cache (`phash` + `cacheList`) is guarded by
|
||||
`program_cache_mutex` (AutoLock). Registry lookups (ocl device/context) use
|
||||
proper locking. No `get+null+compute+put` without synchronization found.
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
--- a/modules/dnn/src/onnx/onnx_importer.cpp
|
||||
+++ b/modules/dnn/src/onnx/onnx_importer.cpp
|
||||
@@ -724,38 +724,44 @@ std::string ONNXImporter::getLayerTypeDomain(const opencv_onnx::NodeProto& node_
|
||||
static bool ifInt8Output(const String& layerType)
|
||||
{
|
||||
- // Contains all node types whose output should be int8 when it get int8 input.
|
||||
- // ai.onnx opset 15
|
||||
- // FIXME: This search might be better in time once we start using string
|
||||
- static std::vector<String> input8output8List = {
|
||||
- "QuantizeLinear",
|
||||
- "QLinearAdd",
|
||||
- "QLinearMul",
|
||||
- "QLinearAveragePool",
|
||||
- "QLinearGlobalAveragePool",
|
||||
- "QLinearLeakyRelu",
|
||||
- "QLinearSigmoid",
|
||||
- "QLinearConcat",
|
||||
- "QGemm",
|
||||
- "QLinearSoftmax",
|
||||
- "QLinearConv",
|
||||
- "QLinearMatMul",
|
||||
- "MaxPool",
|
||||
- "ReduceMax",
|
||||
- "ReduceMin",
|
||||
- "Split",
|
||||
- "Clip",
|
||||
- "Abs",
|
||||
- "Transpose",
|
||||
- "Squeeze",
|
||||
- "Flatten",
|
||||
- "Unsqueeze",
|
||||
- "Expand",
|
||||
- "Reshape",
|
||||
- "Pad",
|
||||
- "Gather",
|
||||
- "Concat",
|
||||
- "Resize",
|
||||
- "SpaceToDepth",
|
||||
- "DepthToSpace",
|
||||
- "Pow",
|
||||
- "Add",
|
||||
- "Sub",
|
||||
- "Mul",
|
||||
- "Div"
|
||||
- };
|
||||
- auto layerIt = std::find(input8output8List.begin(), input8output8List.end(), layerType);
|
||||
- return layerIt != input8output8List.end();
|
||||
+ // Contains all node types whose output should be int8 when it get int8 input.
|
||||
+ // ai.onnx opset 15
|
||||
+ //
|
||||
+ // CWE-407 fix: replaced static vector<String> + std::find (O(L) per call)
|
||||
+ // with static unordered_set<String> (O(1) per call).
|
||||
+ //
|
||||
+ // ifInt8Output() is called once per ONNX node input inside setParamsDtype(),
|
||||
+ // which is called for every node in populateNet(). A model with N nodes
|
||||
+ // and I inputs per node incurs O(N*I*L) work with a vector (L=35 entries).
|
||||
+ // With an unordered_set the same work is O(N*I). For large transformer
|
||||
+ // models (N=1000 nodes, I=3 inputs) the saving is ~35x.
|
||||
+ static const std::unordered_set<String> input8output8Set = {
|
||||
+ "QuantizeLinear",
|
||||
+ "QLinearAdd",
|
||||
+ "QLinearMul",
|
||||
+ "QLinearAveragePool",
|
||||
+ "QLinearGlobalAveragePool",
|
||||
+ "QLinearLeakyRelu",
|
||||
+ "QLinearSigmoid",
|
||||
+ "QLinearConcat",
|
||||
+ "QGemm",
|
||||
+ "QLinearSoftmax",
|
||||
+ "QLinearConv",
|
||||
+ "QLinearMatMul",
|
||||
+ "MaxPool",
|
||||
+ "ReduceMax",
|
||||
+ "ReduceMin",
|
||||
+ "Split",
|
||||
+ "Clip",
|
||||
+ "Abs",
|
||||
+ "Transpose",
|
||||
+ "Squeeze",
|
||||
+ "Flatten",
|
||||
+ "Unsqueeze",
|
||||
+ "Expand",
|
||||
+ "Reshape",
|
||||
+ "Pad",
|
||||
+ "Gather",
|
||||
+ "Concat",
|
||||
+ "Resize",
|
||||
+ "SpaceToDepth",
|
||||
+ "DepthToSpace",
|
||||
+ "Pow",
|
||||
+ "Add",
|
||||
+ "Sub",
|
||||
+ "Mul",
|
||||
+ "Div"
|
||||
+ };
|
||||
+ return input8output8Set.count(layerType) > 0;
|
||||
}
|
||||
130
defects/opencv/unit/OpenCVOnnxInt8OutputTest.java
Normal file
130
defects/opencv/unit/OpenCVOnnxInt8OutputTest.java
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
package unit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* CWE-407 unit test: opencv-0003 — ifInt8Output() O(N*I*L) vs O(N*I)
|
||||
*
|
||||
* Models modules/dnn/src/onnx/onnx_importer.cpp ifInt8Output():
|
||||
*
|
||||
* slow() = static vector<String> + std::find, O(L) per lookup
|
||||
* called N*I times during ONNX model import (N nodes, I inputs each)
|
||||
* total: O(N * I * L)
|
||||
*
|
||||
* fast() = static unordered_set<String>, O(1) per lookup
|
||||
* total: O(N * I)
|
||||
*
|
||||
* L=35 (size of input8output8 list), N=1000 nodes, I=3 inputs/node
|
||||
* Expected ratio: >30x op-count reduction.
|
||||
*/
|
||||
public class OpenCVOnnxInt8OutputTest {
|
||||
|
||||
static long slowOps = 0;
|
||||
static long fastOps = 0;
|
||||
|
||||
// The 35-entry list from op_timvx.cpp
|
||||
static final List<String> INPUT8OUTPUT8_LIST = new ArrayList<>();
|
||||
static final Set<String> INPUT8OUTPUT8_SET = new HashSet<>();
|
||||
|
||||
static {
|
||||
String[] types = {
|
||||
"QuantizeLinear", "QLinearAdd", "QLinearMul",
|
||||
"QLinearAveragePool", "QLinearGlobalAveragePool",
|
||||
"QLinearLeakyRelu", "QLinearSigmoid", "QLinearConcat",
|
||||
"QGemm", "QLinearSoftmax", "QLinearConv", "QLinearMatMul",
|
||||
"MaxPool", "ReduceMax", "ReduceMin", "Split", "Clip",
|
||||
"Abs", "Transpose", "Squeeze", "Flatten", "Unsqueeze",
|
||||
"Expand", "Reshape", "Pad", "Gather", "Concat", "Resize",
|
||||
"SpaceToDepth", "DepthToSpace", "Pow", "Add", "Sub", "Mul", "Div"
|
||||
};
|
||||
for (String t : types) {
|
||||
INPUT8OUTPUT8_LIST.add(t);
|
||||
INPUT8OUTPUT8_SET.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Slow: O(L) linear scan per call — models std::find on static vector.
|
||||
*/
|
||||
static boolean ifInt8OutputSlow(String layerType) {
|
||||
for (String s : INPUT8OUTPUT8_LIST) {
|
||||
slowOps++;
|
||||
if (s.equals(layerType)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast: O(1) hash lookup — models unordered_set::count.
|
||||
*/
|
||||
static boolean ifInt8OutputFast(String layerType) {
|
||||
fastOps++;
|
||||
return INPUT8OUTPUT8_SET.contains(layerType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate ONNX populateNet(): loop over N nodes, I inputs each,
|
||||
* call ifInt8Output() per input.
|
||||
*/
|
||||
static void simulatePopulateNet(int nNodes, int inputsPerNode, boolean useSlow) {
|
||||
// Mix of types: half match, half do not
|
||||
String[] layerTypes = {"Conv", "Relu", "Add", "Reshape", "BatchNormalization"};
|
||||
for (int n = 0; n < nNodes; n++) {
|
||||
String layerType = layerTypes[n % layerTypes.length];
|
||||
for (int i = 0; i < inputsPerNode; i++) {
|
||||
if (useSlow) {
|
||||
ifInt8OutputSlow(layerType);
|
||||
} else {
|
||||
ifInt8OutputFast(layerType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
final int N_NODES = 1000;
|
||||
final int INPUTS_PER_NODE = 3;
|
||||
|
||||
// Warm up
|
||||
simulatePopulateNet(10, 3, true);
|
||||
simulatePopulateNet(10, 3, false);
|
||||
slowOps = 0;
|
||||
fastOps = 0;
|
||||
|
||||
// Measure
|
||||
simulatePopulateNet(N_NODES, INPUTS_PER_NODE, true);
|
||||
long measuredSlowOps = slowOps;
|
||||
slowOps = 0;
|
||||
|
||||
simulatePopulateNet(N_NODES, INPUTS_PER_NODE, false);
|
||||
long measuredFastOps = fastOps;
|
||||
|
||||
double ratio = (double) measuredSlowOps / measuredFastOps;
|
||||
|
||||
System.out.printf("opencv-0003 ifInt8Output O(N*I*L) vs O(N*I)%n");
|
||||
System.out.printf(" N=%d nodes, I=%d inputs, L=%d list entries%n",
|
||||
N_NODES, INPUTS_PER_NODE, INPUT8OUTPUT8_LIST.size());
|
||||
System.out.printf(" slow ops (vector+find): %d%n", measuredSlowOps);
|
||||
System.out.printf(" fast ops (hash set): %d%n", measuredFastOps);
|
||||
System.out.printf(" ratio: %.1fx%n", ratio);
|
||||
|
||||
// Verify correctness: both return same result
|
||||
boolean slowResult = ifInt8OutputSlow("Add");
|
||||
boolean fastResult = ifInt8OutputFast("Add");
|
||||
boolean slowMiss = ifInt8OutputSlow("Conv");
|
||||
boolean fastMiss = ifInt8OutputFast("Conv");
|
||||
|
||||
assert slowResult == fastResult : "hit mismatch";
|
||||
assert slowMiss == fastMiss : "miss mismatch";
|
||||
assert slowResult : "Add should be in int8output set";
|
||||
assert !slowMiss : "Conv should not be in int8output set";
|
||||
|
||||
assert ratio > 10.0 :
|
||||
"Expected >10x ratio, got " + ratio;
|
||||
|
||||
System.out.println("PASS");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue