Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 323630 - Expanding registers in the register view triggers an infinite recursion loop in Eclipse/CDI.
Summary: Expanding registers in the register view triggers an infinite recursion loop ...
Status: RESOLVED FIXED
Alias: None
Product: CDT
Classification: Tools
Component: cdt-debug-cdi (show other bugs)
Version: 7.0   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 7.0.1   Edit
Assignee: Anton Leherbauer CLA
QA Contact: John Cortell CLA
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-08-25 12:01 EDT by Nicolas Blanc CLA
Modified: 2010-09-08 03:23 EDT (History)
3 users (show)

See Also:


Attachments
Suggested fix (2.13 KB, patch)
2010-09-03 05:13 EDT, Anton Leherbauer CLA
aleherb+eclipse: iplog-
Details | Diff
Alternative fix (3.55 KB, patch)
2010-09-03 07:19 EDT, Teodor Madan CLA
teodor.madan: iplog-
Details | Diff
patch for getting correctly value of a register child (1.22 KB, patch)
2010-09-03 07:26 EDT, Teodor Madan CLA
teodor.madan: iplog-
Details | Diff
patch for getting value of register child (updated) (2.77 KB, patch)
2010-09-03 09:47 EDT, Teodor Madan CLA
teodor.madan: iplog-
Details | Diff
patch for getting value of register child (update2) (2.35 KB, patch)
2010-09-06 06:46 EDT, Teodor Madan CLA
teodor.madan: iplog-
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Nicolas Blanc CLA 2010-08-25 12:01:21 EDT
Build Identifier: I20100608-0911

The function 'org.eclipse.cdt.debug.core.code.cdi.model.ICDIVariable#getValue()'
builds and returns a new value if the current value is 'null'. If the the current variable
is of type ICDIArrayType the method calls 'getHexAddress()':

value = new Array(this, getHexAddress()); // Variable.java, Line 366

The problem is that getHexAddress() calls getValue() again, which creates an infinite loop:

hexAddress = v.getValue().getValueString(); // Variable.java, Line 168

So it is wrong to call 'getHexAddress()' from 'getValue()' if 'value' is 'null'.

This line:

value = new Array(this, getHexAddress()); // Variable.java, Line 366

should be:

value = new Array(this, null); // Variable.java, Line 366




Reproducible: Always

