java-topology/defects/tiled-0001/test/tiled-0001-test.cpp
russell@unturf.com 191f018d78 undf: assign 949-951; tiled map editor 3 CWE-407 defects
tiled-0001: mapdocument.cpp sortObjects/sortLayers/moveLayersUp/Down/duplicate
  QList.contains() inside iteration over all map layers/objects = O(N*S)
  Fix: QSet O(1) lookup. MEDIUM severity. 24x speedup at N=2000,S=1000.

tiled-0002: mapobjectmodel.cpp classChanged
  QList.contains(tile) inside nested loop over all map objects = O(O*T)
  Fix: QSet O(1) lookup. MEDIUM severity. 14x speedup at O=2000,T=500.

tiled-0003: editpolygontool.cpp updateHandles
  QList.contains() inside QHash iteration = O(H*S)
  Fix: QSet O(1) lookup. MEDIUM severity. 13x speedup at H=1000,S=500.

3/3 PASS. MOAD-0002/0003/0004/0005 CLEAN.
2026-03-31 11:44:37 -04:00

83 lines
2.6 KiB
C++

// tiled-0001-test.cpp
// CWE-407 unit test: mapdocument.cpp sortObjects/sortLayers/moveLayersUp/moveLayersDown/duplicateLayers
// QList.contains() inside iteration over all map layers/objects = O(AllItems * SelectedItems)
// Fix: QSet lookup O(1) per item
//
// Simulates the pattern: iterate all items, check membership in selected set.
#include <QList>
#include <QSet>
#include <QElapsedTimer>
#include <cstdio>
#include <cstdlib>
#include <cassert>
// Simulate the defective sortObjects pattern
static QList<void*> sortObjects_defective(const QList<void*> &allObjects, const QList<void*> &selected) {
QList<void*> sorted;
sorted.reserve(selected.size());
for (void *obj : allObjects) {
if (selected.contains(obj)) // O(N) per call
sorted.append(obj);
}
return sorted;
}
// Fixed version: QSet for O(1) lookup
static QList<void*> sortObjects_fixed(const QList<void*> &allObjects, const QList<void*> &selected) {
const QSet<void*> selectedSet(selected.begin(), selected.end());
QList<void*> sorted;
sorted.reserve(selected.size());
for (void *obj : allObjects) {
if (selectedSet.contains(obj)) // O(1) per call
sorted.append(obj);
}
return sorted;
}
int main() {
// N = total objects on map, S = selected objects
const int N = 2000;
const int S = 1000;
QList<void*> allObjects;
allObjects.reserve(N);
for (int i = 0; i < N; ++i)
allObjects.append(reinterpret_cast<void*>(static_cast<uintptr_t>(i + 1)));
// Select every other object
QList<void*> selected;
selected.reserve(S);
for (int i = 0; i < S; ++i)
selected.append(allObjects[i * 2]);
const int ITERS = 200;
// Benchmark defective
QElapsedTimer timer;
timer.start();
for (int i = 0; i < ITERS; ++i) {
auto result = sortObjects_defective(allObjects, selected);
assert(result.size() == S);
}
qint64 defective_us = timer.nsecsElapsed() / 1000;
// Benchmark fixed
timer.restart();
for (int i = 0; i < ITERS; ++i) {
auto result = sortObjects_fixed(allObjects, selected);
assert(result.size() == S);
}
qint64 fixed_us = timer.nsecsElapsed() / 1000;
double ratio = (double)defective_us / (double)fixed_us;
printf("tiled-0001 CWE-407 sortObjects/sortLayers QList.contains in loop\n");
printf(" N=%d total objects, S=%d selected, %d iterations\n", N, S, ITERS);
printf(" defective: %lld us\n", defective_us);
printf(" fixed: %lld us\n", fixed_us);
printf(" ratio: %.1fx\n", ratio);
printf(" %s\n", ratio >= 2.0 ? "PASS" : "FAIL");
return ratio >= 2.0 ? 0 : 1;
}