Fix or suppress LGTM findings (#10689)

Motivation:

LGTM reports multiple issues. They need to be triaged,
and real ones should be fixed.

Modifications:
- Fixed multiple issues reported by LGTM, such as redundant conditions,
  resource leaks, typos, possible integer overflows.
- Suppressed false-positives.
- Added a few testcases.

Result:

Fixed several possible issues, get rid of false alarms in the LGTM report.
This commit is contained in:
Artem Smotrakov 2020-10-17 09:49:44 +02:00 committed by Norman Maurer
parent dbe13b41e4
commit f0448d6a8a
31 changed files with 112 additions and 49 deletions

View File

@ -153,8 +153,9 @@ public class ByteBufInputStream extends InputStream implements DataInput {
return endIndex - buffer.readerIndex();
}
// Suppress a warning since the class is not thread-safe
@Override
public void mark(int readlimit) {
public void mark(int readlimit) { // lgtm[java/non-sync-override]
markReaderIndex = buffer.readerIndex();
}
@ -184,8 +185,9 @@ public class ByteBufInputStream extends InputStream implements DataInput {
return len;
}
// Suppress a warning since the class is not thread-safe
@Override
public void reset() throws IOException {
public void reset() throws IOException { // lgtm[java/non-sync-override]
buffer.readerIndex(markReaderIndex);
}

View File

@ -42,6 +42,7 @@ public class ByteBufOutputStream extends OutputStream implements DataOutput {
private final ByteBuf buffer;
private final int startIndex;
private DataOutputStream utf8out; // lazily-instantiated
private boolean closed;
/**
* Creates a new stream which writes data to the specified {@code buffer}.
@ -135,7 +136,11 @@ public class ByteBufOutputStream extends OutputStream implements DataOutput {
public void writeUTF(String s) throws IOException {
DataOutputStream out = utf8out;
if (out == null) {
utf8out = out = new DataOutputStream(this);
if (closed) {
throw new IOException("The stream is closed");
}
// Suppress a warning since the stream is closed in the close() method
utf8out = out = new DataOutputStream(this); // lgtm[java/output-resource-leak]
}
out.writeUTF(s);
}
@ -146,4 +151,20 @@ public class ByteBufOutputStream extends OutputStream implements DataOutput {
public ByteBuf buffer() {
return buffer;
}
@Override
public void close() throws IOException {
if (closed) {
return;
}
closed = true;
try {
super.close();
} finally {
if (utf8out != null) {
utf8out.close();
}
}
}
}

View File

@ -151,7 +151,7 @@ public class HAProxyMessageDecoder extends ByteToMessageDecoder {
v2MaxHeaderSize = V2_MAX_LENGTH;
} else {
int calcMax = maxTlvSize + V2_MIN_LENGTH;
if (calcMax > V2_MAX_LENGTH) {
if (calcMax > V2_MAX_LENGTH) { // lgtm[java/constant-comparison]
v2MaxHeaderSize = V2_MAX_LENGTH;
} else {
v2MaxHeaderSize = calcMax;

View File

@ -977,7 +977,8 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
@Override
public AppendableCharSequence parse(ByteBuf buffer) {
reset();
// Suppress a warning because HeaderParser.reset() is supposed to be called
reset(); // lgtm[java/subtle-inherited-call]
return super.parse(buffer);
}

View File

@ -78,7 +78,8 @@ public final class ReadOnlyHttpHeaders extends HttpHeaders {
for (int i = 0; i < nameValuePairs.length; i += 2) {
CharSequence roName = nameValuePairs[i];
if (AsciiString.hashCode(roName) == nameHash && contentEqualsIgnoreCase(roName, name)) {
return nameValuePairs[i + 1];
// Suppress a warning out of bounds access since the constructor allows only pairs
return nameValuePairs[i + 1]; // lgtm[java/index-out-of-bounds]
}
}
return null;
@ -136,7 +137,7 @@ public final class ReadOnlyHttpHeaders extends HttpHeaders {
for (int i = 0; i < nameValuePairs.length; i += 2) {
CharSequence roName = nameValuePairs[i];
if (AsciiString.hashCode(roName) == nameHash && contentEqualsIgnoreCase(roName, name)) {
values.add(nameValuePairs[i + 1].toString());
values.add(nameValuePairs[i + 1].toString()); // lgtm[java/index-out-of-bounds]
}
}
return values;
@ -150,7 +151,7 @@ public final class ReadOnlyHttpHeaders extends HttpHeaders {
List<Map.Entry<String, String>> entries = new ArrayList<>(size());
for (int i = 0; i < nameValuePairs.length; i += 2) {
entries.add(new SimpleImmutableEntry<>(nameValuePairs[i].toString(),
nameValuePairs[i + 1].toString()));
nameValuePairs[i + 1].toString())); // lgtm[java/index-out-of-bounds]
}
return entries;
}
@ -170,14 +171,14 @@ public final class ReadOnlyHttpHeaders extends HttpHeaders {
if (ignoreCase) {
for (int i = 0; i < nameValuePairs.length; i += 2) {
if (contentEqualsIgnoreCase(nameValuePairs[i], name) &&
contentEqualsIgnoreCase(nameValuePairs[i + 1], value)) {
contentEqualsIgnoreCase(nameValuePairs[i + 1], value)) { // lgtm[java/index-out-of-bounds]
return true;
}
}
} else {
for (int i = 0; i < nameValuePairs.length; i += 2) {
if (contentEqualsIgnoreCase(nameValuePairs[i], name) &&
contentEquals(nameValuePairs[i + 1], value)) {
contentEquals(nameValuePairs[i + 1], value)) { // lgtm[java/index-out-of-bounds]
return true;
}
}

View File

@ -27,14 +27,14 @@ import java.util.concurrent.ThreadLocalRandom;
*/
final class WebSocketUtil {
// Suppress a warning about weak hash algorithm since it's defined in draft-ietf-hybi-thewebsocketprotocol-00
@SuppressWarnings("lgtm[java/weak-cryptographic-algorithm]")
private static final FastThreadLocal<MessageDigest> MD5 = new FastThreadLocal<MessageDigest>() {
@Override
protected MessageDigest initialValue() throws Exception {
try {
//Try to get a MessageDigest that uses MD5
return MessageDigest.getInstance("MD5");
//Suppress a warning about weak hash algorithm
//since it's defined in draft-ietf-hybi-thewebsocketprotocol-00
return MessageDigest.getInstance("MD5"); // lgtm [java/weak-cryptographic-algorithm]
} catch (NoSuchAlgorithmException e) {
//This shouldn't happen! How old is the computer?
throw new InternalError("MD5 not supported on this platform - Outdated?");
@ -42,14 +42,14 @@ final class WebSocketUtil {
}
};
// Suppress a warning about weak hash algorithm since it's defined in draft-ietf-hybi-thewebsocketprotocol-00
@SuppressWarnings("lgtm[java/weak-cryptographic-algorithm]")
private static final FastThreadLocal<MessageDigest> SHA1 = new FastThreadLocal<MessageDigest>() {
@Override
protected MessageDigest initialValue() throws Exception {
try {
//Try to get a MessageDigest that uses SHA1
return MessageDigest.getInstance("SHA1");
//Suppress a warning about weak hash algorithm
//since it's defined in draft-ietf-hybi-thewebsocketprotocol-00
return MessageDigest.getInstance("SHA1"); // lgtm [java/weak-cryptographic-algorithm]
} catch (NoSuchAlgorithmException e) {
//This shouldn't happen! How old is the computer?
throw new InternalError("SHA-1 not supported on this platform - Outdated?");

View File

@ -119,6 +119,18 @@ public class ReadOnlyHttpHeadersTest {
ACCEPT, APPLICATION_JSON, AsciiString.cached(" "));
}
@Test(expected = IllegalArgumentException.class)
public void emptyHeaderName() {
new ReadOnlyHttpHeaders(true,
ACCEPT, APPLICATION_JSON, AsciiString.cached(" "), ZERO);
}
@Test(expected = IllegalArgumentException.class)
public void headerWithoutValue() {
new ReadOnlyHttpHeaders(false,
ACCEPT, APPLICATION_JSON, CONTENT_LENGTH);
}
private static void assert3ParisEquals(Iterator<Entry<String, String>> itr) {
assertTrue(itr.hasNext());
Entry<String, String> next = itr.next();

View File

@ -57,7 +57,8 @@ public enum MqttConnectReturnCode {
VALUES = new MqttConnectReturnCode[160];
for (MqttConnectReturnCode code : values) {
final int unsignedByte = code.byteValue & 0xFF;
VALUES[unsignedByte] = code;
// Suppress a warning about out of bounds access since the enum contains only correct values
VALUES[unsignedByte] = code; // lgtm [java/index-out-of-bounds]
}
}

View File

@ -69,7 +69,7 @@ public abstract class XmlElement {
if (namespace != null ? !namespace.equals(that.namespace) : that.namespace != null) {
return false;
}
if (namespaces != null ? !namespaces.equals(that.namespaces) : that.namespaces != null) {
if (!namespaces.equals(that.namespaces)) {
return false;
}
if (prefix != null ? !prefix.equals(that.prefix) : that.prefix != null) {
@ -84,7 +84,7 @@ public abstract class XmlElement {
int result = name.hashCode();
result = 31 * result + (namespace != null ? namespace.hashCode() : 0);
result = 31 * result + (prefix != null ? prefix.hashCode() : 0);
result = 31 * result + (namespaces != null ? namespaces.hashCode() : 0);
result = 31 * result + namespaces.hashCode();
return result;
}

View File

@ -47,7 +47,7 @@ public class XmlElementStart extends XmlElement {
XmlElementStart that = (XmlElementStart) o;
if (attributes != null ? !attributes.equals(that.attributes) : that.attributes != null) {
if (!attributes.equals(that.attributes)) {
return false;
}
@ -57,7 +57,7 @@ public class XmlElementStart extends XmlElement {
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (attributes != null ? attributes.hashCode() : 0);
result = 31 * result + attributes.hashCode();
return result;
}

View File

@ -101,7 +101,7 @@ public final class DateFormatter {
} else if (length < 0) {
throw new IllegalArgumentException("Can't have end < start");
} else if (length > 64) {
throw new IllegalArgumentException("Can't parse more than 64 chars," +
throw new IllegalArgumentException("Can't parse more than 64 chars, " +
"looks like a user error or a malformed header");
}
return formatter().parse0(requireNonNull(txt, "txt"), start, end);

View File

@ -372,7 +372,9 @@ public class JZlibEncoder extends ZlibEncoder {
if (resultCode != JZlib.Z_OK && resultCode != JZlib.Z_STREAM_END) {
promise.setFailure(ZlibUtil.deflaterException(z, "compression failure", resultCode));
return promise;
} else if (z.next_out_index != 0) {
} else if (z.next_out_index != 0) { // lgtm[java/constant-comparison]
// Suppressed a warning above to be on the safe side
// even if z.next_out_index seems to be always 0 here
footer = Unpooled.wrappedBuffer(out, 0, z.next_out_index);
} else {
footer = Unpooled.EMPTY_BUFFER;

View File

@ -127,8 +127,9 @@ public class ObjectDecoderInputStream extends InputStream implements
in.close();
}
// Suppress a warning since the class is not thread-safe
@Override
public void mark(int readlimit) {
public void mark(int readlimit) { // lgtm[java/non-sync-override]
in.mark(readlimit);
}
@ -137,8 +138,9 @@ public class ObjectDecoderInputStream extends InputStream implements
return in.markSupported();
}
// Suppress a warning since the class is not thread-safe
@Override
public int read() throws IOException {
public int read() throws IOException { // lgtm[java/non-sync-override]
return in.read();
}

View File

@ -442,7 +442,7 @@ public class HashedWheelTimer implements Timer {
if (logger.isErrorEnabled()) {
String resourceType = simpleClassName(HashedWheelTimer.class);
logger.error("You are creating too many " + resourceType + " instances. " +
resourceType + " is a shared resource that must be reused across the JVM," +
resourceType + " is a shared resource that must be reused across the JVM, " +
"so that only a few instances are created.");
}
}

View File

@ -614,8 +614,10 @@ public class ResourceLeakDetector<T> {
// Strip the noisy stack trace elements.
String[] exclusions = excludedMethods.get();
for (int k = 0; k < exclusions.length; k += 2) {
// Suppress a warning about out of bounds access
// since the length of excludedMethods is always even, see addExclusions()
if (exclusions[k].equals(element.getClassName())
&& exclusions[k + 1].equals(element.getMethodName())) {
&& exclusions[k + 1].equals(element.getMethodName())) { // lgtm[java/index-out-of-bounds]
continue out;
}
}

View File

@ -64,13 +64,15 @@ public final class Signal extends Error implements Constant<Signal> {
}
}
// Suppress a warning since the method doesn't need synchronization
@Override
public Throwable initCause(Throwable cause) {
public Throwable initCause(Throwable cause) { // lgtm[java/non-sync-override]
return this;
}
// Suppress a warning since the method doesn't need synchronization
@Override
public Throwable fillInStackTrace() {
public Throwable fillInStackTrace() { // lgtm[java/non-sync-override]
return this;
}

View File

@ -128,8 +128,9 @@ public class DefaultPromise<V> implements Promise<V> {
private static final class LeanCancellationException extends CancellationException {
private static final long serialVersionUID = 2794674970981187807L;
// Suppress a warning since the method doesn't need synchronization
@Override
public Throwable fillInStackTrace() {
public Throwable fillInStackTrace() { // lgtm[java/non-sync-override]
setStackTrace(CANCELLATION_STACK);
return this;
}

View File

@ -30,7 +30,7 @@
return document.getElementById('responseText');
}
function appendTextArea(newData) {
function appendTextArea(newData) { // lgtm[js/unused-local-variable]
var el = getTextAreaElement();
el.value = el.value + '\n' + newData;
}

View File

@ -1624,7 +1624,7 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2) {
minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2;
}
if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2) {
if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2) { // lgtm[java/constant-comparison]
maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2;
}
break;

View File

@ -390,7 +390,7 @@ public final class SslContextBuilder {
public SslContextBuilder keyManager(PrivateKey key, String keyPassword, X509Certificate... keyCertChain) {
if (forServer) {
requireNonNull(keyCertChain, "keyCertChain required for servers");
if (keyCertChain.length == 0) {
if (keyCertChain.length == 0) { // lgtm[java/dereferenced-value-may-be-null]
throw new IllegalArgumentException("keyCertChain must be non-empty");
}
requireNonNull(key, "key required for servers");

View File

@ -32,8 +32,9 @@ public class TimeoutException extends ChannelException {
super(null, null, shared);
}
// Suppress a warning since the method doesn't need synchronization
@Override
public Throwable fillInStackTrace() {
public Throwable fillInStackTrace() { // lgtm[java/non-sync-override]
return this;
}
}

View File

@ -67,8 +67,9 @@ public class DnsNameResolverException extends RuntimeException {
return question;
}
// Suppress a warning since the method doesn't need synchronization
@Override
public Throwable fillInStackTrace() {
public Throwable fillInStackTrace() { // lgtm[java/non-sync-override]
setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
return this;
}

View File

@ -252,8 +252,9 @@ abstract class DnsResolveContext<T> {
initCause(cause.getCause());
}
// Suppress a warning since this method doesn't need synchronization
@Override
public Throwable fillInStackTrace() {
public Throwable fillInStackTrace() { // lgtm[java/non-sync-override]
return this;
}
}

View File

@ -100,7 +100,8 @@ public final class UnixResolverDnsServerAddressStreamProvider implements DnsServ
final boolean useEtcResolverFiles = etcResolverFiles != null && etcResolverFiles.length != 0;
domainToNameServerStreamMap = useEtcResolverFiles ? parse(etcResolverFiles) : etcResolvConfMap;
DnsServerAddresses defaultNameServerAddresses = etcResolvConfMap.get(etcResolvConf.getName());
DnsServerAddresses defaultNameServerAddresses
= etcResolvConfMap.get(etcResolvConf.getName()); // lgtm[java/dereferenced-value-may-be-null]
if (defaultNameServerAddresses == null) {
Collection<DnsServerAddresses> values = etcResolvConfMap.values();
if (values.isEmpty()) {

View File

@ -127,10 +127,15 @@ public final class HostsFileParser {
requireNonNull(charsets, "charsets");
if (file.exists() && file.isFile()) {
for (Charset charset: charsets) {
HostsFileEntries entries = parse(new BufferedReader(new InputStreamReader(
new FileInputStream(file), charset)));
if (entries != HostsFileEntries.EMPTY) {
return entries;
BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(file), charset));
try {
HostsFileEntries entries = parse(reader);
if (entries != HostsFileEntries.EMPTY) {
return entries;
}
} finally {
reader.close();
}
}
}

View File

@ -109,7 +109,8 @@ final class EpollEventArray {
private int getInt(int index, int offset) {
if (PlatformDependent.hasUnsafe()) {
return PlatformDependent.getInt(memoryAddress + index * EPOLL_EVENT_SIZE + offset);
long n = (long) index * (long) EPOLL_EVENT_SIZE;
return PlatformDependent.getInt(memoryAddress + n + offset);
}
return memory.getInt(index * EPOLL_EVENT_SIZE + offset);
}

View File

@ -1136,8 +1136,9 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
initCause(exception);
}
// Suppress a warning since this method doesn't need synchronization
@Override
public Throwable fillInStackTrace() {
public Throwable fillInStackTrace() { // lgtm[java/non-sync-override]
return this;
}
}
@ -1151,8 +1152,9 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
initCause(exception);
}
// Suppress a warning since this method doesn't need synchronization
@Override
public Throwable fillInStackTrace() {
public Throwable fillInStackTrace() { // lgtm[java/non-sync-override]
return this;
}
}
@ -1166,8 +1168,9 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
initCause(exception);
}
// Suppress a warning since this method doesn't need synchronization
@Override
public Throwable fillInStackTrace() {
public Throwable fillInStackTrace() { // lgtm[java/non-sync-override]
return this;
}
}

View File

@ -50,7 +50,8 @@ public class AdaptiveRecvByteBufAllocator extends DefaultMaxMessagesRecvByteBufA
sizeTable.add(i);
}
for (int i = 512; i > 0; i <<= 1) {
// Suppress a warning since i becomes negative when an integer overflow happens
for (int i = 512; i > 0; i <<= 1) { // lgtm[java/constant-comparison]
sizeTable.add(i);
}

View File

@ -602,7 +602,7 @@ public final class ChannelOutboundBuffer {
final int oldValue = unwritable;
final int newValue = oldValue | 1;
if (UNWRITABLE_UPDATER.compareAndSet(this, oldValue, newValue)) {
if (oldValue == 0 && newValue != 0) {
if (oldValue == 0) {
fireChannelWritabilityChanged(invokeLater);
}
break;

View File

@ -30,7 +30,8 @@ final class StacklessClosedChannelException extends ClosedChannelException {
@Override
public Throwable fillInStackTrace() {
return this;
// Suppress a warning since this method doesn't need synchronization
return this; // lgtm [java/non-sync-override]
}
/**

View File

@ -25,7 +25,8 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
final class VoidChannelGroupFuture implements ChannelGroupFuture {
// Suppress a warning about returning the same iterator since it always returns an empty iterator
final class VoidChannelGroupFuture implements ChannelGroupFuture { // lgtm[java/iterable-wraps-iterator]
private static final Iterator<ChannelFuture> EMPTY = Collections.<ChannelFuture>emptyList().iterator();
private final DefaultChannelGroup group;