blender+darktable: 3 new defects, MOADs 0002-0005 scan complete

blender-0004: MOAD-0001 CWE-407 anim_channels_edit.cc
  rearrange_animchannel_islands() calls BLI_findptr(anim_data_visible, channel, ...)
  inside the channel-grouping loop — O(C*V) where C=channels, V=visible channels.
  In a complex rig: C=V=1000, 1,000,000 pointer comparisons per reorder.
  Fix: build blender::Set<void*> from anim_data_visible before loop, O(1) lookup.
  Measured: 250x op-count ratio at C=V=1000.

darktable-0004: MOAD-0004 CWE-312 pwstorage backends
  backend_kwallet.c and backend_apple_keychain.c log credential key/value pairs
  verbatim via dt_print(DT_DEBUG_PWSTORAGE, "storing (%s, %s)", key, value).
  `value` for Piwigo export is JSON including plaintext password.
  Triggered by `darktable -d pwstorage` or `-d all` (common debugging mode).
  Fix: replace value argument with "[REDACTED]" in all four dt_print calls.

darktable-0005: MOAD-0001 CWE-407 modulegroups test_visible O(M*G*P)
  _lib_modulegroups_update_iop_visibility() iterates M=80 IOP modules, calling
  _lib_modulegroups_test_visible() which iterates G=8 groups doing g_list_find_custom
  (linear scan of P=10 module names per group) — O(M*G*P) per UI refresh.
  Called on every search keystroke, module toggle, and group switch.
  Fix: precompute GHashTable of all visible module names; test_visible = O(1).
  Measured: 37.8x op-count ratio at M=80, G=8, P=10.

MOADs 0002/0003/0005 CLEAN for blender; MOADs 0002/0003/0005 CLEAN for darktable.
All 4 blender + 5 darktable unit tests PASS.
This commit is contained in:
russell@unturf.com 2026-03-31 20:49:15 -04:00
parent 595e96ffe1
commit 7d135aa6a1
12 changed files with 467 additions and 7 deletions

View file

@ -1,11 +1,13 @@
import java.util.*;
/**
* CWE-407 simulation tests for darktable defects.
* CWE-407 / CWE-312 simulation tests for darktable defects.
*
* darktable-0001: map_locations image diff via g_list_find O(N*M)
* darktable-0002: _tag_add_tags_to_list dedup via g_list_find O(T*L)
* darktable-0003: map view clustering sel_imgs g_list_find inside O(I*J) loop
* darktable-0004: pwstorage backends log credentials verbatim (CWE-312)
* darktable-0005: modulegroups test_visible O(M*G*P) per UI refresh
*/
public class DarktableTest {
@ -151,12 +153,129 @@ public class DarktableTest {
System.out.println(" PASS");
}
// ---------------------------------------------------------------
// darktable-0004: pwstorage credential logged verbatim (CWE-312)
// ---------------------------------------------------------------
/**
* Defective: credential value logged verbatim.
* Simulates dt_print(DT_DEBUG_PWSTORAGE, "storing (%s, %s)", key, value)
* where value = {"server":"...","username":"...","password":"s3cr3t"}.
*/
static String logCredentialDefective(String key, String credentialJson) {
// Mirrors: dt_print(DT_DEBUG_PWSTORAGE, "storing (%s, %s)", key, value)
return String.format("[pwstorage_kwallet_set] storing (%s, %s)", key, credentialJson);
}
/**
* Fixed: only log the key (service name), never the value (which contains password).
* Mirrors: dt_print(DT_DEBUG_PWSTORAGE, "storing (%s, [REDACTED])", key)
*/
static String logCredentialFixed(String key, String credentialJson) {
return String.format("[pwstorage_kwallet_set] storing (%s, [REDACTED])", key);
}
static void testPwstorageCredentialLog() {
String key = "example.com";
String credJson = "{\"server\":\"example.com\",\"username\":\"alice\",\"password\":\"s3cr3t\"}";
String defectLog = logCredentialDefective(key, credJson);
String fixedLog = logCredentialFixed(key, credJson);
boolean defectExposesPassword = defectLog.contains("s3cr3t");
boolean fixedExposesPassword = fixedLog.contains("s3cr3t");
System.out.printf("darktable-0004 pwstorage CWE-312: defect_exposes=%b fixed_exposes=%b%n",
defectExposesPassword, fixedExposesPassword);
assert defectExposesPassword : "Defective log should expose password";
assert !fixedExposesPassword : "Fixed log must NOT expose password";
assert fixedLog.contains("[REDACTED]") : "Fixed log must contain [REDACTED]";
System.out.println(" PASS");
}
// ---------------------------------------------------------------
// darktable-0005: modulegroups test_visible O(M*G*P) vs O(M)
// ---------------------------------------------------------------
/**
* Defective: for each of M modules, iterate G groups, each doing linear scan of P items.
* Mirrors _lib_modulegroups_test_visible called inside _lib_modulegroups_update_iop_visibility.
*/
static int modulegroupsTestVisibleDefective(List<String> iopModules,
List<List<String>> groups) {
int ops = 0;
for (String module : iopModules) {
// _lib_modulegroups_test_visible inner loop
for (List<String> group : groups) {
for (String gm : group) {
ops++;
if (gm.equals(module)) break;
}
}
}
return ops;
}
/**
* Fixed: precompute a Set of all visible module names across groups.
* test_visible = O(1) per module.
*/
static int modulegroupsTestVisibleFixed(List<String> iopModules,
List<List<String>> groups) {
int ops = 0;
// Rebuild visible set once (done when groups change)
Set<String> visibleSet = new HashSet<>();
for (List<String> group : groups) {
for (String gm : group) {
visibleSet.add(gm);
ops++; // set build cost
}
}
// Per-update: O(M) hash lookups
for (String module : iopModules) {
visibleSet.contains(module);
ops++;
}
return ops;
}
static void testModulegroupsTestVisible() {
// 80 iop modules, 8 groups of 10 modules each
int M = 80;
int G = 8;
int P = 10;
List<String> iopModules = new ArrayList<>();
for (int i = 0; i < M; i++) iopModules.add("module_" + i);
List<List<String>> groups = new ArrayList<>();
for (int g = 0; g < G; g++) {
List<String> group = new ArrayList<>();
for (int p = 0; p < P; p++) {
// Distribute modules evenly across groups
group.add("module_" + (g * P + p));
}
groups.add(group);
}
int defectOps = modulegroupsTestVisibleDefective(iopModules, groups);
int fixedOps = modulegroupsTestVisibleFixed(iopModules, groups);
double ratio = (double) defectOps / fixedOps;
System.out.printf("darktable-0005 modulegroups test_visible: defect=%d fixed=%d ratio=%.1fx%n",
defectOps, fixedOps, ratio);
assert ratio > 3.0 : "Expected >3x ratio, got " + ratio;
System.out.println(" PASS");
}
// ---------------------------------------------------------------
public static void main(String[] args) {
testMapLocationDiff();
testTagAddToList();
testMapViewCluster();
System.out.println("\nAll 3 darktable CWE-407 tests PASSED.");
testPwstorageCredentialLog();
testModulegroupsTestVisible();
System.out.println("\nAll 5 darktable tests PASSED.");
}
}