Skip to content

Commit 8177b09

Browse files
committed
Merge branch 'main' into models5
2 parents 3dabd51 + ae3253b commit 8177b09

30 files changed

+1181
-194
lines changed

MODULE.bazel

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True
3737
# the versions there are canonical, the versions here are used for CI in github/codeql, as well as for the vendoring of dependencies.
3838
RUST_EDITION = "2024"
3939

40+
# run buildutils-internal/scripts/fill-rust-sha256s.py when updating (internal repo)
4041
RUST_VERSION = "1.86.0"
4142

4243
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
@@ -47,6 +48,29 @@ rust.toolchain(
4748
"x86_64-apple-darwin",
4849
"aarch64-apple-darwin",
4950
],
51+
# generated by buildutils-internal/scripts/fill-rust-sha256s.py (internal repo)
52+
sha256s = {
53+
"rustc-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "4438b809ce4a083af31ed17aeeedcc8fc60ccffc0625bef1926620751b6989d7",
54+
"rustc-1.86.0-x86_64-apple-darwin.tar.xz": "42b76253626febb7912541a30d3379f463dec89581aad4cb72c6c04fb5a71dc5",
55+
"rustc-1.86.0-aarch64-apple-darwin.tar.xz": "23b8f52102249a47ab5bc859d54c9a3cb588a3259ba3f00f557d50edeca4fde9",
56+
"rustc-1.86.0-x86_64-pc-windows-msvc.tar.xz": "fdde839fea274529a31e51eb85c6df1782cc8479c9d1bc24e2914d66a0de41ab",
57+
"clippy-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "02aaff2c1407d2da8dba19aa4970dd873e311902b120a66cbcdbe51eb8836edf",
58+
"clippy-1.86.0-x86_64-apple-darwin.tar.xz": "bb85efda7bbffaf124867f5ca36d50932b1e8f533c62ee923438afb32ff8fe9a",
59+
"clippy-1.86.0-aarch64-apple-darwin.tar.xz": "239fa3a604b124f0312f2af08537874a1227dba63385484b468cca62e7c4f2f2",
60+
"clippy-1.86.0-x86_64-pc-windows-msvc.tar.xz": "d00498f47d49219f032e2c5eeebdfc3d32317c0dc3d3fd7125327445bc482cb4",
61+
"cargo-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "c5c1590f7e9246ad9f4f97cfe26ffa92707b52a769726596a9ef81565ebd908b",
62+
"cargo-1.86.0-x86_64-apple-darwin.tar.xz": "af163eb02d1a178044d1b4f2375960efd47130f795f6e33d09e345454bb26f4e",
63+
"cargo-1.86.0-aarch64-apple-darwin.tar.xz": "3cb13873d48c3e1e4cc684d42c245226a11fba52af6b047c3346ed654e7a05c0",
64+
"cargo-1.86.0-x86_64-pc-windows-msvc.tar.xz": "e57a9d89619b5604899bac443e68927bdd371e40f2e03e18950b6ceb3eb67966",
65+
"llvm-tools-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "282145ab7a63c98b625856f44b905b4dc726b497246b824632a5790debe95a78",
66+
"llvm-tools-1.86.0-x86_64-apple-darwin.tar.xz": "b55706e92f7da989207c50c13c7add483a9fedd233bc431b106eca2a8f151ec9",
67+
"llvm-tools-1.86.0-aarch64-apple-darwin.tar.xz": "04d3618c686845853585f036e3211eb9e18f2d290f4610a7a78bdc1fcce1ebd9",
68+
"llvm-tools-1.86.0-x86_64-pc-windows-msvc.tar.xz": "721a17cc8dc219177e4277a3592253934ef08daa1e1b12eda669a67d15fad8dd",
69+
"rust-std-1.86.0-x86_64-unknown-linux-gnu.tar.xz": "67be7184ea388d8ce0feaf7fdea46f1775cfc2970930264343b3089898501d37",
70+
"rust-std-1.86.0-x86_64-apple-darwin.tar.xz": "3b1140d54870a080080e84700143f4a342fbd02a410a319b05d9c02e7dcf44cc",
71+
"rust-std-1.86.0-aarch64-apple-darwin.tar.xz": "0fb121fb3b8fa9027d79ff598500a7e5cd086ddbc3557482ed3fdda00832c61b",
72+
"rust-std-1.86.0-x86_64-pc-windows-msvc.tar.xz": "3d5354b7b9cb950b58bff3fce18a652aa374bb30c8f70caebd3bd0b43cb41a33",
73+
},
5074
versions = [RUST_VERSION],
5175
)
5276
use_repo(rust, "rust_toolchains")

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ ql/java/ql/src/Violations of Best Practice/Naming Conventions/ConfusingMethodNam
7777
ql/java/ql/src/Violations of Best Practice/Naming Conventions/ConfusingOverloading.ql
7878
ql/java/ql/src/Violations of Best Practice/Naming Conventions/LocalShadowsFieldConfusing.ql
7979
ql/java/ql/src/Violations of Best Practice/Naming Conventions/SameNameAsSuper.ql
80+
ql/java/ql/src/Violations of Best Practice/Records/IgnoredSerializationMembersOfRecordClass.ql
81+
ql/java/ql/src/Violations of Best Practice/SpecialCharactersInLiterals/NonExplicitControlAndWhitespaceCharsInLiterals.ql
8082
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToStringToString.ql
8183
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DefaultToString.ql
8284
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DoNotCallFinalize.ql

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ ql/java/ql/src/Violations of Best Practice/Naming Conventions/ConfusingMethodNam
7575
ql/java/ql/src/Violations of Best Practice/Naming Conventions/ConfusingOverloading.ql
7676
ql/java/ql/src/Violations of Best Practice/Naming Conventions/LocalShadowsFieldConfusing.ql
7777
ql/java/ql/src/Violations of Best Practice/Naming Conventions/SameNameAsSuper.ql
78+
ql/java/ql/src/Violations of Best Practice/Records/IgnoredSerializationMembersOfRecordClass.ql
79+
ql/java/ql/src/Violations of Best Practice/SpecialCharactersInLiterals/NonExplicitControlAndWhitespaceCharsInLiterals.ql
7880
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToStringToString.ql
7981
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DefaultToString.ql
8082
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DoNotCallFinalize.ql
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
## Overview
2+
3+
Record types were introduced in Java 16 as a mechanism to provide simpler data handling as an alternative to regular classes. However, record classes behave slightly differently during serialization. Namely any `writeObject`, `readObject`, `readObjectNoData`, `writeExternal`, and `readExternal` methods and `serialPersistentFields` fields declared in these classes cannot be used to affect the serialization process of any `Record` data type.
4+
5+
## Recommendation
6+
7+
Some level of serialization customization is offered by the Java 16 Record feature. The `writeReplace` and `readResolve` methods in a record that implements `java.io.Serializable` can be used to replace the object to be serialized. Otherwise, no further customization of serialization of records is possible, and it is better to consider using a regular class implementing `java.io.Serializable` or `java.io.Externalizable` when customization is needed.
8+
9+
## Example
10+
11+
```java
12+
record T1() implements Serializable {
13+
14+
@Serial
15+
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; // NON_COMPLIANT
16+
17+
@Serial
18+
private void writeObject(ObjectOutputStream out) throws IOException {} // NON_COMPLIANT
19+
20+
@Serial
21+
private void readObject(ObjectOutputStream out) throws IOException {}// NON_COMPLIANT
22+
23+
@Serial
24+
private void readObjectNoData(ObjectOutputStream out) throws IOException { // NON_COMPLIANT
25+
}
26+
}
27+
28+
record T2() implements Externalizable {
29+
30+
@Override
31+
public void writeExternal(ObjectOutput out) throws IOException { // NON_COMPLIANT
32+
}
33+
34+
@Override
35+
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { // NON_COMPLIANT
36+
}
37+
}
38+
39+
record T3() implements Serializable {
40+
41+
public Object writeReplace(ObjectOutput out) throws ObjectStreamException { // COMPLIANT
42+
return new Object();
43+
}
44+
45+
public Object readResolve(ObjectInput in) throws ObjectStreamException { // COMPLIANT
46+
return new Object();
47+
}
48+
}
49+
```
50+
51+
## References
52+
53+
- Oracle Serialization Documentation: [Serialization of Records](https://docs.oracle.com/en/java/javase/16/docs/specs/serialization/serial-arch.html#serialization-of-records)
54+
- Java Record: [Feature Specification](https://openjdk.org/jeps/395)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* @id java/ignored-serialization-member-of-record-class
3+
* @name Ignored serialization member of record class
4+
* @description Using certain members of a record class during serialization will result in
5+
* those members being ignored.
6+
* @previous-id java/useless-members-of-the-records-class
7+
* @kind problem
8+
* @precision very-high
9+
* @problem.severity warning
10+
* @tags quality
11+
* reliability
12+
* correctness
13+
*/
14+
15+
import java
16+
17+
from Record record, Member m
18+
where
19+
record.getAMember() = m and
20+
m.hasName([
21+
"writeObject", "readObject", "readObjectNoData", "writeExternal", "readExternal",
22+
"serialPersistentFields"
23+
])
24+
select m, "Ignored serialization member found in record class $@.", record, record.getName()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
## Overview
2+
3+
This query detects non-explicit control and whitespace characters in Java literals.
4+
Such characters are often introduced accidentally and can be invisible or hard to recognize, leading to bugs when the actual contents of the string contain control characters.
5+
6+
## Recommendation
7+
8+
To avoid issues, use the encoded versions of control characters (e.g. ASCII `\n`, `\t`, or Unicode `U+000D`, `U+0009`).
9+
This makes the literals (e.g. string literals) more readable, and also helps to make the surrounding code less error-prone and more maintainable.
10+
11+
## Example
12+
13+
The following examples illustrate good and bad code:
14+
15+
Bad:
16+
17+
```java
18+
char tabulationChar = ' '; // Non compliant
19+
String tabulationCharInsideString = "A B"; // Non compliant
20+
String fooZeroWidthSpacebar = "foo​bar"; // Non compliant
21+
```
22+
23+
Good:
24+
25+
```java
26+
char escapedTabulationChar = '\t';
27+
String escapedTabulationCharInsideString = "A\tB"; // Compliant
28+
String fooUnicodeSpacebar = "foo\u0020bar"; // Compliant
29+
String foo2Spacebar = "foo bar"; // Compliant
30+
String foo3Spacebar = "foo bar"; // Compliant
31+
```
32+
33+
## Implementation notes
34+
35+
This query detects Java literals that contain reserved control characters and/or non-printable whitespace characters, such as:
36+
37+
- Decimal and hexidecimal representations of ASCII control characters (code points 0-8, 11, 14-31, and 127).
38+
- Invisible characters (e.g. zero-width space, zero-width joiner).
39+
- Unicode C0 control codes, plus the delete character (U+007F), such as:
40+
41+
| Escaped Unicode | ASCII Decimal | Description |
42+
| --------------- | ------------- | ------------------------- |
43+
| `\u0000` | 0 | null character |
44+
| `\u0001` | 1 | start of heading |
45+
| `\u0002` | 2 | start of text |
46+
| `\u0003` | 3 | end of text |
47+
| `\u0004` | 4 | end of transmission |
48+
| `\u0005` | 5 | enquiry |
49+
| `\u0006` | 6 | acknowledge |
50+
| `\u0007` | 7 | bell |
51+
| `\u0008` | 8 | backspace |
52+
| `\u000B` | 11 | vertical tab |
53+
| `\u000E` | 14 | shift out |
54+
| `\u000F` | 15 | shift in |
55+
| `\u0010` | 16 | data link escape |
56+
| `\u0011` | 17 | device control 1 |
57+
| `\u0012` | 18 | device control 2 |
58+
| `\u0013` | 19 | device control 3 |
59+
| `\u0014` | 20 | device control 4 |
60+
| `\u0015` | 21 | negative acknowledge |
61+
| `\u0016` | 22 | synchronous idle |
62+
| `\u0017` | 23 | end of transmission block |
63+
| `\u0018` | 24 | cancel |
64+
| `\u0019` | 25 | end of medium |
65+
| `\u001A` | 26 | substitute |
66+
| `\u001B` | 27 | escape |
67+
| `\u001C` | 28 | file separator |
68+
| `\u001D` | 29 | group separator |
69+
| `\u001E` | 30 | record separator |
70+
| `\u001F` | 31 | unit separator |
71+
| `\u007F` | 127 | delete |
72+
73+
- Zero-width Unicode characters (e.g. zero-width space, zero-width joiner), such as:
74+
75+
| Escaped Unicode | Description |
76+
| --------------- | ------------------------- |
77+
| `\u200B` | zero-width space |
78+
| `\u200C` | zero-width non-joiner |
79+
| `\u200D` | zero-width joiner |
80+
| `\u2028` | line separator |
81+
| `\u2029` | paragraph separator |
82+
| `\u2060` | word joiner |
83+
| `\uFEFF` | zero-width no-break space |
84+
85+
The following list outlines the _**explicit exclusions from query scope**_:
86+
87+
- any number of simple space characters (`U+0020`, ASCII 32).
88+
- an escape character sequence (e.g. `\t`), or the Unicode equivalent (e.g. `\u0009`), for printable whitespace characters:
89+
90+
| Character Sequence | Escaped Unicode | ASCII Decimal | Description |
91+
| ------------------ | --------------- | ------------- | --------------- |
92+
| `\t` | \u0009 | 9 | horizontal tab |
93+
| `\n` | \u000A | 10 | line feed |
94+
| `\f` | \u000C | 12 | form feed |
95+
| `\r` | \u000D | 13 | carriage return |
96+
| | \u0020 | 32 | space |
97+
98+
- character literals (i.e. single quotes) containing control characters.
99+
- literals defined within "likely" test methods, such as:
100+
- JUnit test methods
101+
- methods annotated with `@Test`
102+
- methods of a class annotated with `@Test`
103+
- methods with names containing "test"
104+
105+
## References
106+
107+
- Unicode: [Unicode Control Characters](https://www.unicode.org/charts/PDF/U0000.pdf).
108+
- Wikipedia: [Unicode C0 control codes](https://en.wikipedia.org/wiki/C0_and_C1_control_codes).
109+
- Wikipedia: [Unicode characters with property "WSpace=yes" or "White_Space=yes"](https://en.wikipedia.org/wiki/Unicode_character_property#Whitespace).
110+
- Java API Specification: [Java String Literals](https://docs.oracle.com/javase/tutorial/java/data/characters.html).
111+
- Java API Specification: [Java Class Charset](https://docs.oracle.com/javase/8/docs/api///?java/nio/charset/Charset.html).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* @id java/non-explicit-control-and-whitespace-chars-in-literals
3+
* @name Non-explicit control and whitespace characters
4+
* @description Non-explicit control and whitespace characters in literals make code more difficult
5+
* to read and may lead to incorrect program behavior.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity warning
9+
* @tags quality
10+
* correctness
11+
* maintainability
12+
* readability
13+
*/
14+
15+
import java
16+
17+
/**
18+
* A `Literal` that has a Unicode control character within its
19+
* literal value (as returned by `getLiteral()` member predicate).
20+
*/
21+
class ReservedUnicodeInLiteral extends Literal {
22+
private int indexStart;
23+
24+
ReservedUnicodeInLiteral() {
25+
not this instanceof CharacterLiteral and
26+
exists(int codePoint |
27+
this.getLiteral().codePointAt(indexStart) = codePoint and
28+
(
29+
// Unicode C0 control characters
30+
codePoint < 32 and not codePoint in [9, 10, 12, 13]
31+
or
32+
codePoint = 127 // delete control character
33+
or
34+
codePoint = 8203 // zero-width space
35+
)
36+
)
37+
}
38+
39+
/** Gets the starting index of the Unicode control sequence. */
40+
int getIndexStart() { result = indexStart }
41+
}
42+
43+
from ReservedUnicodeInLiteral literal, int charIndex, int codePoint
44+
where
45+
literal.getIndexStart() = charIndex and
46+
literal.getLiteral().codePointAt(charIndex) = codePoint and
47+
not literal.getEnclosingCallable() instanceof LikelyTestMethod and
48+
not literal.getFile().isKotlinSourceFile()
49+
select literal,
50+
"Literal value contains control or non-printable whitespace character(s) starting with Unicode code point "
51+
+ codePoint + " at index " + charIndex + "."
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| Test.java:7:46:7:67 | serialPersistentFields | Ignored serialization member found in record class $@. | Test.java:4:12:4:13 | T1 | T1 |
2+
| Test.java:10:18:10:28 | writeObject | Ignored serialization member found in record class $@. | Test.java:4:12:4:13 | T1 | T1 |
3+
| Test.java:13:18:13:27 | readObject | Ignored serialization member found in record class $@. | Test.java:4:12:4:13 | T1 | T1 |
4+
| Test.java:16:18:16:33 | readObjectNoData | Ignored serialization member found in record class $@. | Test.java:4:12:4:13 | T1 | T1 |
5+
| Test.java:24:17:24:29 | writeExternal | Ignored serialization member found in record class $@. | Test.java:21:12:21:13 | T2 | T2 |
6+
| Test.java:28:17:28:28 | readExternal | Ignored serialization member found in record class $@. | Test.java:21:12:21:13 | T2 | T2 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
query: Violations of Best Practice/Records/IgnoredSerializationMembersOfRecordClass.ql
2+
postprocess: utils/test/InlineExpectationsTestQuery.ql
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import java.io.*;
2+
3+
public class Test {
4+
record T1() implements Serializable {
5+
6+
@Serial
7+
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; // $ Alert
8+
9+
@Serial
10+
private void writeObject(ObjectOutputStream out) throws IOException {} // $ Alert
11+
12+
@Serial
13+
private void readObject(ObjectOutputStream out) throws IOException {} // $ Alert
14+
15+
@Serial
16+
private void readObjectNoData(ObjectOutputStream out) throws IOException { // $ Alert
17+
}
18+
19+
}
20+
21+
record T2() implements Externalizable {
22+
23+
@Override
24+
public void writeExternal(ObjectOutput out) throws IOException { // $ Alert
25+
}
26+
27+
@Override
28+
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { // $ Alert
29+
}
30+
31+
}
32+
33+
record T3() implements Serializable {
34+
35+
public Object writeReplace(ObjectOutput out) throws ObjectStreamException { // COMPLIANT
36+
return new Object();
37+
}
38+
39+
public Object readResolve(ObjectInput in) throws ObjectStreamException { // COMPLIANT
40+
return new Object();
41+
}
42+
}}

0 commit comments

Comments
 (0)