Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uninitialized object leaked to another thread despite no code explicitly leaking it?

Let's see this simple Java program:

import java.util.*;

class A {
    static B b;
    static class B {
        int x;
        B(int x) {
            this.x = x;
        }
    }
    public static void main(String[] args) {
        new Thread() {
            void f(B q) {
                int x = q.x;
                if (x != 1) {
                    System.out.println(x);
                    System.exit(1);
                }
            }
            @Override
            public void run() {
                while (b == null);
                while (true) f(b);
            }
        }.start();
        for (int x = 0;;x++)
            b = new B(Math.max(x%2,1));
    }
}

Main thread

The main thread creates an instance of B with x set to 1, then writes that instance to the static field A.b. It repeats this action forever.

Polling thread

The spawned thread polls until it finds that A.b.x is not 1.

?!?

Half the time it goes in an infinite loop as expected, but half the time I get this output:

$ java A
0

Why is the polling thread able to see a B that has x not set to 1?


x%2 instead of just x is here simply because the issue is reproducible with it.


I'm running openjdk 6 on linux x64.

like image 315
Dog Avatar asked Dec 20 '22 06:12

Dog


1 Answers

Here is what I think: because b is not final, the compiler is free to reorder the operations as it likes, right? So this, fundamentally is a reordering issue and as a result a unsafe publication issue Marking the variable as final will fix the problem.

More or less, it is the same example as provided here in the Java memory model docs.

The real question is how is this possible. I can also speculate here (since I have no idea how the compiler will reorder), but maybe the reference to B is written to the main memory (where it is visible to the other thread) BEFORE the write to x happens. In between these two operations the read happens, thus the zero value

like image 167
Eugene Avatar answered Feb 16 '23 00:02

Eugene