Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 337486

Summary: AbstractIndexAstChecker allows AST to outlive index read lock
Product: [Tools] CDT Reporter: Sergey Prigogin <eclipse.sprigogin>
Component: cdt-codanAssignee: Sergey Prigogin <eclipse.sprigogin>
Status: RESOLVED FIXED QA Contact: Elena Laskavaia <elaskavaia.cdt>
Severity: critical    
Priority: P3 CC: cdtdoug, malaperle
Version: 8.0Flags: eclipse.sprigogin: review+
Target Milestone: 8.0   
Hardware: PC   
OS: Linux   
Whiteboard:
Attachments:
Description Flags
Proposed fix
eclipse.sprigogin: iplog-
New proposed fix.
eclipse.sprigogin: iplog-
New fix with minor modifications
eclipse.sprigogin: iplog-
Final version of the fix eclipse.sprigogin: iplog-

Description Sergey Prigogin CLA 2011-02-17 15:23:46 EST
An index-based AST should never be accessed after releasing the read index lock that was held when the AST was created. Failure to do so may result in errors like:

java.lang.ArrayIndexOutOfBoundsException: 4422
       at org.eclipse.cdt.internal.core.pdom.db.Database.getChunk(Database.java:274)
       at org.eclipse.cdt.internal.core.pdom.db.Database.getByte(Database.java:461)
       at org.eclipse.cdt.internal.core.pdom.dom.cpp.PDOMCPPClassType.isAnonymous(PDOMCPPClassType.java:231)
       at org.eclipse.cdt.internal.core.pdom.dom.cpp.PDOMCPPClassScope$PopulateMap.visit(PDOMCPPClassScope.java:75)
       at org.eclipse.cdt.internal.core.pdom.dom.cpp.PDOMCPPClassScope.getBindingMap(PDOMCPPClassScope.java:236)
       at org.eclipse.cdt.internal.core.pdom.dom.cpp.PDOMCPPClassScope.getBindingsViaCache(PDOMCPPClassScope.java:174)
       at org.eclipse.cdt.internal.core.pdom.dom.cpp.PDOMCPPClassScope.getBindings(PDOMCPPClassScope.java:156)
       at org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics.getBindingsFromScope(CPPSemantics.java:1196)
       at org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics.lookup(CPPSemantics.java:920)
       at org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics.resolveBinding(CPPSemantics.java:251)
       at org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor.resolveBinding(CPPVisitor.java:1230)
       at org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor.createBinding(CPPVisitor.java:272)
       at org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName.createIntermediateBinding(CPPASTName.java:55)
       at org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase.resolveBinding(CPPASTNameBase.java:86)
       at org.eclipse.cdt.codan.internal.checkers.ProblemBindingChecker$1.visit(ProblemBindingChecker.java:71)
       at org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName.accept(CPPASTName.java:157)
       at org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFieldReference.accept(CPPASTFieldReference.java:177)
       at org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFunctionCallExpression.accept(CPPASTFunctionCallExpression.java:168)
       at org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTExpressionStatement.accept(CPPASTExpressionStatement.java:65)
       at org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTCompoundStatement.accept(CPPASTCompoundStatement.java:72)
       at org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFunctionDefinition.accept(CPPASTFunctionDefinition.java:181)
       at org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit.accept(ASTTranslationUnit.java:271)
       at org.eclipse.cdt.codan.internal.checkers.ProblemBindingChecker.processAst(ProblemBindingChecker.java:63)
       at org.eclipse.cdt.codan.core.cxx.model.AbstractIndexAstChecker.processFile(AbstractIndexAstChecker.java:58)
       at org.eclipse.cdt.codan.core.cxx.model.AbstractIndexAstChecker.processResource(AbstractIndexAstChecker.java:70)
       at org.eclipse.cdt.codan.internal.core.CodanBuilder.processResource(CodanBuilder.java:133)
       at org.eclipse.cdt.codan.internal.core.CodanBuilder.processResource(CodanBuilder.java:94)
       at org.eclipse.cdt.codan.internal.core.CodanBuilder.processResource(CodanBuilder.java:159)
       at org.eclipse.cdt.codan.internal.core.CodanBuilder.processResource(CodanBuilder.java:94)
       at org.eclipse.cdt.codan.internal.core.CodanBuilder.processResource(CodanBuilder.java:159)
       at org.eclipse.cdt.codan.internal.core.CodanBuilder.processResource(CodanBuilder.java:94)
       at org.eclipse.cdt.codan.internal.core.CodanBuilder.processResource(CodanBuilder.java:159)
       at org.eclipse.cdt.codan.internal.core.CodanBuilder.processResource(CodanBuilder.java:94)
       at org.eclipse.cdt.codan.internal.ui.actions.RunCodeAnalysis$1.run(RunCodeAnalysis.java:59)
       at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
Comment 1 Sergey Prigogin CLA 2011-02-17 19:16:16 EST
Codan may use something similar to RefactoringASTCache to implement proper index locking. If it makes sense to reuse the same class, RefactoringASTCache can be moved to core and renamed to remove explicit reference to refactoring.
Comment 2 Elena Laskavaia CLA 2011-02-23 21:29:00 EST
Where is this class I cannot even find it? Yes it would be good to use common one because that is what I am trying to do here too - ast cache
Comment 3 Marc-André Laperle CLA 2011-02-23 21:41:30 EST
org.eclipse.cdt.internal.ui.refactoring.RefactoringASTCache
It should be there if you type it in Open Type (Ctrl+shift+t).

I think it would make sense to move this to core. It will be useful for quick fixes especially. There is already a class called ASTCache though. ASTCash, Alena? ;)
Comment 4 Sergey Prigogin CLA 2011-02-23 23:14:57 EST
I've realized that RefactoringASTCache cannot be moved to core since it depends on org.eclipse.cdt.internal.ui.editor.ASTProvider. We can rename it to DisposableASTCache though.
Comment 5 Sergey Prigogin CLA 2011-04-08 23:07:17 EDT
Created attachment 192884 [details]
Proposed fix

I had to make few backward-incompatible API changes. CxxModelsCache is no longer a singleton. ICAstChecker has been moved to an internal package since we don't expect users to implement it without subclassing AbstractIndexAstChecker.

Interaction between CodanBuilder, AbstractIndexAstChecker and CxxModelsCache could be simplified if they all were located in the same plugin. What is the reason for keeping org.eclipse.cdt.codan.core and org.eclipse.cdt.codan.core.cxx separate?
Comment 6 Elena Laskavaia CLA 2011-04-09 14:17:30 EDT
Reason is to keep cdt part separates so people who could integrate other languages do not need to pull cdt in
Comment 7 Elena Laskavaia CLA 2011-04-09 14:19:50 EDT
In you fix I think you are adding dependency from codan.core to codan.cxx.core I do not want this dependency for reasons outlines above
Comment 8 Elena Laskavaia CLA 2011-04-09 14:48:35 EDT
You patch does not apply on trunk. I did some changes for comments support couple week ago I think you did not update it since
Comment 9 Elena Laskavaia CLA 2011-04-09 15:06:15 EDT
We can add this interface to get rid of this dependency



package org.eclipse.cdt.codan.core.model;

import org.eclipse.core.resources.IFile;

/**
 * Interface for checkers that can be run when user is typing, checker has to be
 * very quick to run in this mode
 * <p>
 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as part
 * of a work in progress. There is no guarantee that this API will work or that
 * it will remain the same.
 * </p>
 *
 * @noextend This interface is not intended to be extended by clients.
 * @since 2.0
 */
public interface IRunnableInEditorCheckerWithSharedModel extends IRunnableInEditorChecker{
	/**
	 * @param file - current file
	 * @param model - shared code mode
	 */
	Object processModel(IFile file, Object model) throws InterruptedException;
}
Comment 10 Elena Laskavaia CLA 2011-04-09 15:08:54 EDT
Another problem - it suppose to be inter-procedural (inter-file) cache.
Some checkers require access to multiple ast  - it suppose to cache results of this - how does it suppose to work now?
Comment 11 Sergey Prigogin CLA 2011-04-09 23:00:00 EDT
Created attachment 192895 [details]
New proposed fix.

