Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bad thread-interleaving occurs, as a result test failure happens #1286

Open
Alisha-0321 opened this issue Nov 17, 2022 · 0 comments
Open

Bad thread-interleaving occurs, as a result test failure happens #1286

Alisha-0321 opened this issue Nov 17, 2022 · 0 comments

Comments

@Alisha-0321
Copy link

Commit version- aad6654

Describe the bug
It is possible to find some bad interleaving where one thread is writing from a synchronized block and another thread is reading the same variable from another method which is not synchronized. Here, flushandclosestate is a shared variable which is updated from a synchronized block at Line 596, but another thread uses flushandclosestate at Line 615 which is not synchronized. I can observe such an execution results in the assertion fail from running an existing test org.java_websocket.issues.Issue256Test with some added delay just before Line 596 of WebSocketImpl, resulting in the following stack trace.

Debug log
Tests run: 20, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.823 sec <<< FAILURE!
runReconnectSocketClose6 Time elapsed: 1.013 sec <<< FAILURE!
java.lang.AssertionError: Found 1 zombie thread(s)
at org.junit.Assert.fail(Assert.java:88)
at org.java_websocket.util.ThreadCheck.checkZombies(ThreadCheck.java:74)
at org.java_websocket.util.ThreadCheck.after(ThreadCheck.java:53)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:50)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)

Results :

Tests run: 20, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.823 sec <<< FAILURE!
runReconnectSocketClose6 Time elapsed: 1.013 sec <<< FAILURE!
java.lang.AssertionError: Found 1 zombie thread(s)

Tests in error:
Failed tests: runReconnectSocketClose6: Found 1 zombie thread(s)
Tests run: 20, Failures: 1, Errors: 0, Skipped: 0

To Reproduce
Steps to reproduce the behavior:

Add Thread.sleep(100) before Line 596
Run mvn test -Dtest=org.java_websocket.issues.Issue256Test -Dcheckstyle.skip

Expected behavior
Test failure should not occur

Additional context
When I investigated the WebSocketImpl class, I find flushandclosestate is a shared variable that is used on Line 615 and Line 596. By injecting a delay before Line 596 of WebSocketImpl.java, I could get a different thread interleaving where the variable flushandclosestate was not set to true when other threads were trying to close connection at Line 615. As a result, the assertion fails.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant