SonarQube扫描常见Bug、漏洞修复整理

1.类中方法全为静态方法时,私有化构造器

 问题样例

class StringUtils { // Noncompliant

  public static String concatenate(String s1, String s2) {
    return s1 + s2;
  }

}

原因:当类中的方法全部都是 static 关键字修饰时 ,它的构造方法最好作为 private 私有化,理由是方法全是 static, 不知道的人会去new对象去调用,需要调用构造方法。 但 static的方法直接用类名调用就行!

 解决样例

class StringUtils { // Compliant

  private StringUtils() {
    throw new IllegalStateException("Utility class");
  }

  public static String concatenate(String s1, String s2) {
    return s1 + s2;
  }

}

2.多个异常使用多个方法块捕获

问题样例

try {
  /* ... */
} catch (Exception e) {
  if(e instanceof IOException) { /* ... */ }         // Noncompliant
  if(e instanceof NullPointerException{ /* ... */ }  // Noncompliant
}

原因:应使用适当类型的多个捕获块,而不是捕获一般异常,然后对该类型进行测试。

 解决样例

class MyClass {
   private int my_field;
}

3.命名规范

问题样例

class MyClass {
   private int my_field;
}

原因:共享一些命名约定是团队高效协作的关键。此规则允许检查字段名是否与提供的正则表达式匹配。驼峰命名

解决样例 

class MyClass {
   private int myField;
}

4.泛型定义具体类型

问题样例

List myList; // Noncompliant
Set mySet; // Noncompliant

原因:提供此泛型的参数化类型。

 解决样例

List<String> myList;
Set<? extends Number> mySet;

5.移除未使用的变量、注释的代码

public int numberOfMinutes(int hours) {
  int seconds = 0;   // seconds is never used
  return hours * 60;
}

public int numberOfMinutes(int hours) {
  int seconds = 0;   // seconds is never used
  return hours * 60;
}

原因:删掉注释的代码行、未使用的变量、私有方法等、移除未使用的变量

public int numberOfMinutes(int hours) {
  return hours * 60;
}

public int numberOfMinutes(int hours) {
  return hours * 60;
}

6.常见空指针异常

String path = null;
path = UploadConfigurationRead.getInstance().getConfigItem(toUploadPath).trim();
			if(path != null){
				flag = "0";
			}else{
				flag = "1";
			}
fileType = path.substring(path.length()-1,path.length());



String errNode = hyperV(document.selectSingleNode("//responseMessage"));
errNode = convterEcfErrCode(errNode);

原因:常见的空指针异常

String path = null;
path = UploadConfigurationRead.getInstance().getConfigItem(toUploadPath).trim();
			if(path != null){
				flag = "0";
				fileType = path.substring(path.length()-1,path.length());
			}else{
				flag = "1";
				fileType = path.substring(path.length()-1,path.length());
			}

if(errNode==null) ///99999,无返回提示
				errCode = "99999-无提示";
			else{
				errCode=convterEcfErrCode(errNode);
			}

7.静态变量使用规范

public class MyClass {
  public static final int SOME_CONSTANT = 0;     // Compliant - constants are not checked
  public String firstName;                       // Noncompliant

}

原因:静态变量加final、驼峰命名、或者使用私有变量并提供方法访问

public class MyClass {
  public static final int SOME_CONSTANT = 0;     // Compliant - constants are not checked
  private String firstName;                      // Compliant
  public String getFirstName() {
    return firstName;
  }

8.集合使用建议

Vector cats = new Vector();

原因:Java API的早期类(如Vector、Hashtable和StringBuffer)被同步以使其线程安全。不幸的是,同步对性能有很大的负面影响,即使在从单个线程使用这些集合时也是如此。

最好使用新的非同步替换:

ArrayList或LinkedList而不是Vector

Deque而不是Stack

HashMap而不是Hashtable

StringBuilder而不是StringBuffer

即使在同步上下文中使用,在使用它之前也应该三思,因为它的用法可能很棘手。如果您确信使用是合法的,则可以安全地忽略此警告。

ArrayList cats = new ArrayList();

//这些同步类的使用在重写方法的签名中被忽略。
@Override
public Vector getCats() {...}

9.定义专用异常

public void foo(String bar) throws Throwable {  // Noncompliant
  throw new RuntimeException("My Message");     // Noncompliant
}

原因:定义并抛出专用异常,而不是使用通用异常。

public void foo(String bar) {
  throw new MyOwnRuntimeException("My Message");
}

10.IO等资源的正确使用

private void readTheFile() throws IOException {
  Path path = Paths.get(this.fileName);
  BufferedReader reader = Files.newBufferedReader(path, this.charset);
  // ...
  reader.close();  // Noncompliant
  // ...
  Files.lines("input.txt").forEach(System.out::println); // Noncompliant: The stream needs to be closed
}

@CheckForNull
String getName(){...}

public boolean isNameEmpty() {
  return getName().length() == 0; // Noncompliant; the result of getName() could be null, but isn't null-checked
}

Connection conn = null;
Statement stmt = null;
try{
  conn = DriverManager.getConnection(DB_URL,USER,PASS);
  stmt = conn.createStatement();
  // ...

}catch(Exception e){
  e.printStackTrace();
}finally{
  stmt.close();   // Noncompliant; stmt could be null if an exception was thrown in the try{} block
  conn.close();  // Noncompliant; conn could be null if an exception was thrown
}

原因:1.IO资源未使用try()catch包裹 2.资源未正确关闭

绝不应取消引用/访问对null的引用。这样做将导致引发NullPointerException。充其量,这种异常会导致程序突然终止。最坏的情况是,它可能会暴露对攻击者有用的调试信息,或者允许攻击者绕过安全措施。

请注意,当它们出现时,该规则利用JSR-305中定义的@CheckForNull和@Nonnull注释来了解哪些值是可为null的,哪些值不可为null,除非@Nonnull用于equals的参数,根据约定,这些值应始终与null一起工作。

IO资源应该在使用后关闭。在try语句中使用了Connections, streams, files等,这些类实现了Closeable 或者AutoCloseable接口,必须在finally块中关闭,否则,如果出现异常就可能无法关闭。对于实现了AutoCloseable接口的类,最好使用“try-with-resource”语句来自动关闭。如果不能正确地关闭资源,就会导致资源泄漏,这可能会导致应用程序甚至整个系统的崩溃。

关于IO资源的处理问题,以下比较三种解决方案。

close()放在try块中

close()放在finally块中

使用try-with-resource语句

方法一 jdk1.7前推荐
PrintWriter out = null;
try {
    out = new PrintWriter(
        new BufferedWriter(
        new FileWriter("out.txt", true)));
    out.println("the text");
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (out != null) {
        out.close();
    }


方法二 jdk1.8实现了AutoCloseable接推荐
//try-with-resource statement
try (PrintWriter out2 = new PrintWriter(
            new BufferedWriter(
            new FileWriter("out.txt", true)))) {
    out2.println("the text");
} catch (IOException e) {
    e.printStackTrace();
}

11.浮点数的使用

double d = 1.1;

BigDecimal bd1 = new BigDecimal(d); // Noncompliant; see comment above
BigDecimal bd2 = new BigDecimal(1.1); // Noncompliant; same result

原因:由于浮点不精确,您不太可能从BigDecimal(double)构造函数中获得所需的值。相反,您应该使用BigDecimal.valueOf,它在封面下使用字符串来消除浮点舍入错误,或者使用string参数的构造函数

double d = 1.1;

BigDecimal bd1 = BigDecimal.valueOf(d);
BigDecimal bd2 = new BigDecimal("1.1"); // using String constructor will result in precise value

12.数据计算及数据类型转换

float twoThirds = 2/3; // Noncompliant; int division. Yields 0.0
long millisInYear = 1_000*3_600*24*365; // Noncompliant; int multiplication. Yields 1471228928
long bigNum = Integer.MAX_VALUE + 2; // Noncompliant. Yields -2147483647
long bigNegNum =  Integer.MIN_VALUE-1; //Noncompliant, gives a positive result instead of a negative one.
Date myDate = new Date(seconds * 1_000); //Noncompliant, won't produce the expected result if seconds > 2_147_483

原因:当对整数执行算术运算时,结果将始终是整数。您可以通过自动类型转换将该结果分配给long、double或float,但如果以int或long开头,则结果可能不是您期望的结果。例如,如果将int除法的结果分配给浮点变量,则在分配之前精度将丢失。同样,如果乘法的结果被分配给long,那么在分配之前它可能已经溢出。无论哪种情况,结果都不会像预期的那样。相反,在操作发生之前,应至少将一个操作数强制转换或提升为最终类型。总的来说,要么强制转换,要么将其中一个变量提升

float twoThirds = 2f/3; // 2 promoted to float. Yields 0.6666667
float twoThirds = (float)2/3; // 2 cast to float
long millisInYear = (long)1_000*3_600*24*365; // 1_000 cast to long
long bigNum = (long)Integer.MAX_VALUE + 2;

13. ==比较

String firstName = getFirstName(); // String overrides equals
String lastName = getLastName();

if (firstName == lastName) { ... }; // Non-compliant; false even if the strings have the same value

原因:使用引用等式==或!=来比较java.lang.String或java.lang.Integer等装箱类型的两个实例几乎总是错误的,因为它不是比较实际值,而是比较内存中的位置。

String firstName = getFirstName();
String lastName = getLastName();

if (firstName != null && firstName.equals(lastName)) { ... };

14. 不同类型的比较判断

InvDetail invDetail = new InvDetail();

if(null != invDetail && !"".equals(invDetail)){

}

原因:删除对“equals”的调用;不相关类型之间的比较总是返回false。

InvDetail invDetail = new InvDetail();
if(null != invDetail)){

}

15.循环中break的使用

for (int i = 0; i < 10; i++) { // noncompliant, loop only executes once
  printf("i is %d", i);
  break;
}

原因:一次循环建议使用if。如果在循环中使用break,建议加上判断条件

for (int i = 0; i < 10; i++) {
  if (i == x) {
    break;
  } else {
    printf("i is %d", i);
  }
}

16.条件判断的注意事项

//什么都没做
if(resultMap!=null){
     if(PUBParm.RT_STATE_N.equals(resultMap.get("state"))){
     }else{
     }
}else{
}

//做了一样的事情
if (b == 0) {  // Noncompliant
  doOneMoreThing();
} else {
  doOneMoreThing();
}

//条件判断后 永远只进入一个分支
int b = a > 12 ? 4 : 4;  // Noncompliant

switch (i) {  // Noncompliant
  case 1:
    doSomething();
    break;
  case 2:
    doSomething();
    break;
  case 3:
    doSomething();
    break;
  default:
    doSomething();
}

17.左右运算符条件一致

if(!sts.equals("8")&&!sts.equals("8")){}

if ( a == b && a == b ) { // if the first one is true, the second one is too
  doX();
}

if(flag =0 0)

原因:运算符左右条件一致,更新判定条件

18.对于InterruptedExceptions的处理

public void run () {
  try {
    while (true) {
      // do stuff
    }
  }catch (InterruptedException e) { // Noncompliant; logging is not enough
    LOGGER.log(Level.WARN, "Interrupted!", e);
  }
}

 try {
    while (true) {
      // do stuff
    }
	latch.await();
		} catch (Exception e) {
Either re-interrupt this method or rethrow the "InterruptedException" that can be caught here.
			e.printStackTrace();
			throw new ServiceException(e.getMessage());
		}
		return ipg;

原因:代码中决不应忽略InterruptedExceptions,在这种情况下,只需将异常计数记录为“忽略”即可。抛出InterruptedException将清除线程的中断状态,因此如果异常处理不当,则线程被中断的信息将丢失。相反,InterruptedExceptions应该立即或在清理方法状态后重新抛出,或者通过调用thread.crupt()来重新中断线程,即使这是一个单线程应用程序。任何其他操作过程都有延迟线程关闭的风险,并丢失线程被中断的信息——可能没有完成任务。

同样,也应传播ThreadDeath异常。根据其JavaDoc:如果ThreadDeath被某个方法捕获,则必须对其进行重新处理,以使线程实际死亡。

public void run () {
  try {
    while (true) {
      // do stuff
    }
  }catch (InterruptedException e) {
    LOGGER.log(Level.WARN, "Interrupted!", e);
    // Restore interrupted state...
    Thread.currentThread().interrupt();
  }
}

19.fianlly块中不应使用retrun、break等语句

public static void main(String[] args) {
  try {
    doSomethingWhichThrowsException();
    System.out.println("OK");   // incorrect "OK" message is printed
  } catch (RuntimeException e) {
    System.out.println("ERROR");  // this message is not shown 
  }
}

public static void doSomethingWhichThrowsException() {
  try {
    throw new RuntimeException();
  } finally {
    for (int i = 0; i < 10; i ++) {
      //...
      if (q == i) {
        break; // ignored
      }
    }

    /* ... */
    return;      // Noncompliant - prevents the RuntimeException from being propagated
  }
}

原因:使用finally块中的return、break、throw等将抑制try或catch块中引发的任何未处理Throwable的传播。当跳转语句(break、continue、return、throw和goto)将强制控制流离开finally块时,此规则会引发问题。

public static void main(String[] args) {
  try {
    doSomethingWhichThrowsException();
    System.out.println("OK");
  } catch (RuntimeException e) {
    System.out.println("ERROR");  // "ERROR" is printed as expected
  }
}

public static void doSomethingWhichThrowsException() {
  try {
    throw new RuntimeException();
  } finally {
    for (int i = 0; i < 10; i ++) {
      //...
      if (q == i) {
        break; // ignored
      }
    }

    /* ... */
  }
}

20.根据函数返回的状态进行操作

 if (zipFile.exists()) { 
    zipFile.delete();
  }
  zipFile.createNewFile();

原因:

当函数调用的返回值包含操作状态代码时,应测试该值以确保操作成功完成。

当忽略以下项的返回值时,此规则会引发问题:

  • java.io.返回状态代码的文件操作(mkdirs除外)
  • 迭代器hasNext()
  • 枚举.hhasMoreElements()
  • Lock.tryLock()
  • 非void Condition.await*方法
  • CountDownLatch.await(long,TimeUnit)
  • Semaphore.try获取
  • BlockingQueue:提供,删除

可以直接根据调用函数返回的状态码值进行下一步操作

 if (!zipFile.delete();) { 
     zipFile.createNewFile();
  }
 

21.compareTo方法在判断中的使用建议

if (myClass.compareTo(arg) == -1) {  // Noncompliant
  // ...
}

原因:虽然大多数compareTo方法返回-1、0或1,但有些方法不返回,并且将compareTo的结果与0以外的特定值进行测试可能会导致错误否定。

if (myClass.compareTo(arg) < 0) {
  // ...
}

22.可能存在的1/0异常

User.numFormat(Math.abs((value - lastValue) / lastValue) * 100,2)).append("%,");

原因:要确定 lastValue不为0

if (lastValue!=0) {
 User.numFormat(Math.abs((value - lastValue) / lastValue) * 100,2)).append("%,");
}

