Skip to content

Commit 7a2023b

Browse files
Jami CogswellJami Cogswell
authored andcommitted
Java: move original files
1 parent 38fdf7e commit 7a2023b

File tree

5 files changed

+213
-0
lines changed

5 files changed

+213
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# J-D-001: Method call to `java.lang.Thread` or its subclasses may indicate a logical bug
2+
3+
Calling `run()` on `java.lang.Thread` or its subclasses may indicate misunderstanding on the programmer's part.
4+
5+
## Overview
6+
7+
The `java.lang` package provides class `Thread` for multithreading. This class provides a method named `start`, to begin executing its code in a separate thread, that calls another public API called `run`. However, directly calling `run` does not result in this multithreading behavior; rather, it executes the code in the context of the current thread.
8+
9+
Meanwhile, the argument of the call to the constructor of `Thread` should implement `java.lang.Runnable` which provides the public method `run`. Calling this method directly also does not create a separate thread, however, this rule does not prohibit such calls.
10+
11+
## Recommendation
12+
13+
For instances of `Thread` and its subclasses, use `start` instead of `run` to start the thread and begin executing the `run` method of the `Runnable` instance used to construct the instance of `Thread`.
14+
15+
## Example
16+
17+
The following example creates an instance of `java.lang.Thread` and intends to execute it by calling the `run` method on it instead of `start`.
18+
19+
```java
20+
import java.lang.Thread;
21+
import java.lang.Runnable;
22+
23+
class Job implements Runnable {
24+
public void run() {
25+
/* ... */
26+
}
27+
}
28+
29+
class AnotherThread extends Thread {
30+
AnotherThread(Runnable runnable) {
31+
super(runnable);
32+
}
33+
34+
public void run() {
35+
/* ... */
36+
}
37+
}
38+
39+
class ThreadExample {
40+
public void f() {
41+
Thread thread = new Thread(new Job());
42+
thread.run(); // NON_COMPLIANT
43+
thread.start(); // COMPLIANT
44+
45+
AnotherThread anotherThread = new AnotherThread(new Job());
46+
anotherThread.run(); // NON_COMPLIANT
47+
anotherThread.start(); // COMPLIANT
48+
49+
Job job = new Job();
50+
job.run(); // COMPLIANT
51+
}
52+
}
53+
```
54+
55+
## References
56+
57+
- Oracle: [Documentation of java.lang.Thread](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html).
58+
- Oracle: [Documentation of java.lang.Runnable](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html).
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* @id java/run-method-called-on-java-lang-thread-directly
3+
* @name J-D-001: Method call to `java.lang.Thread` or its subclasses may indicate a logical bug
4+
* @description Calling `run()` on `java.lang.Thread` or its subclasses may indicate
5+
* misunderstanding on the programmer's part.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity warning
9+
* @tags correctness
10+
* performance
11+
* concurrency
12+
*/
13+
14+
import java
15+
import semmle.code.java.dataflow.DataFlow
16+
17+
/**
18+
* The import statement that brings java.lang.Thread into scope.
19+
*/
20+
class JavaLangThreadImport extends ImportType {
21+
JavaLangThreadImport() { this.getImportedType().hasQualifiedName("java.lang", "Thread") }
22+
}
23+
24+
/**
25+
* A class that inherits from `java.lang.Thread` either directly or indirectly.
26+
*/
27+
class JavaLangThreadSubclass extends Class {
28+
JavaLangThreadSubclass() {
29+
exists(JavaLangThreadImport javaLangThread |
30+
this.getASupertype+() = javaLangThread.getImportedType()
31+
)
32+
}
33+
}
34+
35+
class ProblematicRunMethodCall extends MethodCall {
36+
ProblematicRunMethodCall() {
37+
this.getMethod().getName() = "run" and
38+
(
39+
exists(JavaLangThreadImport javaLangThread |
40+
this.getQualifier().getType() = javaLangThread.getImportedType()
41+
)
42+
or
43+
exists(JavaLangThreadSubclass javaLangThreadSubclass |
44+
this.getQualifier().getType() = javaLangThreadSubclass
45+
)
46+
)
47+
}
48+
}
49+
50+
from ProblematicRunMethodCall problematicRunMethodCall
51+
select problematicRunMethodCall, "The run method is called directly on a thread instance."
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| Test.java:70:5:70:16 | run(...) | The run method is called directly on a thread instance. |
2+
| Test.java:74:5:74:24 | run(...) | The run method is called directly on a thread instance. |
3+
| Test.java:78:5:78:24 | run(...) | The run method is called directly on a thread instance. |
4+
| Test.java:82:5:82:27 | run(...) | The run method is called directly on a thread instance. |
5+
| Test.java:86:5:86:27 | run(...) | The run method is called directly on a thread instance. |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/J-D-001/RunMethodCalledOnJavaLangThreadDirectly.ql
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import java.lang.Thread;
2+
import java.lang.Runnable;
3+
4+
class Job implements Runnable {
5+
public void run() {
6+
/* ... */
7+
}
8+
}
9+
10+
/**
11+
* A class that subclasses `java.lang.Thread` and inherits its `.run()` method.
12+
*/
13+
class AnotherThread1 extends Thread {
14+
AnotherThread1(Runnable runnable) {
15+
super(runnable);
16+
}
17+
}
18+
19+
/**
20+
* A class that directly subclasses `java.lang.Thread` and overrides its
21+
* `.run()` method.
22+
*/
23+
class AnotherThread2 extends Thread {
24+
AnotherThread2(Runnable runnable) {
25+
super(runnable);
26+
}
27+
28+
/**
29+
* An overriding definition of `Thread.run`.
30+
*/
31+
@Override
32+
public void run() {
33+
/* ... */
34+
}
35+
}
36+
37+
/**
38+
* A class that indirectly subclasses `java.lang.Thread` by subclassing
39+
* `AnotherThread1` and inherits its `.run()`
40+
* method.
41+
*/
42+
class YetAnotherThread1 extends AnotherThread1 {
43+
YetAnotherThread1(Runnable runnable) {
44+
super(runnable);
45+
}
46+
}
47+
48+
/**
49+
* A class that indirectly subclasses `java.lang.Thread` by subclassing
50+
* `AnotherThread2` and overrides its `.run()`
51+
* method.
52+
*/
53+
class YetAnotherThread2 extends AnotherThread2 {
54+
YetAnotherThread2(Runnable runnable) {
55+
super(runnable);
56+
}
57+
58+
/**
59+
* An overriding definition of `AnotherThread.run`.
60+
*/
61+
@Override
62+
public void run() {
63+
/* ... */
64+
}
65+
}
66+
67+
class ThreadExample {
68+
public void f() {
69+
Thread thread = new Thread(new Job());
70+
thread.run(); // NON_COMPLIANT: `Thread.run()` called directly.
71+
thread.start(); // COMPLIANT: Thread started with `.start()`.
72+
73+
AnotherThread1 anotherThread1 = new AnotherThread1(new Job());
74+
anotherThread1.run(); // NON_COMPLIANT: Inherited `Thread.run()` called on its instance.
75+
anotherThread1.start(); // COMPLIANT: Inherited `Thread.start()` used to start the thread.
76+
77+
AnotherThread2 anotherThread2 = new AnotherThread2(new Job());
78+
anotherThread2.run(); // NON_COMPLIANT: Overriden `Thread.run()` called on its instance.
79+
anotherThread2.start(); // COMPLIANT: Overriden `Thread.start()` used to start the thread.
80+
81+
YetAnotherThread1 yetAnotherThread1 = new YetAnotherThread1(new Job());
82+
yetAnotherThread1.run(); // NON_COMPLIANT: Inherited `AnotherThread1.run()` called on its instance.
83+
yetAnotherThread1.start(); // COMPLIANT: Inherited `AnotherThread.start()` used to start the thread.
84+
85+
YetAnotherThread2 yetAnotherThread2 = new YetAnotherThread2(new Job());
86+
yetAnotherThread2.run(); // NON_COMPLIANT: Overriden `AnotherThread2.run()` called on its instance.
87+
yetAnotherThread2.start(); // COMPLIANT: Overriden `AnotherThread2.start()` used to start the thread.
88+
89+
Runnable runnable = new Runnable() {
90+
public void run() {
91+
/* ... */ }
92+
};
93+
runnable.run(); // COMPLIANT: This rule does not prevent `Runnable.run()` from being run.
94+
95+
Job job = new Job();
96+
job.run(); // COMPLIANT: This rule does not prevent `Runnable.run()` from being run.
97+
}
98+
}

0 commit comments

Comments
 (0)