Here is a much cleaner solution. It doesn't introduce any plugin dependencies but doesn't sacrifice type safety either. I think it addressed all the comments.
Comment 12 Sergey Prigogin CLA 2011-04-09 23:03:33 EDT
(In reply to comment #10)
> Another problem - it suppose to be inter-procedural (inter-file) cache.
> Some checkers require access to multiple ast  - it suppose to cache results of
> this - how does it suppose to work now?

I added methods that accept ITranslationUnit. ITranslationUnit is preferable to IFile since conceivably checkers may use an AST of a header file that is located outside workspace.
Comment 13 Sergey Prigogin CLA 2011-04-10 16:30:10 EDT
Created attachment 192908 [details]
New fix with minor modifications

Added context parameter to IRunnableInEditorChecker.processModel method.
Comment 14 Elena Laskavaia CLA 2011-04-11 09:22:44 EDT
I was thinking too of breaking API by changing processModel signature. It should not be that bad since nobody should really use this method directly?
Do you want to post this API breaking on CDT forum just to make sure?
Comment 15 Sergey Prigogin CLA 2011-04-11 15:35:48 EDT
Created attachment 192966 [details]
Final version of the fix
Comment 16 Elena Laskavaia CLA 2011-04-11 21:41:45 EDT
Btw I don't remember why before and after return boolean in IChecker. If you can't think of anything either may as well change to void while we breaking API's
Comment 17 Elena Laskavaia CLA 2011-04-11 21:44:22 EDT
And if context is not stored in checker we should pass it before, after and enabledInContext functions too
Comment 18 Sergey Prigogin CLA 2011-04-11 21:55:37 EDT
(In reply to comment #16)
> Btw I don't remember why before and after return boolean in IChecker. If you
> can't think of anything either may as well change to void while we breaking
> API's

I have doubts about 'before' and 'after' methods. They complicate the API and look unnecessary to me.
Comment 19 Sergey Prigogin CLA 2011-04-11 21:59:48 EDT
(In reply to comment #17)
> And if context is not stored in checker we should pass it before, after and
> enabledInContext functions too

Unfortunately, several objects are stored inside a checker. That includes context, problemReporter and modelCache. Ideally, checkers should be stateless, but they were not stateless before my change.
Comment 20 Elena Laskavaia CLA 2011-04-12 16:34:21 EDT
ok just commit what you have, we can discuss further changes later
Comment 21 Sergey Prigogin CLA 2011-04-12 18:14:37 EDT
Fixed in HEAD > 20110412.
Comment 22 CDT Genie CLA 2011-04-12 18:23:09 EDT
*** cdt cvs genie on behalf of sprigogin ***
Bug 337486 - AbstractIndexAstChecker allows AST to outlive index read lock.

[*] AbstractIndexAstChecker.java 1.18 http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.cdt/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/model/AbstractIndexAstChecker.java?root=Tools_Project&r1=1.17&r2=1.18
[*] CxxModelsCache.java 1.9 http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.cdt/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/model/CxxModelsCache.java?root=Tools_Project&r1=1.8&r2=1.9

[*] ReturnChecker.java 1.20 http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.cdt/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ReturnChecker.java?root=Tools_Project&r1=1.19&r2=1.20

[*] CodanFastCxxAstTestCase.java 1.5 http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.cdt/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/CodanFastCxxAstTestCase.java?root=Tools_Project&r1=1.4&r2=1.5

[+] ICodanDisposable.java  http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.cdt/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/ICodanDisposable.java?root=Tools_Project&revision=1.1&view=markup
[*] AbstractChecker.java 1.18 http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.cdt/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java?root=Tools_Project&r1=1.17&r2=1.18
[*] IRunnableInEditorChecker.java 1.4 http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.cdt/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IRunnableInEditorChecker.java?root=Tools_Project&r1=1.3&r2=1.4
[*] IChecker.java 1.10 http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.cdt/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/IChecker.java?root=Tools_Project&r1=1.9&r2=1.10
[*] ICheckerInvocationContext.java 1.2 http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.cdt/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/ICheckerInvocationContext.java?root=Tools_Project&r1=1.1&r2=1.2

[*] CheckerInvocationContext.java 1.3 http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.cdt/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CheckerInvocationContext.java?root=Tools_Project&r1=1.2&r2=1.3
[*] CodanBuilder.java 1.20 http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.cdt/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanBuilder.java?root=Tools_Project&r1=1.19&r2=1.20
Comment 23 Andrew Gvozdev CLA 2011-04-13 10:40:33 EDT
I installed the latest Hudson build 642 today and now having deadlocks related to AST:

"Worker-0" prio=6 tid=0x52153800 nid=0x1228 waiting for monitor entry [0x5434f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.eclipse.cdt.internal.core.model.ASTCache.releaseSharedAST(ASTCache.java:259)
	- waiting to lock <0x12b61908> (a java.lang.Object)
	at org.eclipse.cdt.internal.core.model.ASTCache.runOnAST(ASTCache.java:231)
	at org.eclipse.cdt.internal.ui.editor.ASTProvider.runOnAST(ASTProvider.java:334)
	at org.eclipse.cdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup.calculateASTandInform(SelectionListenerWithASTManager.java:168)
	at org.eclipse.cdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup$3.run(SelectionListenerWithASTManager.java:142)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)

"main" prio=6 tid=0x008f6800 nid=0x170c waiting for monitor entry [0x0012f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.eclipse.cdt.internal.ui.editor.ASTProvider.canUseCache(ASTProvider.java:373)
	- waiting to lock <0x12b3e640> (a org.eclipse.cdt.internal.ui.editor.ASTProvider)
	at org.eclipse.cdt.internal.ui.editor.ASTProvider.runOnAST(ASTProvider.java:332)
	at org.eclipse.cdt.internal.ui.editor.CElementHyperlinkDetector.detectHyperlinks(CElementHyperlinkDetector.java:71)
	at org.eclipse.ui.texteditor.HyperlinkDetectorRegistry$HyperlinkDetectorDelegate.detectHyperlinks(HyperlinkDetectorRegistry.java:80)
	at org.eclipse.jface.text.hyperlink.HyperlinkManager.findHyperlinks(HyperlinkManager.java:286)
	- locked <0x05ee3070> (a [Lorg.eclipse.jface.text.hyperlink.IHyperlinkDetector;)
	at org.eclipse.jface.text.hyperlink.HyperlinkManager.findHyperlinks(HyperlinkManager.java:258)


"Worker-11" prio=6 tid=0x540c6800 nid=0x480 waiting for monitor entry [0x5913f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.eclipse.cdt.internal.core.model.ASTCache.isActiveElement(ASTCache.java:371)
	- waiting to lock <0x12b61908> (a java.lang.Object)
	at org.eclipse.cdt.internal.ui.editor.ASTProvider.canUseCache(ASTProvider.java:373)
	- locked <0x12b3e640> (a org.eclipse.cdt.internal.ui.editor.ASTProvider)
	at org.eclipse.cdt.internal.ui.editor.ASTProvider.runOnAST(ASTProvider.java:332)
	at org.eclipse.cdt.internal.ui.search.actions.OpenDeclarationsJob.performNavigation(OpenDeclarationsJob.java:144)
	at org.eclipse.cdt.internal.ui.search.actions.OpenDeclarationsJob.run(OpenDeclarationsJob.java:120)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)

   Locked ownable synchronizers:
	- None

"Worker-10" prio=6 tid=0x549d0400 nid=0x1500 waiting for monitor entry [0x5903f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.eclipse.cdt.internal.ui.editor.ASTProvider.canUseCache(ASTProvider.java:373)
	- waiting to lock <0x12b3e640> (a org.eclipse.cdt.internal.ui.editor.ASTProvider)
	at org.eclipse.cdt.internal.ui.editor.ASTProvider.runOnAST(ASTProvider.java:332)
	at org.eclipse.cdt.internal.ui.search.actions.OpenDeclarationsJob.performNavigation(OpenDeclarationsJob.java:144)
	at org.eclipse.cdt.internal.ui.search.actions.OpenDeclarationsJob.run(OpenDeclarationsJob.java:120)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)

"Worker-4" prio=6 tid=0x54882400 nid=0x1784 waiting on condition [0x58a3f000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x0349aed8> (a java.util.concurrent.Semaphore$NonfairSync)
	at java.util.concurrent.locks.LockSupport.park(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(Unknown Source)
	at java.util.concurrent.Semaphore.acquire(Unknown Source)
	at org.eclipse.cdt.internal.core.model.ASTCache.acquireSharedAST(ASTCache.java:248)
	- locked <0x12b61908> (a java.lang.Object)
	at org.eclipse.cdt.internal.core.model.ASTCache.runOnAST(ASTCache.java:223)
	at org.eclipse.cdt.internal.ui.editor.ASTProvider.runOnAST(ASTProvider.java:334)
	at org.eclipse.cdt.internal.ui.search.actions.OpenDeclarationsJob.performNavigation(OpenDeclarationsJob.java:144)
Comment 24 Sergey Prigogin CLA 2011-04-13 17:41:12 EDT
(In reply to comment #23)
A fix for the deadlock has been submitted.