由于移位导致循环迭代被跳过¶
ID: js/loop-iteration-skipped-due-to-shifting
Kind: problem
Security severity:
Severity: warning
Precision: high
Tags:
- correctness
Query suites:
- javascript-security-and-quality.qls
可以使用 splice
方法从数组中移除项,但在这样做时,所有后续项将被移至较低的索引。如果在迭代数组时执行此操作,则移位可能会导致循环跳过移除元素后的直接元素。
建议¶
确定循环应该执行的操作
如果目的是移除每个特定值的所有出现,则在移除元素后递减循环计数器,以抵消移位。
如果循环仅用于从数组中移除单个值,请考虑在
splice
调用后添加break
。如果循环故意跳过元素,请考虑将索引递增移动到循环体中,以便明确循环不是一个简单的数组迭代循环。
示例¶
在这个示例中,一个函数旨在从路径中移除 “..
” 部分
function removePathTraversal(path) {
let parts = path.split('/');
for (let i = 0; i < parts.length; ++i) {
if (parts[i] === '..') {
parts.splice(i, 1);
}
}
return path.join('/');
}
但是,当输入包含两个彼此相邻的 “..
” 部分时,只会移除第一个。例如,字符串 “../../secret.txt
” 将被映射到 “../secret.txt
”。在移除索引 0 处的元素后,循环计数器增加到 1,但第二个 “..
” 字符串现在已移至索引 0,因此将被跳过。
避免此问题的一种方法是在从数组中移除元素后递减循环计数器
function removePathTraversal(path) {
let parts = path.split('/');
for (let i = 0; i < parts.length; ++i) {
if (parts[i] === '..') {
parts.splice(i, 1);
--i; // adjust for array shift
}
}
return path.join('/');
}
或者,使用 filter
方法
function removePathTraversal(path) {
return path.split('/').filter(part => part !== '..').join('/');
}
参考¶
MDN: Array.prototype.splice().
MDN: Array.prototype.filter().