Skip to content

Commit 46b2679

Browse files
committed
Java: Update docs and promote to quality java/jvm-exit
1 parent b31e6a7 commit 46b2679

File tree

6 files changed

+56
-33
lines changed

6 files changed

+56
-33
lines changed

java/ql/integration-tests/java/query-suite/java-code-quality-extended.qls.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ ql/java/ql/src/Violations of Best Practice/Naming Conventions/SameNameAsSuper.ql
8181
ql/java/ql/src/Violations of Best Practice/Records/IgnoredSerializationMembersOfRecordClass.ql
8282
ql/java/ql/src/Violations of Best Practice/SpecialCharactersInLiterals/NonExplicitControlAndWhitespaceCharsInLiterals.ql
8383
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToStringToString.ql
84+
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToSystemExit.ql
8485
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DefaultToString.ql
8586
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DoNotCallFinalize.ql
8687
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/PrintLnArray.ql

java/ql/integration-tests/java/query-suite/java-code-quality.qls.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ ql/java/ql/src/Violations of Best Practice/Naming Conventions/SameNameAsSuper.ql
7979
ql/java/ql/src/Violations of Best Practice/Records/IgnoredSerializationMembersOfRecordClass.ql
8080
ql/java/ql/src/Violations of Best Practice/SpecialCharactersInLiterals/NonExplicitControlAndWhitespaceCharsInLiterals.ql
8181
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToStringToString.ql
82+
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToSystemExit.ql
8283
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DefaultToString.ql
8384
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DoNotCallFinalize.ql
8485
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/PrintLnArray.ql

java/ql/integration-tests/java/query-suite/not_included_in_qls.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@ ql/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConsta
187187
ql/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.ql
188188
ql/java/ql/src/Violations of Best Practice/Naming Conventions/ConfusingOverridesNames.ql
189189
ql/java/ql/src/Violations of Best Practice/Naming Conventions/LocalShadowsField.ql
190-
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToSystemExit.ql
191190
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/GarbageCollection.ql
192191
ql/java/ql/src/Violations of Best Practice/legacy/AutoBoxing.ql
193192
ql/java/ql/src/Violations of Best Practice/legacy/FinallyMayNotComplete.ql

java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToSystemExit.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ boolean write(String[] s) {
44
try {
55
output.write(s.getBytes());
66
} catch (IOException e) {
7-
System.exit(1);
7+
System.exit(1); // BAD: Should handle or propagate error instead of exiting
88
}
99
return true;
1010
}
@@ -16,9 +16,30 @@ public void run() {
1616
// ...
1717
// Perform tasks ...
1818
// ...
19-
System.exit(0);
19+
System.exit(0); // BAD: Should return status or throw exception
2020
}
2121
public static void main(String[] args) {
22-
new Action(args).run();
22+
new Action().run();
2323
}
24-
}
24+
}
25+
26+
// Good example: Proper error handling
27+
class BetterAction {
28+
public int run() throws Exception {
29+
// ...
30+
// Perform tasks ...
31+
// ...
32+
return 0; // Return status instead of calling System.exit
33+
}
34+
35+
public static void main(String[] args) {
36+
try {
37+
BetterAction action = new BetterAction();
38+
int exitCode = action.run();
39+
System.exit(exitCode); // GOOD: Exit from main method
40+
} catch (Exception e) {
41+
System.err.println("Error: " + e.getMessage());
42+
System.exit(1); // GOOD: Exit from main method on error
43+
}
44+
}
45+
}

java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToSystemExit.qhelp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,20 @@ program state from being written to disk consistently.</p>
1313

1414
<p>It is sometimes considered acceptable to call <code>System.exit</code>
1515
from a program's <code>main</code> method in order to indicate the overall exit status
16-
of the program. Such calls are an exception to this rule.</p>
16+
of the program. The <code>main</code> method should be the primary place
17+
where exit conditions are handled, as it represents the natural termination point
18+
of the application. Such calls are an exception to this rule.</p>
1719

1820
</overview>
1921
<recommendation>
2022

