mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-10 02:24:35 +08:00
- Implemented final verification tests for contentPattern to validate behavior with empty strings, dangerous patterns, and normal patterns. - Created glob pattern matching tests to verify regex conversion and matching functionality. - Developed infinite loop risk tests using Worker threads to isolate potential blocking operations. - Introduced optimized contentPattern tests to validate improvements in the findMatches function. - Added verification tests to assess the effectiveness of contentPattern optimizations. - Conducted safety tests for contentPattern to identify edge cases and potential vulnerabilities. - Implemented unrestricted loop tests to analyze infinite loop risks without match limits. - Developed tests for zero-width pattern detection logic to ensure proper handling of dangerous regex patterns.
209 lines
5.8 KiB
JavaScript
209 lines
5.8 KiB
JavaScript
/**
|
|
* 测试无限制情况下的无限循环风险
|
|
* 移除 matches.length < 10 的限制
|
|
*/
|
|
|
|
function findMatchesUnrestricted(content, pattern, maxIterations = 10000) {
|
|
try {
|
|
const regex = new RegExp(pattern, 'gm');
|
|
const matches = [];
|
|
let match;
|
|
let iterations = 0;
|
|
let lastIndex = -1;
|
|
|
|
while ((match = regex.exec(content)) !== null) {
|
|
iterations++;
|
|
|
|
// 检测是否卡在同一位置(无限循环指标)
|
|
if (match.index === lastIndex) {
|
|
return {
|
|
hasStall: true,
|
|
iterations,
|
|
stalledAt: match.index,
|
|
message: 'Detected stall - regex.exec() not advancing'
|
|
};
|
|
}
|
|
lastIndex = match.index;
|
|
|
|
// 安全限制
|
|
if (iterations > maxIterations) {
|
|
return {
|
|
exceededIterations: true,
|
|
iterations,
|
|
message: `Exceeded ${maxIterations} iterations without completion`
|
|
};
|
|
}
|
|
|
|
const lineStart = content.lastIndexOf('\n', match.index) + 1;
|
|
const lineEnd = content.indexOf('\n', match.index);
|
|
const line = content.substring(lineStart, lineEnd === -1 ? undefined : lineEnd).trim();
|
|
matches.push(line.substring(0, 200));
|
|
}
|
|
|
|
return { hasStall: false, iterations, matches, completed: true };
|
|
} catch (error) {
|
|
return { error: error.message, iterations };
|
|
}
|
|
}
|
|
|
|
console.log('=== 无限循环风险详细分析 ===\n');
|
|
console.log('测试不受限制的 findMatches 行为(无 matches.length < 10 限制)\n');
|
|
|
|
const tests = [
|
|
{
|
|
name: '正常模式 - 应该正常完成',
|
|
content: 'Line 1\nLine 2\nLine 3',
|
|
pattern: 'Line',
|
|
expected: '正常'
|
|
},
|
|
{
|
|
name: '空字符串模式 - 卡住风险',
|
|
content: 'Line 1\nLine 2',
|
|
pattern: '',
|
|
expected: '卡住或高迭代'
|
|
},
|
|
{
|
|
name: '零宽匹配 - 卡住风险',
|
|
content: 'abc\ndef',
|
|
pattern: 'x*',
|
|
expected: '卡住或高迭代'
|
|
},
|
|
{
|
|
name: '或运算符空匹配 - 卡住风险',
|
|
content: 'test',
|
|
pattern: 'a|',
|
|
expected: '卡住或高迭代'
|
|
}
|
|
];
|
|
|
|
for (const test of tests) {
|
|
console.log(`\n${'='.repeat(60)}`);
|
|
console.log(`测试: ${test.name}`);
|
|
console.log(`内容: "${test.content}"`);
|
|
console.log(`模式: "${test.pattern}"`);
|
|
console.log(`预期: ${test.expected}`);
|
|
|
|
const result = findMatchesUnrestricted(test.content, test.pattern, 1000);
|
|
|
|
if (result.hasStall) {
|
|
console.log(`❌ 检测到卡住!`);
|
|
console.log(` 迭代次数: ${result.iterations}`);
|
|
console.log(` 卡在位置: ${result.stalledAt}`);
|
|
console.log(` 原因: ${result.message}`);
|
|
} else if (result.exceededIterations) {
|
|
console.log(`❌ 超过迭代限制!`);
|
|
console.log(` 迭代次数: ${result.iterations}`);
|
|
console.log(` 原因: ${result.message}`);
|
|
} else if (result.error) {
|
|
console.log(`⚠️ 错误: ${result.error}`);
|
|
} else {
|
|
console.log(`✅ 正常完成`);
|
|
console.log(` 迭代次数: ${result.iterations}`);
|
|
console.log(` 匹配数量: ${result.matches.length}`);
|
|
}
|
|
}
|
|
|
|
console.log(`\n${'='.repeat(60)}`);
|
|
console.log('\n结论:\n');
|
|
|
|
const dangerousPatterns = [
|
|
{
|
|
pattern: '"" (空字符串)',
|
|
risk: '每次匹配空字符串,前进 0 字符',
|
|
behavior: '无限循环或极高迭代次数'
|
|
},
|
|
{
|
|
pattern: '"x*" (零宽量词)',
|
|
risk: '匹配 0 个或多个,可能匹配空字符串',
|
|
behavior: '在非 "x" 字符处无限循环'
|
|
},
|
|
{
|
|
pattern: '"a|" (或空)',
|
|
risk: '总是能匹配(至少匹配空)',
|
|
behavior: '每个字符位置都匹配一次'
|
|
},
|
|
{
|
|
pattern: '"(?=...)" (零宽断言)',
|
|
risk: '断言不消耗字符',
|
|
behavior: '如果断言总是成功,会卡住'
|
|
}
|
|
];
|
|
|
|
dangerousPatterns.forEach((d, i) => {
|
|
console.log(`${i + 1}. ${d.pattern}`);
|
|
console.log(` 风险: ${d.risk}`);
|
|
console.log(` 行为: ${d.behavior}`);
|
|
console.log('');
|
|
});
|
|
|
|
console.log('当前实现的保护措施:');
|
|
console.log('- ✅ 有 matches.length < 10 限制(但不够)');
|
|
console.log('- ❌ 没有迭代计数器');
|
|
console.log('- ❌ 没有位置前进检查');
|
|
console.log('- ❌ 没有超时保护');
|
|
console.log('- ❌ 没有模式验证');
|
|
|
|
console.log('\n建议的修复方案:');
|
|
console.log(`
|
|
function findMatches(content: string, pattern: string): string[] {
|
|
try {
|
|
// 1. 验证模式
|
|
if (!pattern || pattern.length === 0) {
|
|
throw new Error('Pattern cannot be empty');
|
|
}
|
|
|
|
// 2. 检查危险模式
|
|
const dangerousPatterns = ['', '.*', 'x*', 'a|', '(?='];
|
|
if (dangerousPatterns.includes(pattern)) {
|
|
throw new Error(\`Dangerous pattern: \${pattern}\`);
|
|
}
|
|
|
|
const regex = new RegExp(pattern, 'gm');
|
|
const matches = [];
|
|
const seen = new Set<string>(); // 去重
|
|
let match;
|
|
let iterations = 0;
|
|
let lastIndex = -1;
|
|
const MAX_ITERATIONS = 1000;
|
|
|
|
while ((match = regex.exec(content)) !== null &&
|
|
matches.length < 10) {
|
|
iterations++;
|
|
|
|
// 3. 迭代计数器保护
|
|
if (iterations > MAX_ITERATIONS) {
|
|
throw new Error(\`Pattern exceeded \${MAX_ITERATIONS} iterations\`);
|
|
}
|
|
|
|
// 4. 位置前进检查
|
|
if (match.index === lastIndex) {
|
|
// 正则没有前进,强制前进
|
|
regex.lastIndex = match.index + 1;
|
|
continue;
|
|
}
|
|
lastIndex = match.index;
|
|
|
|
// 获取匹配行
|
|
const lineStart = content.lastIndexOf('\\n', match.index) + 1;
|
|
const lineEnd = content.indexOf('\\n', match.index);
|
|
const line = content.substring(
|
|
lineStart,
|
|
lineEnd === -1 ? undefined : lineEnd
|
|
).trim();
|
|
|
|
// 5. 去重
|
|
if (!seen.has(line)) {
|
|
seen.add(line);
|
|
matches.push(line.substring(0, 200));
|
|
}
|
|
}
|
|
|
|
return matches;
|
|
} catch (error) {
|
|
// 6. 返回错误信息而不是静默失败
|
|
console.error(\`Pattern search failed: \${error.message}\`);
|
|
return [];
|
|
}
|
|
}
|
|
`);
|