CodeQL 文档

由于移位导致循环迭代被跳过

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

点击查看 CodeQL 代码库中的查询

可以使用 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('/');
}

参考

  • ©GitHub, Inc.
  • 条款
  • 隐私