{"record":{"id":"bea68ecb7d5315be","repo":"shadowsocks/shadowsocks-rust","slug":"bloomfilter2","errorCode":null,"errorMessage":"BloomFilter2","messagePattern":"BloomFilter2","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/shadowsocks/src/security/replay/ppbloom.rs","lineNumber":51,"sourceCode":"    bloom_count: [usize; 2],\n    item_count: usize,\n    current: usize,\n}\n\nimpl PingPongBloom {\n    pub fn new(ty: ServerType) -> Self {\n        let (mut item_count, fp_p) = if ty.is_local() {\n            (BF_NUM_ENTRIES_FOR_CLIENT, BF_ERROR_RATE_FOR_CLIENT)\n        } else {\n            (BF_NUM_ENTRIES_FOR_SERVER, BF_ERROR_RATE_FOR_SERVER)\n        };\n\n        item_count /= 2;\n\n        Self {\n            blooms: [\n                Bloom::new_for_fp_rate(item_count, fp_p).expect(\"BloomFilter1\"),\n                Bloom::new_for_fp_rate(item_count, fp_p).expect(\"BloomFilter2\"),\n            ],\n            bloom_count: [0, 0],\n            item_count,\n            current: 0,\n        }\n    }\n\n    // Check if data in `buf` exist.\n    //\n    // Set into the current bloom filter if not exist.\n    //\n    // Return `true` if data exist in bloom filter.\n    pub fn check_and_set(&mut self, buf: &[u8]) -> bool {\n        for bloom in &self.blooms {\n            if bloom.check(buf) {\n                return true;\n            }\n        }","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks/src/security/replay/ppbloom.rs#L33-L69","documentation":"Identical to BloomFilter1 but for the second of the two rotating bloom filters in ppbloom's Self constructor. Bloom::new_for_fp_rate for the second filter failed (most commonly zero item capacity after item_count /= 2) and expect('BloomFilter2') panics.","triggerScenarios":"Public constructor Self::with_capacity with item_count 0 or 1, causing the second Bloom::new_for_fp_rate(item_count, fp_p) call to fail after the halving step.","commonSituations":"Zero/near-zero capacity settings flowing from server config; unit tests constructing Ppbloom with tiny capacities; capacity values reduced by earlier refactors without updating call sites.","solutions":["Ensure item_count is at least 2 before construction","Guard capacity at the configuration layer (minimum allowed replay filter size)","Replace expect with error propagation in a wrapper if dynamic capacities are unavoidable","Update to a shadowsocks-rust version that validates capacity in the constructor"],"exampleFix":"// before\nPpbloom::with_capacity(0, FP_P)\n// after\nif capacity < 2 { capacity = 2; }\nPpbloom::with_capacity(capacity, FP_P)","handlingStrategy":"validation","validationCode":"let item_count = item_count.max(2);\n// both bloom filters now receive at least 1 item after the internal /= 2","typeGuard":null,"tryCatchPattern":"// clamp before construction; do not attempt to catch this panic\nlet capacity = if capacity < 2 { 2 } else { capacity };","preventionTips":["Apply the same capacity floor used for BloomFilter1 to all Ppbloom constructions","Centralize Ppbloom construction behind a checked factory function","Reject capacity=0/1 in CLI/config validation with a clear message","Add regression tests for minimum-capacity construction"],"tags":["rust","shadowsocks","bloom-filter","replay-protection","panic"],"backgroundTag":"invalid-constructor-argument","analyzedSha":"8eb0f0a65b1d976ab6bed5787327ef86529b0435","analyzedAt":"2026-09-09T12:20:43.168Z","contentChangedAt":"2026-09-09T12:20:43.168Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}