2016-08-04 2 views
3

私は、コードを以下ました:ここでNetBeansはヌルポインタの逆参照に関する警告を表示しますか?

import java.util.concurrent.ConcurrentHashMap; 
import java.util.concurrent.ConcurrentMap; 
import java.util.concurrent.TimeUnit; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 

public class NullDereference { 

    private static final ConcurrentMap<Integer, Object> MAP = new ConcurrentHashMap<>(); 

    public static void main(String[] args) { 
     Object object = getObject(1); 

     if (object == null) { 
      Lock lock = new ReentrantLock(); 
      lock.lock(); 
      try { 
       lock.newCondition().await(1, TimeUnit.SECONDS); 

       object = new Object(); 
       object = addObject(object); // [3] 
      } catch (InterruptedException ex) { 
       throw new RuntimeException(ex); 
      } finally {  // [1] 
       lock.unlock(); // [1] 
      } 
     } 

     System.out.println("class: " + object.getClass()); // [2] 
    } 

    private static Object getObject(int hashCode) { 
     return MAP.get(hashCode); 
    } 

    private static Object addObject(Object newObject) { 
     Object oldObject = MAP.putIfAbsent(newObject.hashCode(), newObject); 
     if (oldObject != null) { 
      return oldObject; 
     } 

     return newObject; 
    } 
} 

NetBeansはラインで[2] "可能NULLポインタを間接参照" に関する警告が表示されます。なぜ私は分からない。私はそれが行[3]のためだと思っていましたが、私が行[3]をコメントアウトすると、警告はまだここにあります。私は行[2]の前にヌル値を明示的にチェックするか、finally文全体([1]で注釈が付けられた行)をコメントアウトすると警告が消えます。

私はコードを分析し、これが偽陽性と考えています。私は正しいですか?

ヌルポインタの追加チェックをしたくありません。このコードで何が間違っていますか?警告なしにコードを変更することはできますか?

+0

強力なステートメントがないため、 'object'が初期化され、決してnullを返さないとコンパイラが判断する –

答えて

1

これを再現できます。短く:そうだね、NetBeansのバグのようだ。 EclipseとIDEAではここに警告は表示されません。

ロング:可能なすべてのコントロールフローパスを慎重に走査する必要があるため、「可能なnull参照解除」警告は非常に簡単な静的解析ではありません(私は実際に類似のアナライザを作成しています。 finallyにすると、最終的にセクションがすべてのコードパスの後に実行され、コントロールが元のコードに戻されるため、作業がさらに難しくなります。適切な制御フローグラフは、最終的にブロックのいくつかの複製を作成する必要があります。複数の着信エッジと発信エッジを追加するだけでは不十分です。 NetBeansがこの部分を間違って実行していると推測できます。ここで

が間違っ制御フローグラフのスケッチです:

[ try { lock.newCondition().await(...) ...} ] 
     /  |   \ 
     /   |   \ 
    /   |   \ 
Successful InterruptedException other exception 
Execution   |    /
    \    |   /
     \    |   /
     \   |   /
    [ finally { lock.unlock; } ] 
    /   |   \ 
    /   |    \ 
    /   |    \ 
    |    |    | 
[System.out] [throw RuntimeEx] [throw the original exception] 

は、このグラフに沿って行くことあなたがInterruptedExceptionまたは他のいくつかの例外の後、最終的なSystem.out文を訪問することができますエッジいることを参照してください。

[ try { lock.newCondition().await(...) ...} ] 
     /  |   \ 
     /   |   \ 
    /   |   \ 
Successful InterruptedException other exception 
Execution   |    | 
    |    |    | 
[finally_copy1] [finally_copy2] [finally_copy3] 
    |    |    | 
    |    |    | 
[System.out] [throw RuntimeEx] [throw the original exception] 

objectが確実に割り当てられているときにのみ成功しtry実行後System.out文を達することができますこの方法:正しいグラフは、finallyブロックの3つのコピーを作成する必要があります。

関連する問題