Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduced detector for rule VNA-00 and VNA-02 with test cases #2077

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,10 @@ This is the changelog for SpotBugs. This follows [Keep a Changelog v1.0.0](http:
Currently the versioning policy of this project follows [Semantic Versioning v2.0.0](http://semver.org/spec/v2.0.0.html).

## Unreleased - 2022-??-??
### Added
* New detector `BadVisibilityOnSharedPrimitiveVariables` for new bug type `SPV_BAD_VISIBILITY_ON_SHARED_PRIMITIVE_VARIABLES` (See [SEI CERT rule VNA00-J](https://wiki.sei.cmu.edu/confluence/display/java/VNA00-J.+Ensure+visibility+when+accessing+shared+primitive+variables))
* New detector `CompoundOperationsOnSharedVariables` for new bug type `COSV_COMPOUND_OPERATIONS_ON_SHARED_VARIABLES` (See [SEI CERT rule VNA02-J](https://wiki.sei.cmu.edu/confluence/display/java/VNA02-J.+Ensure+that+compound+operations+on+shared+variables+are+atomic))

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is already an Added section in Unreleased. Can you please merge the two?

### Fixed
- Fixed False positives for `RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE` on try-with-resources with interface references ([#1931](https://github.com/spotbugs/spotbugs/issues/1931))
- Disabled detector `ThrowingExceptions` by default to avoid many false positives ([#2040](https://github.com/spotbugs/spotbugs/issues/2040))
Expand Down
@@ -0,0 +1,109 @@
/*
* FindBugs - Find Bugs in Java programs
gonczmisi marked this conversation as resolved.
Show resolved Hide resolved
* Copyright (C) 2003-2008 University of Maryland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

package edu.umd.cs.findbugs.detect;

import edu.umd.cs.findbugs.AbstractIntegrationTest;
import edu.umd.cs.findbugs.SystemProperties;
import edu.umd.cs.findbugs.test.matcher.BugInstanceMatcher;
import edu.umd.cs.findbugs.test.matcher.BugInstanceMatcherBuilder;
import org.junit.Before;
import org.junit.Test;

import static edu.umd.cs.findbugs.test.CountMatcher.containsExactly;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;

public class BadVisibilityOnSharedPrimitiveVariablesTest extends AbstractIntegrationTest {

@Before
public void setup() {
SystemProperties.setProperty("ful.debug", "true");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is "ful"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume it stands for FindUnreleasedLock, it is the system property that defines the DEBUG flag in the class.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would be worth to comment it here, so later the codereader will know it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, IMO the tests shouldn't modify the state of the system, so it would be worth to set it back to the original setting after the tests.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does the FindUnreleasedLock have to do with this test? Why do you need to set this value?

}

@Test
public void failurePath_fieldWithBadVisibility_whenOtherMethodHasSynchronizedBlock() {
performAnalysis("multithreaded/sharedPrimitiveVariables/SynchronizedBlockAndBadVisibilityOnField.class");
assertSPVNumOfBugs(1);
assertSPVBug("SynchronizedBlockAndBadVisibilityOnField", "shutdown", 36);
}

@Test
public void failurePath_fieldWithBadVisibility_whenOtherMethodIsSynchronized() {
performAnalysis("multithreaded/sharedPrimitiveVariables/SynchronizedMethodAndBadVisibilityOnField.class");
assertSPVNumOfBugs(1);
assertSPVBug("SynchronizedMethodAndBadVisibilityOnField", "shutdown", 36);
}

@Test
public void failurePath_fieldWithBadVisibility_whenClassExtendsThread() {
performAnalysis("multithreaded/sharedPrimitiveVariables/FieldWithBadVisibilityThread.class");
assertSPVNumOfBugs(1);
assertSPVBug("FieldWithBadVisibilityThread", "shutdown", 37);
}

@Test
public void failurePath_fieldWithBadVisibility_whenClassImplementsRunnable() {
performAnalysis("multithreaded/sharedPrimitiveVariables/FieldWithBadVisibilityRunnable.class");
assertSPVNumOfBugs(1);
assertSPVBug("FieldWithBadVisibilityRunnable", "shutdown", 37);
}

@Test
public void happyPath_atomicField() {
performAnalysis("multithreaded/sharedPrimitiveVariables/AtomicField.class");
assertSPVNumOfBugs(0);
}

@Test
public void happyPath_volatileField() {
performAnalysis("multithreaded/sharedPrimitiveVariables/VolatileField.class");
assertSPVNumOfBugs(0);
}

@Test
public void happyPath_synchronizedBlock() {
performAnalysis("multithreaded/sharedPrimitiveVariables/SynchronizedBlock.class");
assertSPVNumOfBugs(0);
}

@Test
public void happyPath_synchronizedMethod() {
performAnalysis("multithreaded/sharedPrimitiveVariables/SynchronizedMethod.class");
assertSPVNumOfBugs(0);
}

private void assertSPVNumOfBugs(int num) {
final BugInstanceMatcher bugTypeMatcher = new BugInstanceMatcherBuilder()
.bugType("SPV_BAD_VISIBILITY_ON_SHARED_PRIMITIVE_VARIABLES")
.build();
assertThat(getBugCollection(), containsExactly(num, bugTypeMatcher));
}

private void assertSPVBug(String className, String methodName, int line) {
final BugInstanceMatcher bugInstanceMatcher = new BugInstanceMatcherBuilder()
.bugType("SPV_BAD_VISIBILITY_ON_SHARED_PRIMITIVE_VARIABLES")
.inClass(className)
.inMethod(methodName)
.atLine(line)
.build();
assertThat(getBugCollection(), hasItem(bugInstanceMatcher));
}

}
@@ -0,0 +1,195 @@
/*
* FindBugs - Find Bugs in Java programs
gonczmisi marked this conversation as resolved.
Show resolved Hide resolved
* Copyright (C) 2003-2008 University of Maryland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

package edu.umd.cs.findbugs.detect;

import edu.umd.cs.findbugs.AbstractIntegrationTest;
import edu.umd.cs.findbugs.SystemProperties;
import edu.umd.cs.findbugs.test.matcher.BugInstanceMatcher;
import edu.umd.cs.findbugs.test.matcher.BugInstanceMatcherBuilder;
import org.junit.Before;
import org.junit.Test;

import static edu.umd.cs.findbugs.test.CountMatcher.containsExactly;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;

public class FindCompoundOperationsOnSharedVariablesTest extends AbstractIntegrationTest {

@Before
public void setup() {
SystemProperties.setProperty("ful.debug", "true");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the tests shouldn't modify the state of the system, so it would be worth to set it back to the original setting after the tests.

}

@Test
public void happyPath_compoundOperation_onSharedAtomicVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundOperationOnSharedAtomicVariable.class");
assertCOSVNumOfBugs(0);
}

@Test
public void happyPath_compoundOperationInsideSynchronizedBlock_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/SynchronizedBlockCompoundOperationOnSharedVariable.class");
assertCOSVNumOfBugs(0);
}

@Test
public void happyPath_compoundOperationInsideSynchronizedMethod_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/SynchronizedMethodCompoundOperationOnSharedVariable.class");
assertCOSVNumOfBugs(0);
}

// --num
@Test
public void reportsBugFor_compoundPreDecrementation_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundPreDecrementationOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundPreDecrementationOnSharedVariable", "getNum", 30);
}

// num--
@Test
public void reportsBugFor_compoundPostDecrementation_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundPostDecrementationOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundPostDecrementationOnSharedVariable", "getNum", 30);
}

// ++num
@Test
public void reportsBugFor_compoundPreIncrementation_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundPreIncrementationOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundPreIncrementationOnSharedVariable", "getNum", 30);
}

// num++
@Test
public void reportsBugFor_compoundPostIncrementation_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundPostIncrementationOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundPostIncrementationOnSharedVariable", "getNum", 30);
}

// &=
@Test
public void reportsBugFor_compoundIAND_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundIANDOperationOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundIANDOperationOnSharedVariable", "getNum", 30);
}

// |=
@Test
public void reportsBugFor_compoundIOR_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundIOROperationOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundIOROperationOnSharedVariable", "getNum", 30);
}

// >>>=
@Test
public void reportsBugFor_compoundLogicalRightShifting_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundLogicalRightShiftingOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundLogicalRightShiftingOnSharedVariable", "getNum", 30);
}

// >>=
@Test
public void reportsBugFor_compoundRightShifting_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundRightShiftingOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundRightShiftingOnSharedVariable", "getNum", 30);
}

// <<=
@Test
public void reportsBugFor_compoundLeftShifting_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundLeftShiftingOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundLeftShiftingOnSharedVariable", "getNum", 30);
}

// %=
@Test
public void reportsBugFor_compoundModulo_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundModuloOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundModuloOnSharedVariable", "getNum", 31);
}

// *=
@Test
public void reportsBugFor_compoundMultiplication_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundMultiplicationOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundMultiplicationOnSharedVariable", "getNum", 30);
}

// /=
@Test
public void reportsBugFor_compoundDivision_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundDivisionOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundDivisionOnSharedVariable", "getNum", 30);
}

// -=
@Test
public void reportsBugFor_compoundSubtraction_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundSubtractionOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundSubtractionOnSharedVariable", "getNum", 30);
}


// +=
@Test
public void reportsBugFor_compoundAddition_onSharedVolatileVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundAdditionOnSharedVolatileVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundAdditionOnSharedVolatileVariable", "getNum", 30);
}

// ^=
@Test
public void reportsBugFor_compoundXOROperation_onSharedVariable() {
performAnalysis("multithreaded/compoundOperationOnSharedVariables/CompoundXOROperationOnSharedVariable.class");
assertCOSVNumOfBugs(1);
assertCOSVBug("CompoundXOROperationOnSharedVariable", "getFlag", 30);
}

private void assertCOSVNumOfBugs(int num) {
final BugInstanceMatcher bugTypeMatcher = new BugInstanceMatcherBuilder()
.bugType("COSV_COMPOUND_OPERATIONS_ON_SHARED_VARIABLES")
.build();
assertThat(getBugCollection(), containsExactly(num, bugTypeMatcher));
}

private void assertCOSVBug(String className, String methodName, int line) {
final BugInstanceMatcher bugInstanceMatcher = new BugInstanceMatcherBuilder()
.bugType("COSV_COMPOUND_OPERATIONS_ON_SHARED_VARIABLES")
.inClass(className)
.inMethod(methodName)
.atLine(line)
.build();
assertThat(getBugCollection(), hasItem(bugInstanceMatcher));
}
}
6 changes: 6 additions & 0 deletions spotbugs/etc/findbugs.xml
Expand Up @@ -669,6 +669,10 @@
reports="PERM_SUPER_NOT_CALLED_IN_GETPERMISSIONS"/>
<Detector class="edu.umd.cs.findbugs.detect.FindPotentialSecurityCheckBasedOnUntrustedSource" speed="fast"
reports="USC_POTENTIAL_SECURITY_CHECK_BASED_ON_UNTRUSTED_SOURCE"/>
<Detector class="edu.umd.cs.findbugs.detect.BadVisibilityOnSharedPrimitiveVariables"
reports="SPV_BAD_VISIBILITY_ON_SHARED_PRIMITIVE_VARIABLES"/>
<Detector class="edu.umd.cs.findbugs.detect.CompoundOperationsOnSharedVariables"
reports="COSV_COMPOUND_OPERATIONS_ON_SHARED_VARIABLES"/>
<!-- Bug Categories -->
<BugCategory category="NOISE" hidden="true"/>

Expand Down Expand Up @@ -1286,4 +1290,6 @@
<BugPattern abbrev="PERM" type="PERM_SUPER_NOT_CALLED_IN_GETPERMISSIONS" category="MALICIOUS_CODE" />
<BugPattern abbrev="USC" type="USC_POTENTIAL_SECURITY_CHECK_BASED_ON_UNTRUSTED_SOURCE"
category="MALICIOUS_CODE"/>
<BugPattern abbrev="SPV" type="SPV_BAD_VISIBILITY_ON_SHARED_PRIMITIVE_VARIABLES" category="MT_CORRECTNESS" />
<BugPattern abbrev="COSV" type="COSV_COMPOUND_OPERATIONS_ON_SHARED_VARIABLES" category="MT_CORRECTNESS"/>
</FindbugsPlugin>