21-
<p>It is usually preferable to use a different mechanism for reporting
22-
failure conditions. Consider returning a special value (perhaps
23-
<code>null</code>) that users of the current method check for and
24-
recover from appropriately. Alternatively, throw a suitable exception, which
25-
unwinds the stack and allows properly written code to clean up after itself,
26-
while leaving other threads undisturbed.</p>
23+
<p>Instead of calling <code>System.exit</code> from non-main methods, prefer to propagate
24+
errors upward to the <code>main</code> method where they can be handled appropriately.
25+
Consider returning a special value (perhaps <code>null</code>) that users of the current
26+
method check for and recover from appropriately. Alternatively, throw a suitable exception,
27+
which unwinds the stack and allows properly written code to clean up after itself,
28+
while leaving other threads undisturbed. The <code>main</code> method can then catch
29+
these exceptions and decide whether to exit the program and with what exit code.</p>
2730

2831
</recommendation>
2932
<example>
@@ -33,17 +36,20 @@ to write some data to disk and terminates the JVM if this fails. This
3336
leaves the partially-written file on disk without any cleanup
3437
code running. It would be better to either return <code>false</code> to
3538
indicate the failure, or let the <code>IOException</code> propagate
36-
upwards and be handled by a method that knows how to recover.</p>
39+
upwards to the <code>main</code> method where it can be handled appropriately
40+
and the program can exit gracefully if necessary.</p>
3741

3842
<p>Problem 2 is more subtle. In this example, there is just one entry point to
3943
the program (the <code>main</code> method), which constructs an
4044
<code>Action</code> and performs it. <code>Action.run</code> calls
41-
<code>System.exit</code> to indicate successful completion. Consider,
42-
however, how this code might be integrated in an application server that
43-
constructs <code>Action</code> instances and calls
45+
<code>System.exit</code> to indicate successful completion. Instead, the
46+
<code>run</code> method should return a status code or throw an exception
47+
on failure, allowing the <code>main</code> method to decide whether to exit
48+
and with what exit code. Consider how this code might be integrated in an
49+
application server that constructs <code>Action</code> instances and calls
4450
<code>run</code> on them without going through <code>main</code>.
4551
The fact that <code>run</code> terminates the JVM instead of returning its
46-
exit code as an integer makes that use-case impossible.</p>
52+
exit code makes that use-case impossible.</p>
4753

4854
<sample src="CallsToSystemExit.java" />
4955

java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToSystemExit.ql

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
* reuse and prevent important cleanup steps from running.
55
* @kind problem
66
* @problem.severity warning
7-
* @precision low
7+
* @precision high
88
* @id java/jvm-exit
9-
* @tags reliability
10-
* maintainability
9+
* @tags quality
10+
* reliability
11+
* correctness
1112
* external/cwe/cwe-382
1213
*/
1314

@@ -22,18 +23,12 @@ import java
2223
*/
2324
class ExitOrHaltMethod extends Method {
2425
ExitOrHaltMethod() {
25-
exists(Class system |
26-
this.getDeclaringType() = system and
27-
(
28-
this.hasName("exit") and
29-
(
30-
system.hasQualifiedName("java.lang", "System") or
31-
system.hasQualifiedName("java.lang", "Runtime")
32-
)
33-
or
34-
this.hasName("halt") and
35-
system.hasQualifiedName("java.lang", "Runtime")
36-
)
26+
exists(Class system | this.getDeclaringType() = system |
27+
this.hasName("exit") and
28+
system.hasQualifiedName("java.lang", ["System", "Runtime"])
29+
or
30+
this.hasName("halt") and
31+
system.hasQualifiedName("java.lang", "Runtime")
3732
)
3833
}
3934
}
@@ -48,7 +43,7 @@ class ExitOrHaltMethodCall extends MethodCall {
4843
}
4944

5045
/**
51-
* Represents an intentional `MethodCall` to a system or runtime "exit" method, such as for
46+
* An intentional `MethodCall` to a system or runtime "exit" method, such as for
5247
* functions which exist for the purpose of exiting the program. Assumes that a an exit method
5348
* call within a method is intentional if the exit code is passed from a parameter of the
5449
* enclosing method.

0 commit comments

Comments
 (0)