23.重写“equals()”,因此也应重写“hashCode()

class MyClass {    // Noncompliant - should also override "hashCode()"

  @Override
  public boolean equals(Object obj) {
    /* ... */
  }

}


//代码中的具体使用
public boolean equals(Object obj) {
  return true;
}

原因:此类重写“equals()”,因此也应重写“hashCode()”。

class MyClass {    // Compliant

  @Override
  public boolean equals(Object obj) {
    /* ... */
  }

  @Override
  public int hashCode() {
    /* ... */
  }

}

24.自我赋值

public void setName(String name) {
  name = name;
}

原因:没有理由将变量重新分配给它自己。要么是多余的,应该删除,要么重新赋值是错误的,而另一个值或变量用于赋值。

public void setName(String name) {
  this.name = name;
}

25.创建变量给参数重新赋值

public void doTheThing(String str, int i, List<String> strings) {
  str = Integer.toString(i); // Noncompliant

  for (String s : strings) {
    s = "hello world"; // Noncompliant
  }

26.调用函数有返回值要接收

propDeTypes.replace("|", "");

原因:调用函数有返回值要接收,当满足以下两个条件时,此规则不会产生问题:

方法调用位于带有关联catch子句的try块中。

方法名称以“parse”、“format”、“decode”或“valueOf”开头,或者方法是String.getBytes(Charset)。

public void handle(String command){
  String formattedCommand = command.toLowerCase();
  ...
}

private boolean textIsInteger(String textToCheck) {
    try {
        Integer.parseInt(textToCheck, 10); // OK
        return true;
    } catch (NumberFormatException ignored) {
        return false;
    }
}

27.Random应当抽取使用

public void doSomethingCommon() {
  Random rand = new Random();  // Noncompliant; new instance created with each invocation
  int rValue = rand.nextInt();
  //...

原因:每次需要随机值时创建一个新的Random对象是低效的,并且可能会产生不随机的数字,具体取决于JDK。为了获得更好的效率和随机性,请创建一个Random,然后存储并重用它。Random()构造函数每次都尝试用不同的值设置种子。然而,不能保证种子是随机的,甚至是均匀分布的。有些JDK将使用当前时间作为种子,这使得生成的数字完全不是随机的。可不修改

private Random rand = SecureRandom.getInstanceStrong();  // SecureRandom is preferred to Random

public void doSomethingCommon() {
  int rValue = this.rand.nextInt();
  //...

28.Calendar等类不应当定义为静态变量

public class MyClass {
  private static SimpleDateFormat format = new SimpleDateFormat("HH-mm-ss");  // Noncompliant
  private static Calendar calendar = Calendar.getInstance();  // Noncompliant

原因:并非标准Java库中的所有类都是线程安全的。以多线程方式使用它们极有可能在运行时导致数据问题或异常。当Calendar、DateFormat、javax.xml.xpath.XXPath或javax.xml.validation.SchemaFactory的实例标记为静态时,此规则会引发问题。

DateUtil工具中使用日历变量的,建议在代码中新增,而不使用静态日历变量

public class MyClass {
  private SimpleDateFormat format = new SimpleDateFormat("HH-mm-ss");
  private Calendar calendar = Calendar.getInstance();

29.正则表达式的使用规范

private static final String CHECK_TEL_VALUE ="/^[+]{0,1}(\\d){1,3}[ ]?([-]?((\\d)|[ ]){1,12})+$/";
Pattern.compile("$[a-z]+^"); // Noncompliant

原因:在正则表达式中,边界^和\A只能在输入的开头匹配(或者,如果^与MULTILINE标志组合,则为行的开头),$、\Z和\Z只能在结尾匹配。这些模式可能会被误用,例如,通过意外切换^和$来创建一个永远无法匹配的模式。

Pattern.compile("^[a-z]+$");

30.hibernate.hbm2ddl.auto使用

<session-factory>
  <property name="hibernate.hbm2ddl.auto">update</property>  <!-- Noncompliant -->
</session-factory>

原因:对hibernate.hbm2ddl.auto使用除“validate”以外的任何值都可能导致应用程序使用的数据库架构被更改、删除或清除所有数据。简而言之,使用该属性是有风险的,并且只有在生产中使用“validate”选项时,才能使用该属性

<session-factory>
  <property name="hibernate.hbm2ddl.auto">validate</property>  <!-- Compliant -->
</session-factory>

or

<session-factory>
  <!-- Property deleted -->
</session-factory>

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值