164 lines
5.4 KiB
Java
164 lines
5.4 KiB
Java
/**
|
|
* CWE-407 simulation tests for ImageMagick defects.
|
|
*
|
|
* imagemagick-0001: UHDR coder GetImageListLength() O(N) called N times in loop = O(N^2)
|
|
* imagemagick-0002: SyncImageList nested loop scene-number duplicate check = O(N^2)
|
|
*/
|
|
public class ImageMagickTest {
|
|
|
|
// ---------------------------------------------------------------
|
|
// imagemagick-0001: UHDR GetImageListLength in loop
|
|
// ---------------------------------------------------------------
|
|
|
|
/** Simulate a doubly-linked image list */
|
|
static class ImageNode {
|
|
int scene;
|
|
int depth;
|
|
ImageNode next;
|
|
ImageNode previous;
|
|
|
|
ImageNode(int scene, int depth) {
|
|
this.scene = scene;
|
|
this.depth = depth;
|
|
}
|
|
}
|
|
|
|
static ImageNode buildImageList(int n) {
|
|
ImageNode head = new ImageNode(0, 8);
|
|
ImageNode prev = head;
|
|
for (int i = 1; i < n; i++) {
|
|
ImageNode node = new ImageNode(i, 8);
|
|
node.previous = prev;
|
|
prev.next = node;
|
|
prev = node;
|
|
}
|
|
return head;
|
|
}
|
|
|
|
/** O(N) traversal — simulates GetImageListLength */
|
|
static int getImageListLength(ImageNode image) {
|
|
// Go to end first
|
|
ImageNode p = image;
|
|
while (p.next != null) p = p.next;
|
|
// Count backwards
|
|
int count = 0;
|
|
while (p != null) {
|
|
count++;
|
|
p = p.previous;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/** DEFECTIVE: calls getImageListLength inside loop = O(N^2) */
|
|
static long writeUhdrDefective(ImageNode image) {
|
|
long ops = 0;
|
|
for (int i = 0; i < getImageListLength(image); i++) {
|
|
ops += getImageListLength(image); // count traversal ops
|
|
// simulate per-frame work
|
|
if (image.next != null) image = image.next;
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
/** FIXED: cache length before loop = O(N) */
|
|
static long writeUhdrFixed(ImageNode image) {
|
|
long ops = 0;
|
|
int numberScenes = getImageListLength(image);
|
|
ops += numberScenes; // one traversal
|
|
for (int i = 0; i < numberScenes; i++) {
|
|
ops++; // per-frame work
|
|
if (image.next != null) image = image.next;
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
static void testUhdrGetImageListLength() {
|
|
int N = 500;
|
|
ImageNode list = buildImageList(N);
|
|
|
|
long defectOps = writeUhdrDefective(list);
|
|
long fixedOps = writeUhdrFixed(buildImageList(N));
|
|
double ratio = (double) defectOps / fixedOps;
|
|
|
|
System.out.printf("imagemagick-0001 UHDR GetImageListLength in loop:%n");
|
|
System.out.printf(" N=%d defect_ops=%d fixed_ops=%d ratio=%.1fx%n",
|
|
N, defectOps, fixedOps, ratio);
|
|
assert ratio > 50.0 : "Expected significant overhead ratio, got " + ratio;
|
|
System.out.println(" PASS");
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// imagemagick-0002: SyncImageList O(N^2) scene dedup
|
|
// ---------------------------------------------------------------
|
|
|
|
/** DEFECTIVE: nested loop duplicate scene check O(N^2) */
|
|
static long syncImageListDefective(ImageNode images) {
|
|
long ops = 0;
|
|
ImageNode p, q;
|
|
boolean hasDup = false;
|
|
for (p = images; p != null; p = p.next) {
|
|
for (q = p.next; q != null; q = q.next) {
|
|
ops++;
|
|
if (p.scene == q.scene) {
|
|
hasDup = true;
|
|
break;
|
|
}
|
|
}
|
|
if (hasDup) break;
|
|
}
|
|
if (!hasDup) {
|
|
// scenes are unique — no renumbering needed (worst case: full scan)
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
/** FIXED: single-pass sequential check O(N) */
|
|
static long syncImageListFixed(ImageNode images) {
|
|
long ops = 0;
|
|
if (images == null || images.next == null) return 0;
|
|
boolean needsRenumber = false;
|
|
int expected = images.scene;
|
|
for (ImageNode p = images.next; p != null; p = p.next) {
|
|
ops++;
|
|
expected++;
|
|
if (p.scene != expected) {
|
|
needsRenumber = true;
|
|
break;
|
|
}
|
|
}
|
|
if (needsRenumber) {
|
|
for (ImageNode p = images.next; p != null; p = p.next) {
|
|
ops++;
|
|
p.scene = p.previous.scene + 1;
|
|
}
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
static void testSyncImageListDedup() {
|
|
int N = 1000;
|
|
// Build list with unique sequential scenes (worst case for defective)
|
|
ImageNode list = buildImageList(N);
|
|
long defectOps = syncImageListDefective(list);
|
|
|
|
ImageNode list2 = buildImageList(N);
|
|
long fixedOps = syncImageListFixed(list2);
|
|
double ratio = (double) defectOps / fixedOps;
|
|
|
|
System.out.printf("imagemagick-0002 SyncImageList scene dedup:%n");
|
|
System.out.printf(" N=%d defect_ops=%d fixed_ops=%d ratio=%.1fx%n",
|
|
N, defectOps, fixedOps, ratio);
|
|
assert ratio > 100.0 : "Expected significant overhead ratio, got " + ratio;
|
|
System.out.println(" PASS");
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// Main
|
|
// ---------------------------------------------------------------
|
|
|
|
public static void main(String[] args) {
|
|
testUhdrGetImageListLength();
|
|
testSyncImageListDedup();
|
|
System.out.println("\nAll ImageMagick CWE-407 tests PASS");
|
|
}
|
|
}
|