Java


JAVA.CONCURRENCY.UG.METH : Unguarded Method (Java)

要旨

A public or protected method or constructor might be called without the expected lock being held.

Java uses synchronized statements and methods to guarantee that data is accessed in a sequential way and avoid race conditions in multithreaded applications. Incorrect uses of synchronization result in unexpected behaviors and subtle bugs, very hard to identify and reproduce.

Checks for this warning class make use of annotations @com.juliasoft.julia.checkers.guardedBy.GuardedBy and @com.juliasoft.julia.checkers.guardedBy.Holding. Add these annotations to your code to identify synchronization requirements for CodeSonar to check.

The @GuardedBy annotation for fields and parameters and the @Holding annotation for methods and constructors accept a string argument, according to the following syntax.

プロパティ

クラス名 Unguarded Method (Java)
日本語クラス名 Unguarded Method (Java)
クラス分類 信頼性 (reliability)
ニーモニック JAVA.CONCURRENCY.UG.METH
カテゴリー
CWE CWE:366 Race Condition within a Thread
  CWE:820 Missing Synchronization
CERT-Java CERT-Java:LCK05-J Synchronize access to static fields that can be modified by untrusted code
対応言語 Java で利用可能です。
有効/無効設定 このワーニングクラスのチェックはデフォルトで無効になっています。チェックを有効にするにはプロジェクト設定ファイル (configuration file)に以下の WARNING_FILTER ルールを追加してください。
WARNING_FILTER += allow class="Unguarded Method (Java)"

import lock.quals.GuardedBy;
import lock.quals.Holding;

public class GuardedByTest {
  private int counter;
  private Object lock = new Object();
  private long counter2;
  private static int counter3;
  private static Object lock4 = new Object();
  private static int counter4 = 13;
  private final Object[] locks = new Object[10];
  private int next;
  private final Object lock5 = new Object();
  private final static Object lock6 = new Object();
  private int counter5;

  public GuardedByTest() {
    this.counter = 1;
    this.counter5 = 17;
    this.counter5 += counter;
  }

  public synchronized void incrementCounter() {
    counter++;
  }

  public void decrementCounter() {
    synchronized (this) {
      counter--;
    }
  }

  public boolean checkCounterIs0() {
    Object copy = this;
    synchronized (copy) {
      return counter == 0;
    }
  }

  public void incrementOtherCounter(GuardedByTest other) {
    GuardedByTest copy = other;
    synchronized (copy) {
      incrementCounterAux(other);
    }
  }

  private void incrementCounterAux(@GuardedBy("this") GuardedByTest other) {
   other.counter += 2;
  }

  public void incrementCounter2() {
    synchronized (lock) {
      counter2++;
    }
  }

  public void decrementCounter2() {
    synchronized (lock) {
      counter2--;
    }
  }

  public boolean checkCounter2Is0() {
    Object copy = lock;
    synchronized (copy) {
          return counter2 == 0;
    }
  }

  public void incrementOtherCounter2(GuardedByTest other) {
    GuardedByTest copy = other;
    synchronized (copy.lock) {
      incrementCounter2Aux(other);
    }
  }

  private static void incrementCounter2Aux(GuardedByTest other) {
    other.counter2 += 2;
  }

  public void incrementCounter3() {
    synchronized (GuardedByTest.class) {
      counter3++;
    }
  }

  @Holding("GuardedByTest.class")
  public static synchronized void decrementCounter3() { // Unguarded Method (Java) warning issued here
    counter3--;
  }

  public void incrementCounter4() {
    synchronized (lock4) {
      counter4++;
    }
  }

  public static void decrementCounter4() {
    synchronized (lock4) {
      decrementCounter4Aux();
    }
  }

  @Holding("GuardedByTest.lock4")
  private static void decrementCounter4Aux() {
    counter4--;
  }

  private Object getLock() {
    return locks[next % locks.length];
  }

  public void incrementCounter5() {
    synchronized (getLock()) {
      counter5++;
      next++;
    }
  }

  public void decrementCounter5() {
    synchronized (getLock()) {
      decrementCounter5Aux();
    }
  }

  private void decrementCounter5Aux() {
    counter5--;
  }

  public void accessLock5() {
    synchronized (lock5) {
      lock5.hashCode();
    }
  }

  public static void accessLock6() {
    synchronized (lock6) {
      lock6.hashCode();
    }
  }

  public synchronized void parameterTest1(Object o1, String o2, String o3) {
    System.out.println(o1);
    synchronized (lock) {
      System.out.println(o2);
    }
    synchronized (o3) {
      System.out.println(o3 + " ");
    }
  }
}

解決法

Verify if the missing synchronization should actually be there. Annotate fields and methods with the lock that must be held when they are accessed or called, by using the @GuardedBy and @Holding annotations. If this checker does not accept those annotations, it is likely the case that your program has a synchronization problem.

関連のある設定ファイルパラメータ

設定ファイルの以下のパラメータがこのワーニングクラスのチェックに影響します。