DZone
Java Zone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
  • Refcardz
  • Trend Reports
  • Webinars
  • Zones
  • |
    • Agile
    • AI
    • Big Data
    • Cloud
    • Database
    • DevOps
    • Integration
    • IoT
    • Java
    • Microservices
    • Open Source
    • Performance
    • Security
    • Web Dev
DZone > Java Zone > How to Crash the Java Virtual Machine With a Race Condition

How to Crash the Java Virtual Machine With a Race Condition

A look at what kind of errors you'll see if the JVM crashes thanks to using race conditions.

Thomas Krieger user avatar by
Thomas Krieger
·
Mar. 14, 17 · Java Zone · Tutorial
Like (8)
Save
Tweet
17.61K Views

Join the DZone community and get the full member experience.

Join For Free

This is a how-to guide for crashing the Java virtual machine. It gives you an introduction to race conditions and shows you what errors can happen if your code contains such bugs.

Create a Race Condition

Let us start with the following method:

public class DataRaceTest implements Runnable 
{ 
    private Type[] instance; 
    @Override public void run()  
    { 
      if (instance == null) 
       { 
         Type[] ts = new Type[1]; 
         ts[0] = Object.class; instance = ts;  
       } 
       instance[0].getTypeName(); 
    } 
} 

If this method is executed by multiple threads it leads to a race condition. More specifically, it leads to a data race. Data races are defined in the Java memory model as access to a shared field without correct synchronization.

According to the Java memory model, data races lead to platform dependent undefined behavior. Without correct synchronization, very strange, confusing, and counterintuitive behaviors are possible.

If the code is executed in the given order, everything is O.K. But if some component reorders the statements, the array might not be completely initialized. One such component is the cache system of the CPU.

Intel Processors, for example, have a cache system with strong memory guarantees. The cache system makes sure that the values written by the cores are almost always seen in the same order as they have been written by the other cores. But ARM-compatible processors like in smartphones or the Raspberry Pi do not have this guarantee.

Create a Nullpointer Exception

To see what is happening, I'll execute the method multiple times by multiple threads. To do this, I use a tool to reproduce race conditions called stress test. I run it with the following command line options:

java -cp stress-test-0.0.1-SNAPSHOT-jar-with-dependencies.jar 
  com.vmlens.StressTest -i 5 -w 16 
  com.vmlens.stressTest.examples.dataRace.DataRaceTestSetup 

Using the following test setup class:

public class DataRaceTestSetup implements TestSetup 
{ 
  @Override 
  public Runnable createTest() 
  { 
    return new DataRaceTest(); 
  } 
} 

This runs the DataRaceTest method for 5 iterations. Each iteration consists of 16,000 tests run by 16 threads.

If I run this on my Intel i5 workstation, I could not create an exception. If I run this on my Raspberry Pi, I see the following Nullpointer Exception for every 2000 tests:

java.lang.NullPointerException 
  at com.vmlens.stressTest.examples.dataRace.DataRaceTest.run(DataRaceTest.java:78) 
  at com.vmlens.stressTest.internal.TestCall.call(TestCall.java:36) 
  at com.vmlens.stressTest.internal.TestCall.call(TestCall.java:7) 
  at com.vmlens.stressTest.internal.WorkerThread.run(WorkerThread.java:22) 

Crash the Java Virtual Machine

Now let us add some native calls. Let us clone the array:

 @Override public void run() 
 { 
   if (instance == null) 
   { 
     Type[] ts = new Type[1]; 
     ts[0] = Object.class; instance = ts; 
   } 
   Type[] clonedInstance = instance.clone(); 
   clonedInstance[0].getTypeName(); 
 } 

This time I'll run the test until I see at least one error. This is done by using the -e option:

java -cp stress-test-0.0.1-SNAPSHOT-jar-with-dependencies.jar 
  com.vmlens.StressTest -e 1 -w 16
  com.vmlens.stressTest.examples.dataRace.DataRaceTestSetup 

If I run this code on a Raspberry Pi, I'll see the Java virtual machine crash after some time. It takes between half an hour and a day:

# 
# A fatal error has been detected by the Java Runtime Environment: 
#
# SIGSEGV (0xb) at pc=0x741ab340, pid=26364, tid=1682633824 
# 
# JRE version: Java(TM) SE Runtime Environment (8.0_65-b17) (build 1.8.0_65-b17) 
# Java VM: Java HotSpot(TM) Client VM (25.65-b01 mixed mode linux-arm ) 
# Problematic frame: 
# J 38 C1 com.vmlens.stressTest.internal.TestSetupCall.call()Lcom/vmlens/stressTest/internal/Result; (45 bytes) @ 0x741ab340 [0x741ab250+0xf0] 

Conclusion

Data races are hard to reproduce. You need different types of hardware, and even then it takes time until you see an error occur.

That is the reason I developed vmlens, a tool to detect data races in the execution trace of an application.

Java virtual machine Virtual Machine Race condition Java (programming language) Machine Crash (computing)

Published at DZone with permission of Thomas Krieger, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Modern Application Security Requires Defense in Depth
  • Vaadin Apps as Native Executables Using Quarkus Native
  • Monitoring Spring Boot Application With Prometheus and Grafana
  • Making Your Own Express Middleware

Comments

Java Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • MVB Program
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends:

DZone.com is powered by 

AnswerHub logo