import java.util.*; /** * CWE-407 unit test for Redis acl.c defect. * * redis-0001: src/acl.c getUpcomingChannelList() * list *upcoming built from new ACL channels, then checked with * listSearchKey(upcoming, channel) — O(U) per original channel, O(C×U) total. * Fix: build dict *upcoming_set alongside list for O(1) exact-match lookup. */ public class RedisTest { // Simulate listSearchKey approach (defect) static boolean isChannelInUpcomingList(List upcoming, String channel) { for (String c : upcoming) { // O(U) linear scan if (c.equals(channel)) return true; } return false; } static boolean getUpcomingChannelList_list(List newChannels, List originalChannels) { // Build upcoming list (O(U)) List upcoming = new ArrayList<>(newChannels); // Check each original channel against upcoming: O(C × U) boolean match = true; for (String ch : originalChannels) { if (!isChannelInUpcomingList(upcoming, ch)) { match = false; break; } } return match; } // Simulate dict/set approach (fix) static boolean getUpcomingChannelList_dict(List newChannels, List originalChannels) { // Build upcoming set for O(1) lookup Set upcoming_set = new HashSet<>(newChannels); boolean match = true; for (String ch : originalChannels) { if (!upcoming_set.contains(ch)) { // O(1) lookup match = false; break; } } return match; } static void testRedis0001() throws Exception { int U = 1000; // upcoming channels (new ACL) int C = 1000; // original channels to check List newChannels = new ArrayList<>(); for (int i = 0; i < U; i++) newChannels.add("chan:" + i); // original channels: 500 overlap + 500 new (forces full scan in list version) List originalChannels = new ArrayList<>(); for (int i = 0; i < C / 2; i++) originalChannels.add("chan:" + i); for (int i = 0; i < C / 2; i++) originalChannels.add("extra:" + i); // correctness boolean r1 = getUpcomingChannelList_list(newChannels, originalChannels); boolean r2 = getUpcomingChannelList_dict(newChannels, originalChannels); assert r1 == r2 : "list and dict must agree: " + r1 + " vs " + r2; // performance long t0 = System.nanoTime(); for (int r = 0; r < 500; r++) getUpcomingChannelList_list(newChannels, originalChannels); long tList = System.nanoTime() - t0; t0 = System.nanoTime(); for (int r = 0; r < 500; r++) getUpcomingChannelList_dict(newChannels, originalChannels); long tDict = System.nanoTime() - t0; double ratio = (double) tList / tDict; System.out.printf("redis-0001: list=%.3fs dict=%.3fs ratio=%.1f×%n", tList / 1e9, tDict / 1e9, ratio); assert ratio > 3 : "Expected >3× speedup, got " + ratio; System.out.println("PASS redis-0001"); } public static void main(String[] args) throws Exception { testRedis0001(); System.out.println("ALL PASS"); } }