【问题标题】:Sonar Violation: Security - Array is stored directly声纳违规:安全 - 阵列直接存储
【发布时间】:2012-07-19 19:47:23
【问题描述】:

存在声纳违规:

声纳违规:安全 - 阵列直接存储

public void setMyArray(String[] myArray) { 
  this.myArray = myArray; 
} 

解决方案:

public void setMyArray(String[] newMyArray) { 
  if(newMyArray == null) { 
    this.myArray = new String[0]; 
  } else { 
   this.myArray = Arrays.copyOf(newMyArray, newMyArray.length); 
  } 
}

但我想知道为什么?

【问题讨论】:

  • 嗯...实际上,该解决方案对我不起作用。尽管制作了副本,Sonar 仍然拿起它并抱怨它。
  • @ndtreviv 你是怎么解决的?
  • @ndtreviv:我也遇到了这个问题,如果提供给方法的局部变量的名称与您存储的实例变量相同,则此错误不会消失。确保它们不同,并且上述解决方案应该有效。我通过以下link 发现了这一点
  • Java 绝对应该发明const 以避免复制受此 d*** 规则强制的 const 数据。

标签: java sonarqube


【解决方案1】:

它抱怨您存储的数组与调用者持有的数组相同。也就是说,如果调用者随后修改了这个数组,那么存储在对象中的数组(以及对象本身)将会改变。

解决方案是在对象被传递时在对象内进行复制。这称为防御性复制。对集合的后续修改不会影响存储在对象中的数组。

通常在返回集合时执行此操作也是一种好习惯(例如,在相应的 getMyArray() 调用中)。否则接收者可能会执行修改并影响存储的实例。

请注意,这显然适用于所有可变集合(实际上是所有可变对象)——不仅仅是数组。另请注意,这会对性能产生影响,需要与其他问题一起评估。

【讨论】:

  • 我可以看到原因....如果我故意希望调用者和它的目标持有相同的副本怎么办?
  • 这是一个设计决定。但我认为了解 拥有这些数据以及如何(如有必要)通知持有它的对象它已更改是很重要的。在没有防御性复制的情况下传递集合密切相关的组件集是非常合理的。但在某些时候,您需要保护自己的边界(例如插入第三方或客户的代码)
  • 肯定 OP 正在this.myArray = Arrays.copyOf(newMyArray, newMyArray.length);制作防御性副本?
  • 我也不明白为什么它只是显示数组。因为,在一个 bean 中,我们将有自定义对象和相同的问题(调用者将持有相同的副本,如果他更改,它将影响内部)可能会发生,但它不会抱怨。
  • @Manoj 可能是因为声纳不知道对象是否可变。对于不可变对象,不必担心某些其他类可能会意外地更改对象的状态。数组不可能是不可变的,所以声纳知道一直标记它们
【解决方案2】:

这称为防御性复制。关于该主题的一篇不错的文章是 Brian Goetz 的 "Whose object is it, anyway?",它讨论了 getter 和 setter 的值和引用语义之间的区别。

基本上,引用语义(没有副本)的风险是您错误地认为您拥有该数组,并且当您修改它时,您还修改了具有该数组别名的其他结构。您可以在网上找到许多关于防御性复制和对象别名相关问题的信息。

【讨论】:

  • 感谢队友,投赞成票。能不能举个小例子,或者把原因压缩在50字以内?
  • @ewernli :链接已损坏,请修复。谢谢!
  • @ewernli :是的,谢谢!
【解决方案3】:

我遇到了同样的问题:

安全性 - 数组直接存储用户提供的数组 'palomitas' 直接存储。

我原来的方法:

public void setCheck(boolean[] palomitas) {
        this.check=palomitas;
    }

固定转为:

public void setCheck(boolean[] palomitas) { 
      if(palomitas == null) { 
        this.check = new boolean[0]; 
      } else { 
       this.check = Arrays.copyOf(palomitas, palomitas.length); 
      } 
}

其他例子:

安全性 - 数组直接存储用户提供的数组

private String[] arrString;

    public ListaJorgeAdapter(String[] stringArg) {      
        arrString = stringArg;
    }

固定:

public ListaJorgeAdapter(String[] stringArg) {  
    if(stringArg == null) { 
      this.arrString = new String[0]; 
    } else { 
      this.arrString = Arrays.copyOf(stringArg, stringArg.length); 
    } 
}

【讨论】:

    【解决方案4】:

    要消除它们,您必须在存储/返回之前克隆数组,如以下类实现所示,因此没有人可以修改或获取您的类的原始数据,而只能是它们的副本。

    public byte[] getarrString() {
        return arrString.clone();
    }
    /**
     * @param arrStringthe arrString to set
     */
    public void arrString(byte[] arrString) {
        this.arrString= arrString.clone();
    }
    

    我是这样使用它的,现在我没有收到任何违反声纳的行为......

    【讨论】:

      【解决方案5】:

      这比这一切都更容易。您只需要将方法参数重命名为其他任何内容即可避免 Sonar 违规。

      http://osdir.com/ml/java-sonar-general/2012-01/msg00223.html

      public void setInventoryClassId(String[] newInventoryClassId)
          {                
                  if(newInventoryClassId == null)
                  {
                          this.inventoryClassId = new String[0];
                  }
                  else
                  {
                          this.inventoryClassId = Arrays.copyOf(newInventoryClassId, newInventoryClassId.length);
                  }
      
          } 
      

      【讨论】:

        【解决方案6】:

        采用防御性实施方式可以为您节省大量时间。 在 Guava 中,您可以获得另一个很好的解决方案来实现目标:ImmutableCollections

        http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained

        【讨论】:

          【解决方案7】:

          在某些情况下,这是一个设计决策,不容错过。在这些情况下,您需要修改 Sonar 规则以将其排除,以便它不会在报告中显示此类问题。

          【讨论】:

            猜你喜欢
            • 2015-05-10
            • 1970-01-01
            • 2014-06-16
            • 2014-07-25
            • 1970-01-01
            • 1970-01-01
            • 2014-05-17
            • 1970-01-01
            相关资源
            最近更新 更多