Skip to content

NullPointerException due to different thread interleaving #1282

Description

@Alisha-0321

Describe the bug
It is possible to encounter a NullPointerException due to a thread interleaving where one thread reads from shared variable connectReadThread after setting a new object (Line 375), but another thread sets connectReadThread to null (Line 526). I can observe such an execution that results in the exception from running an existing test org.java_websocket.issues.Issue256Test with some added delay, resulting in the following stack trace.

Debug log
runReconnectSocketClose5 Time elapsed: 0.02 sec <<< ERROR!
java.lang.NullPointerException
at org.java_websocket.client.WebSocketClient.connect(WebSocketClient.java:375)
at org.java_websocket.client.WebSocketClient.connectBlocking(WebSocketClient.java:386)
at org.java_websocket.client.WebSocketClient.reconnectBlocking(WebSocketClient.java:328)
at org.java_websocket.issues.Issue256Test.runTestScenarioReconnect(Issue256Test.java:136)
at org.java_websocket.issues.Issue256Test.runReconnectSocketClose(Issue256Test.java:156)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:298)
at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:292)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.lang.Thread.run(Thread.java:829)

Results :

Failed tests: runReconnectSocketClose3: Found 1 zombie thread(s)
runReconnectSocketClose4: Found 1 zombie thread(s)

Tests in error:
runReconnectSocketClose5

Tests run: 20, Failures: 2, Errors: 1, Skipped: 0

To Reproduce
Steps to reproduce the behavior:

  1. Add Thread.sleep(1000) before Line 526
  2. Run mvn test -Dtest=org.java_websocket.issues.Issue256Test -Dcheckstyle.skip

Expected behavior

  1. Null Pointer Exception and test failure should not occur

Additional context
When I investigated the WebSocketClient class, I find connectReadThread is a shared variable that is used on Line 375 and Line 526. By injecting a delay before Line 526 of WebSocketClient.java, I could get a different thread interleaving where the variable is set to null on Line 526 before the variable is used on Line 375. As a result, the execution throws a NullPointerException.

Environment(please complete the following information):
I ran the test on an Ubuntu 20.04 LTS machine using OpenJDK 1.8.0_312.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions