Bug 573404 - [DOM] Via "Double-Checked Locking" idiom lazy initialized fields have to be "volatile"
Summary: [DOM] Via "Double-Checked Locking" idiom lazy initialized fields have to be "...
Status: NEW
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.19   Edit
Hardware: PC Windows 10
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Sarika Sinha CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks:
 
Reported: 2021-05-06 10:05 EDT by Holger Voormann CLA
Modified: 2023-05-03 20:18 EDT (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Holger Voormann CLA 2021-05-06 10:05:24 EDT
In "org.eclipse.jdt.core.dom", the "Double-Checked Locking" idiom is used multiple times, but without the corresponding lazy initialized fields being "volatile".

A field that is lazy initialized via the "Double-Checked Locking" idiom has to be "volatile" to be multithreaded-safe. Otherwise, another thread may get a partial initialized field since the initialization of a non-volatile non-primitiv field is not guaranteed to be atomic.

The double-check idiom wasn't guaranteed to work until Java 1.5. Since Java 1.5 the "volatile" keyword ensures that multiple threads handle the singleton instance correctly. In "org.eclipse.jdt.core.dom", at least some of the via the double-check idiom lazy initialized fields have been introduced before Java 1.5.

See:
- https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
- http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

For example, org.eclipse.jdt.core.dom.ForStatement:

public class ForStatement extends Statement {
	// ...
	private Statement body = null;
	// ...
	public Statement getBody() {
		if (this.body == null) {
			// lazy init must be thread-safe for readers
			synchronized (this) {
				if (this.body == null) {
					preLazyInit();
					this.body = new Block(this.ast);
					postLazyInit(this.body, BODY_PROPERTY);
				}
			}
		}
		return this.body;
	}
	// ...
}

... has to be (with "volatile" and with "localRef" to access the "volatile" field only once for better performance):

public class ForStatement extends Statement {
	// ...
	private volatile Statement body = null;
	// ...
	public Statement getBody() {
		Statement localRef = this.body;
		if (localRef == null) {
			// lazy init must be thread-safe for readers
			synchronized (this) {
				localRef = this.body;
				if (localRef == null) {
					preLazyInit();
					this.body = localRef = new Block(this.ast);
					postLazyInit(this.body, BODY_PROPERTY);
				}
			}
		}
		return localRef;
	}
	// ...
}

Or do I miss something?
Comment 1 Vikas Chandra CLA 2021-05-06 10:16:49 EDT
Sarika, can you please have a look?
Comment 2 Carsten Hammer CLA 2021-05-06 17:23:27 EDT
You can find a gerrit for that at 
https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/171945
Comment 3 Holger Voormann CLA 2021-05-07 02:57:33 EDT
(In reply to Carsten Hammer from comment #2)
> You can find a gerrit for that at 
> https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/171945

Yes, exactly. But why did you abandon it?
Comment 4 Sarika Sinha CLA 2021-05-07 03:32:14 EDT
@Holger,
Where do you see these AST conversion being called in a multi threaded environment?

We need to understand if we really face this issue or it is just by code inspection we see this as an issue.
Comment 5 Holger Voormann CLA 2021-05-07 03:58:25 EDT
(In reply to Sarika Sinha from comment #4)
> @Holger,
> Where do you see these AST conversion being called in a multi threaded
> environment?
> 
> We need to understand if we really face this issue or it is just by code
> inspection we see this as an issue.
The comments say:
// lazy init must be thread-safe for readers

The "Double-Checked Locking" idiom is used incorrectly here. Maybe it is no longer needed, but then it has to be removed.
Comment 6 Carsten Hammer CLA 2021-05-07 12:54:16 EDT
(In reply to Holger Voormann from comment #3)
> (In reply to Carsten Hammer from comment #2)
> > You can find a gerrit for that at 
> > https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/171945
> 
> Yes, exactly. But why did you abandon it?

Oh, I still think the gerrit is basically right (while there is a slightly nicer coding pattern that is equally right) but after experience in

https://git.eclipse.org/r/c/platform/eclipse.platform.ui/+/173575

and 

https://git.eclipse.org/r/c/jdt/eclipse.jdt.ui/+/173560

I felt there is no chance to get that changed and gave up for the moment. It is not so important at the moment for me.
Besides just pointing to publications regarding wrong and right coding patterns are not seen as valid measure to change coding in general in the jdt communiy. You have to create a failing junit test to prove it is wrong especially as non-commiter and even then it can be difficult. I have not the time currently to prepare all this.

And there are no open bugzillas directly related to this issue which is a very convincing argument imho.
Feel free to pick it up.
Comment 7 Eclipse Genie CLA 2023-05-03 20:18:20 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.