Steps to Reproduce:
Happens every time with the Intel debugger
when trying to expand XMM registers in the register window.
Comment 1 Anton Leherbauer CLA 2010-09-02 04:54:13 EDT
I think it would help to see a stacktrace of the infinite loop / recursion.
Comment 2 Nicolas Blanc CLA 2010-09-02 07:57:12 EDT
(In reply to comment #1)
> I think it would help to see a stacktrace of the infinite loop / recursion.

Sure, please see below the stack and mi traces. Big registers, e.g., XMM registers, are represented as arrays. The address of the arrays that are stored in registers is thus undefined, but Eclipse keeps asking for an address in a recursive fashion.

Regards,

Nicolas

==============================================

Stack trace:

Register(Variable).getValue() line: 364 
Register(Variable).getHexAddress() line: 166    
Register(Variable).getValue() line: 364 
Register(Variable).getHexAddress() line: 166    
Register(Variable).getValue() line: 364 
Register(Variable).getHexAddress() line: 166    
Register(Variable).getValue() line: 364 
Register(Variable).getHexAddress() line: 166    
Register(Variable).getValue() line: 364 
Register(Variable).getHexAddress() line: 166    
Register(Variable).getValue() line: 364 
Register(Variable).getHexAddress() line: 166    
Register(Variable).getValue() line: 364 
Register(Variable).getHexAddress() line: 166    
Register(Variable).getValue() line: 364 
Register(Variable).getHexAddress() line: 166    
Register(Variable).getValue() line: 364 
Register(Variable).getHexAddress() line: 166    
Register(Variable).getValue() line: 364 
Register(Variable).getHexAddress() line: 166    
Register(Variable).getValue() line: 364 
Register(Variable).getHexAddress() line: 166    
Register(Variable).getValue() line: 364 
Register(Variable).getHexAddress() line: 166    
Register(Variable).getValue() line: 364 
CLocalVariable$InternalVariable.getValue() line: 213    
CLocalVariable(CVariable).getValue() line: 251  
CVariableLabelProvider.getLabel(TreePath, IPresentationContext, String) line: 46    
CVariableLabelProvider(ElementLabelProvider).getLabel(TreePath, IPresentationContext, String, int) line: 312    
CVariableLabelProvider(ElementLabelProvider).retrieveLabel(ILabelUpdate) line: 215  
ElementLabelProvider$LabelUpdater.run() line: 160   
ElementLabelProvider$LabelJob.run(IProgressMonitor) line: 74    
Worker.run() line: 54


Here is the mi trace:


[1,283,419,238,628] 164^done,lang="C++",expr="$xmm0"
[1,283,419,238,629] (gdb) 
[1,283,419,247,416] 165-var-create - * &(($xmm0).v16_int8)
[1,283,419,247,424] 165^done,name="var53",numchild="16",value="", type="short:8 [16]"
[1,283,419,247,425] 166-var-set-format var53 hexadecimal
[1,283,419,247,425] (gdb) 
[1,283,419,247,430] 166^done,format="hexadecimal", value=""
[1,283,419,247,431] (gdb) 
[1,283,419,252,815] 167-var-set-format var53 hexadecimal
[1,283,419,252,818] 167^done,format="hexadecimal", value=""
[1,283,419,252,819] (gdb) 
[1,283,419,254,336] 168-var-set-format var53 hexadecimal
[1,283,419,254,340] 168^done,format="hexadecimal", value=""
[1,283,419,254,341] (gdb) 
[1,283,419,255,135] 169-var-set-format var53 hexadecimal
[1,283,419,255,140] 169^done,format="hexadecimal", value=""
[1,283,419,255,141] (gdb) 
[1,283,419,255,814] 170-var-set-format var53 hexadecimal
[1,283,419,255,818] 170^done,format="hexadecimal", value=""
[1,283,419,255,819] (gdb) 
[1,283,419,256,647] 171-var-set-format var53 hexadecimal
[1,283,419,256,650] 171^done,format="hexadecimal", value=""
[1,283,419,256,651] (gdb) 
[1,283,419,257,351] 172-var-set-format var53 hexadecimal
[1,283,419,257,354] 172^done,format="hexadecimal", value=""
[1,283,419,257,355] (gdb) 
[1,283,419,259,095] 173-var-set-format var53 hexadecimal
[1,283,419,259,098] 173^done,format="hexadecimal", value=""
[1,283,419,259,101] (gdb) 
[1,283,419,259,699] 174-var-set-format var53 hexadecimal
[1,283,419,259,701] 174^done,format="hexadecimal", value=""
[1,283,419,259,703] (gdb) 
[1,283,419,260,213] 175-var-set-format var53 hexadecimal
[1,283,419,260,215] 175^done,format="hexadecimal", value=""
[1,283,419,260,218] (gdb) 
[1,283,419,260,788] 176-var-set-format var53 hexadecimal
[1,283,419,260,791] 176^done,format="hexadecimal", value=""
[1,283,419,260,793] (gdb) 
[1,283,419,261,181] 177-var-set-format var53 hexadecimal
[1,283,419,261,185] 177^done,format="hexadecimal", value=""
[1,283,419,261,186] (gdb)
Comment 3 Anton Leherbauer CLA 2010-09-03 03:21:48 EDT
I am not very familiar with this code, so I wonder if it can make sense to call getHexAddress() for other cases, i.e. we might break something if we just replace the call with 'null'?
Have you tried with the DSF-GDB debugger yet?  CDI is considered unsupported since 7.0.
Comment 4 Nicolas Blanc CLA 2010-09-03 04:32:27 EDT
(In reply to comment #3)
> I am not very familiar with this code, so I wonder if it can make sense to call
> getHexAddress() for other cases, i.e. we might break something if we just
> replace the call with 'null'?
> Have you tried with the DSF-GDB debugger yet?  CDI is considered unsupported
> since 7.0.


So instead of

value = new ArrayValue(this, getHexAddress());

What about:

value = new ArrayValue(this, hexAddress);

This would stop the recursion if the address is undefined without
much impact on other cases. This bug does only occur in CDI mode but
we need to keep supporting it.

Thx,

Nicolas
Comment 5 Anton Leherbauer CLA 2010-09-03 05:12:31 EDT
(In reply to comment #4)
> So instead of
> 
> value = new ArrayValue(this, getHexAddress());
> 
> What about:
> 
> value = new ArrayValue(this, hexAddress);
> 
> This would stop the recursion if the address is undefined without
> much impact on other cases. This bug does only occur in CDI mode but
> we need to keep supporting it.

This would be basically the same as new ArrayValue(this, null), because hexAddress is only initialized upon the first call to getHexAddress() and getHexAddress() is only called from getValue(), therefore it will always be null.
I'll attach a patch with my suggested solution from comment 3.
Comment 6 Anton Leherbauer CLA 2010-09-03 05:13:24 EDT
Created attachment 178125 [details]
Suggested fix

Could you try this?
Comment 7 Nicolas Blanc CLA 2010-09-03 05:34:05 EDT
(In reply to comment #6)
> Created an attachment (id=178125) [details]
> Suggested fix
> Could you try this?

Your patch fixes this issue and is more general. I am playing
with the debugger and everything looks right.

Thanks for your prompt answer.

Nicolas
Comment 8 Anton Leherbauer CLA 2010-09-03 05:46:40 EDT
Excellent.  I tested with GDB and everything seems to be normal.
Do you need a fix in 7.0.1?
Comment 9 Nicolas Blanc CLA 2010-09-03 05:50:51 EDT
(In reply to comment #8)
> Excellent.  I tested with GDB and everything seems to be normal.
> Do you need a fix in 7.0.1?

That would be perfect.
Comment 10 Anton Leherbauer CLA 2010-09-03 05:58:43 EDT
John, would you review my changes before I commit?
Comment 11 Teodor Madan CLA 2010-09-03 07:17:00 EDT
(In reply to comment #6)
> Created an attachment (id=178125) [details]
> Suggested fix
> 
Actually a memory mapped register can have an address
Comment 12 Teodor Madan CLA 2010-09-03 07:19:36 EDT
Created attachment 178131 [details]
Alternative fix

Alternative fix. Hexadecimal address is needed only later when the array pointer value is needed. Postpone this.
Comment 13 Teodor Madan CLA 2010-09-03 07:26:31 EDT
Created attachment 178132 [details]
patch for getting correctly value of a register child

Also, recursion is  due to find mi register algorithm that does not take in account that a register variable can have children. Thus the search should check for the qualified name as well. 

i.e. "$mm4" should be a different variable object then "&($mm4)"
Comment 14 Nicolas Blanc CLA 2010-09-03 07:36:31 EDT
(In reply to comment #11)
> (In reply to comment #6)
> > Created an attachment (id=178125) [details] [details]
> > Suggested fix
> > 
> Actually a memory mapped register can have an address

Shouldn't a memory mapped register be treated as a volatile variable?
Comment 15 Nicolas Blanc CLA 2010-09-03 08:26:51 EDT
(In reply to comment #12)
> Created an attachment (id=178131) [details]
> Alternative fix
> Alternative fix. Hexadecimal address is needed only later when the array
> pointer value is needed. Postpone this.

This solution works for me too.
Comment 16 Anton Leherbauer CLA 2010-09-03 08:32:14 EDT
(In reply to comment #13)
> Created an attachment (id=178132) [details]
> patch for getting correctly value of a register child
> 
> Also, recursion is  due to find mi register algorithm that does not take in
> account that a register variable can have children. Thus the search should
> check for the qualified name as well. 
> 
> i.e. "$mm4" should be a different variable object then "&($mm4)"

Looks like this patch alone should already take care of the recursion?
I suggest to use this patch for 7.0.1.
The "Alternative fix" adds new API which is not allowed on a maintenance branch.

I would also add a check in getHexAddress() to test for an immediate recursion:

    // make sure to avoid infinite recursion
    if (v != this) {
        v.setFormat(ICDIFormat.HEXADECIMAL);
        hexAddress = v.getValue().getValueString();
    } else {
        hexAddress = "";
    }
Comment 17 Teodor Madan CLA 2010-09-03 09:47:32 EDT
Created attachment 178143 [details]
patch for getting value of register child (updated)

Incorporate Toni's feedback
Comment 18 Teodor Madan CLA 2010-09-03 09:53:00 EDT
(In reply to comment #16)
> Looks like this patch alone should already take care of the recursion?
> I suggest to use this patch for 7.0.1.
> The "Alternative fix" adds new API which is not allowed on a maintenance
> branch.
> 

Agree. Though I would still commit on head. To lessen the cost of creating ArrayValue objects.

> I would also add a check in getHexAddress() to test for an immediate recursion:
> 
Done in the updated patch.

Nicolas, could you please check if applying only register child value patch works on Intel debugger as well?

Thank you,
Teo
Comment 19 Nicolas Blanc CLA 2010-09-03 11:20:09 EDT
(In reply to comment #18)
> (In reply to comment #16)
> > Looks like this patch alone should already take care of the recursion?
> > I suggest to use this patch for 7.0.1.
> > The "Alternative fix" adds new API which is not allowed on a maintenance
> > branch.
> > 
> Agree. Though I would still commit on head. To lessen the cost of creating
> ArrayValue objects.
> > I would also add a check in getHexAddress() to test for an immediate recursion:
> > 
> Done in the updated patch.
> Nicolas, could you please check if applying only register child value patch
> works on Intel debugger as well?
> Thank you,
> Teo

Hmm, the expressions I see are much more complex and recursion is still there.
I need to check if it's not a problem on my side. So I'll post an update on Monday.
Comment 20 Teodor Madan CLA 2010-09-06 05:15:44 EDT
(In reply to comment #19)

> 
> Hmm, the expressions I see are much more complex and recursion is still there.
> I need to check if it's not a problem on my side. So I'll post an update on
> Monday.

The difference most likely are due to register children type how they are reported, and being interpreted as array for Intel debugger

with intel debugger:
165-var-create - * &(($xmm0).v16_int8)
165^done,name="var53",numchild="16",value="",type="short:8[16]"

with mingw gdb debugger (gdb 7.1):
1860-var-create - * &(($xmm0).v16_int8)
1860^done,name="var101",numchild="1",value="",type="int8_t (*)[16]"

"int8_t (*)[16]" is interpreted as pointer to 16 element array of int8_t, while "short:8[16]" most probably is interpreted as 16 element array of "short:8"

I am not very familiar with gdb type parser, but the call to
org.eclipse.cdt.debug.mi.core.cdi.SourceManager.getType(Target, String) would be the starting point.
Comment 21 Anton Leherbauer CLA 2010-09-06 05:37:37 EDT
(In reply to comment #17)
> Created an attachment (id=178143) [details]
> patch for getting value of register child (updated)
> 
> Incorporate Toni's feedback

The patch contains a suspicious diff:

@@ -353,8 +358,8 @@
 			} else if (t instanceof ICDIFloatType) {
 				value = new FloatValue(this);
 			} else if (t instanceof ICDIDoubleType) {
-				value = new DoubleValue(this);
 			} else if (t instanceof ICDIFunctionType) {
+				value = new DoubleValue(this);
 				value = new FunctionValue(this);
 			} else if (t instanceof ICDIPointerType) {
 				value = new PointerValue(this);

I don't think you intended that change.
Comment 22 Teodor Madan CLA 2010-09-06 06:46:49 EDT
Created attachment 178256 [details]
 patch for getting value of register child (update2) 

remove unintended change
Comment 23 Nicolas Blanc CLA 2010-09-06 06:56:13 EDT
(In reply to comment #22)
> Created an attachment (id=178256) [details]
>  patch for getting value of register child (update2) 
> remove unintended change


My eclipse workspace is kind of mess up. I am getting a unresolved compilation problem when lauching eclipse in debug mode:

java.lang.Error: Unresolved compilation problem:
Comment 24 Nicolas Blanc CLA 2010-09-06 07:08:20 EDT
(In reply to comment #23)
 (In reply to comment #22)
 > Created an attachment (id=178256) [details] [details]
 >  patch for getting value of register child (update2) 
 > remove unintended change
 My eclipse workspace is kind of mess up. I am getting a unresolved compilation
 problem when lauching eclipse in debug mode:
 java.lang.Error: Unresolved compilation problem:

"!MESSAGE An internal error occurred during: "Initiating resource change handling..".
!STACK 0
java.lang.Error: Unresolved compilation problem: 
    The method addSaveParticipant(Plugin, ISaveParticipant) in the type IWorkspace is not applicable for the arguments (String, ResourceChangeHandler)

    at org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager.startSaveParticipant(CProjectDescriptionManager.java:362)
    at org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager.access$1(CProjectDescriptionManager.java:359)
    at org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager$3.run(CProjectDescriptionManager.java:334)
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)"


I am using the CDT revision from HEAD with eclipse 3.6.0. Everything looks fine when I compile the CDT sources.  Did anyone experience a similar issue?
Comment 25 Anton Leherbauer CLA 2010-09-06 08:02:43 EDT
(In reply to comment #24)
> I am using the CDT revision from HEAD with eclipse 3.6.0. Everything looks fine
> when I compile the CDT sources.  Did anyone experience a similar issue?

This works for me in my HEAD workspace.  Maybe you need to do a clean build and/or check the runtime plug-ins in your launch configuration.
Comment 26 Anton Leherbauer CLA 2010-09-07 05:46:47 EDT
To make some progress, I am going to commit my suggest change from comment 16 to cdt_7_0 (without any other changes).
This is a safe change and should address the infinite recursion originally reported.
Comment 27 CDT Genie CLA 2010-09-07 06:23:02 EDT
*** cdt cvs genie on behalf of aleherbau ***
Bug 323630 - Expanding registers in the register view triggers an infinite recursion loop in Eclipse/CDI

[*] Variable.java 1.37.2.1 http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.cdt/all/org.eclipse.cdt.debug.mi.core/cdi/org/eclipse/cdt/debug/mi/core/cdi/model/Variable.java?root=Tools_Project&r1=1.37&r2=1.37.2.1
Comment 28 Nicolas Blanc CLA 2010-09-07 12:18:49 EDT
(In reply to comment #27)
> *** cdt cvs genie on behalf of aleherbau ***
> Bug 323630 - Expanding registers in the register view triggers an infinite
> recursion loop in Eclipse/CDI
> [*] Variable.java 1.37.2.1
> http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.cdt/all/org.eclipse.cdt.debug.mi.core/cdi/org/eclipse/cdt/debug/mi/core/cdi/model/Variable.java?root=Tools_Project&r1=1.37&r2=1.37.2.1

The bug does not show up anymore :-).

Thanks,

Nicolas
Comment 29 Anton Leherbauer CLA 2010-09-08 03:06:36 EDT
Thanks Nicolas.
Teo, I committed your patches to HEAD.