Skip to content

Commit e3bc505

Browse files
authored
Add EOFException-instead-of-return-value.ql
1 parent e977519 commit e3bc505

1 file changed

Lines changed: 98 additions & 0 deletions

File tree

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* Finds implementations of `read` methods which should return a value when reaching the
3+
* end of the data (e.g. returning the number of bytes read or -1), but instead throw
4+
* an `EOFException`.
5+
*
6+
* Depending on the use case, such an `EOFException` might be unexpected and callers of
7+
* the method might not handle it properly.
8+
*
9+
* @kind problem
10+
* @id TODO
11+
*/
12+
13+
import java
14+
15+
// TODO: Deduplicate this with other queries which also define something similar? though this here focuses mainly
16+
// on abstract methods and not on all `read` methods (e.g. it ignores `RandomAccessFile#read`)
17+
/**
18+
* `read` method which should return on EOF, but not throw an exception.
19+
*
20+
* Mainly covers abstract methods which have to be implemented by users; does not
21+
* cover non-abstract methods which are most likely not overridden.
22+
*/
23+
class ReadMethod extends Method {
24+
ReadMethod() {
25+
getDeclaringType().hasQualifiedName("java.io", "InputStream") and
26+
hasStringSignature([
27+
"available()",
28+
"read()",
29+
"read(byte[])",
30+
"read(byte[], int, int)",
31+
"readNBytes(byte[], int, int)",
32+
"skip(long)",
33+
])
34+
or
35+
getDeclaringType().hasQualifiedName("java.io", "DataInput") and
36+
hasStringSignature(["skipBytes(int)",])
37+
or
38+
getDeclaringType().hasQualifiedName("java.io", "ObjectInput") and
39+
hasStringSignature([
40+
"available()",
41+
"read()",
42+
"read(byte[])",
43+
"read(byte[], int, int)",
44+
"skip(long)",
45+
])
46+
or
47+
getDeclaringType().hasQualifiedName("java.lang", "Readable") and
48+
hasStringSignature(["read(CharBuffer)",])
49+
or
50+
getDeclaringType().hasQualifiedName("java.io", "Reader") and
51+
hasStringSignature([
52+
"read()",
53+
"read(char[])",
54+
"read(char[], int, int)",
55+
"skip(long)",
56+
])
57+
or
58+
getDeclaringType().hasQualifiedName("java.nio.channels", "ReadableByteChannel") and
59+
hasStringSignature(["read(ByteBuffer)",])
60+
or
61+
getDeclaringType().hasQualifiedName("java.nio.channels", "FileChannel") and
62+
hasStringSignature(["read(ByteBuffer, long)",])
63+
or
64+
getDeclaringType().hasQualifiedName("java.nio.channels", "ScatteringByteChannel") and
65+
hasStringSignature([
66+
"read(ByteBuffer[])",
67+
"read(ByteBuffer[], int, int)",
68+
])
69+
}
70+
}
71+
72+
class EofException extends Class {
73+
EofException() { hasQualifiedName("java.io", "EOFException") }
74+
}
75+
76+
abstract class EofThrowing extends ExprParent {
77+
abstract Callable getEnclosingCallable();
78+
}
79+
80+
class ThrowEof extends EofThrowing, ThrowStmt {
81+
ThrowEof() { getThrownExceptionType().getASourceSupertype*() instanceof EofException }
82+
83+
override Callable getEnclosingCallable() { result = ThrowStmt.super.getEnclosingCallable() }
84+
}
85+
86+
class CallThrowsEof extends EofThrowing, Call {
87+
CallThrowsEof() {
88+
getCallee().getAThrownExceptionType().getASourceSupertype*() instanceof EofException
89+
}
90+
91+
override Callable getEnclosingCallable() { result = Call.super.getEnclosingCallable() }
92+
}
93+
94+
from Method readOverride, EofThrowing eofThrowing
95+
where
96+
readOverride.getASourceOverriddenMethod+() instanceof ReadMethod and
97+
eofThrowing.getEnclosingCallable() = readOverride
98+
select eofThrowing, "Throws EOFException in a method which should not throw it"

0 commit comments

Comments
 (0)