| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package org.chromium.tools.findbugs.plugin; |
| |
| import org.apache.bcel.classfile.Code; |
| |
| import edu.umd.cs.findbugs.BugInstance; |
| import edu.umd.cs.findbugs.BugReporter; |
| import edu.umd.cs.findbugs.bcel.OpcodeStackDetector; |
| |
| /** |
| * This class detects the synchronized(this). |
| * |
| * The pattern of byte code of synchronized(this) is |
| * aload_0 # Load the 'this' pointer on top of stack |
| * dup # Duplicate the 'this' pointer |
| * astore_x # Store this for late use, it might be astore. |
| * monitorenter |
| */ |
| public class SynchronizedThisDetector extends OpcodeStackDetector { |
| private static final int PATTERN[] = {ALOAD_0, DUP, 0xff, 0xff, MONITORENTER}; |
| |
| private int mStep = 0; |
| private BugReporter mBugReporter; |
| |
| public SynchronizedThisDetector(BugReporter bugReporter) { |
| mBugReporter = bugReporter; |
| } |
| |
| @Override |
| public void visit(Code code) { |
| mStep = 0; |
| super.visit(code); |
| } |
| |
| @Override |
| public void sawOpcode(int seen) { |
| if (PATTERN[mStep] == seen) { |
| mStep++; |
| if (mStep == PATTERN.length) { |
| mBugReporter.reportBug(new BugInstance(this, "CHROMIUM_SYNCHRONIZED_THIS", |
| NORMAL_PRIORITY) |
| .addClassAndMethod(this) |
| .addSourceLine(this)); |
| mStep = 0; |
| return; |
| } |
| } else if (mStep == 2) { |
| // This could be astore_x |
| switch (seen) { |
| case ASTORE_0: |
| case ASTORE_1: |
| case ASTORE_2: |
| case ASTORE_3: |
| mStep += 2; |
| break; |
| case ASTORE: |
| mStep++; |
| break; |
| default: |
| mStep = 0; |
| break; |
| } |
| } else if (mStep == 3) { |
| // Could be any byte following the ASTORE. |
| mStep++; |
| } else { |
| mStep = 0; |
| } |
| } |
| } |