Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 529450 - Broken or missing LVT entries for unused variables
Summary: Broken or missing LVT entries for unused variables
Status: RESOLVED WONTFIX
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.8.2   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Andrey Loskutov CLA
QA Contact: Stephan Herrmann CLA
URL:
Whiteboard:
Keywords:
: 494225 (view as bug list)
Depends on:
Blocks:
 
Reported: 2018-01-05 07:20 EST by Andrey Loskutov CLA
Modified: 2018-01-13 17:01 EST (History)
1 user (show)

See Also:


Attachments
project with example sources (8.23 KB, application/x-zip-compressed)
2018-01-05 07:20 EST, Andrey Loskutov CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Andrey Loskutov CLA 2018-01-05 07:20:50 EST
Created attachment 272144 [details]
project with example sources

Follow up on https://github.com/spotbugs/spotbugs/issues/516.

I found that ecj does not generate LVT entries for unused local variables, or generates them with wrong pc ranges.

The pattern is common for all *blocks*: if there is only one unused variable defined, LVT entry will be NOT generated for it. If there are more "unused" variables defined, the *last one* will have NO LVT entry, and all other entries will have PC ranges off by one.

This makes bytecode analysis tools like SpotBugs unhappy, because they can't resolve variable names. Such "unused" variables are typical after (bad) merges, so it is important to find and report such places ASAP.

I've attached the example project where the missing / wrong LVT entries can be easily observed in Eclipse with the help of Bytecode Outline view (https://marketplace.eclipse.org/content/bytecode-outline).

Bytecode Outline can resolve "ASTORE 1" to "ASTORE 1: variable" and also shows LVT content with the variable scopes.

I can see that this is broken at least since Eclipse 3.8.2.

See also bug 494225 which is basically the same for lambdas (3.8.2 does not know about lambdas :-)).
Comment 1 Andrey Loskutov CLA 2018-01-05 07:26:42 EST
Stephan, if you could give me a hint where I can look for, I could try to provide a patch and tests for all this.
Comment 2 Stephan Herrmann CLA 2018-01-05 07:27:52 EST
*** Bug 494225 has been marked as a duplicate of this bug. ***
Comment 3 Stephan Herrmann CLA 2018-01-05 07:32:51 EST
(In reply to Andrey Loskutov from comment #1)
> Stephan, if you could give me a hint where I can look for, I could try to
> provide a patch and tests for all this.

That'd be awesome.

I believe most of the magic can be found in BlockScope.computeLocalVariablePositions(int, int, CodeStream)

See that the non-javadoc comment of that method states "ignoring unused local variables", but OTOH there is compilerOptions().preserveAllLocalVariables.

HTH
Comment 4 Stephan Herrmann CLA 2018-01-05 07:33:43 EST
Forgot to mention: we should also add a test using lambdas to make sure bug 494225 is covered as well.
Comment 5 Andrey Loskutov CLA 2018-01-06 18:13:04 EST
I have two variants of a patch, but I fear the current state is by design.

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.13 :


local_variable_table[]

    Each entry in the local_variable_table array indicates a range of code array offsets within which a local variable has a value. It also indicates the index into the local variable array of the current frame at which that local variable can be found. Each entry must contain the following five items:

    start_pc, length

        The given local variable must have a value at indices into the code array in the interval [start_pc, start_pc + length), that is, between start_pc inclusive and start_pc + length exclusive.

        The value of start_pc must be a valid index into the code array of this Code attribute and must be the index of the opcode of an instruction.

        The value of start_pc + length must either be a valid index into the code array of this Code attribute and be the index of the opcode of an instruction, or it must be the first index beyond the end of that code array.


There are two problems in the current code (which seem to be correct according to the spec), and I don't know if we can fix them.

The local variable initial pc is given *after* first store into the variable. This explains that we see "wrong" ranges for all variables (not from the first pc where the variable value is being loaded: at this time the variable is not initialized yet, so according to the spec, we can't use that pc).

The second problem is that class file does not write LVT entries where the pc init and pc end of the variable are equal. This is the case for *last* unused variables in any block, because the pc at block end is same as the last pc from the store into the unused variable. Why this is for blocks and not for simple method bodies? Because in the last case the last pc is the return statement (+1).

The spec itself allows the start pc + lenght to go beyond the actual code array, so I can imagine that we could "fix" missing LVT entries by simply increasing the lenght from zero to one while writing the LVT, but I fear we can't fix the "off by one" pc values for all locals.
Comment 6 Eclipse Genie CLA 2018-01-07 03:50:47 EST
New Gerrit change created: https://git.eclipse.org/r/115033
Comment 7 Eclipse Genie CLA 2018-01-07 03:51:09 EST
New Gerrit change created: https://git.eclipse.org/r/115034
Comment 8 Andrey Loskutov CLA 2018-01-07 03:53:51 EST
(In reply to Eclipse Genie from comment #6)
> New Gerrit change created: https://git.eclipse.org/r/115033

(In reply to Eclipse Genie from comment #7)
> New Gerrit change created: https://git.eclipse.org/r/115034

Both patches breaks class verification :-(
Any ideas are welcome.
Comment 9 Andrey Loskutov CLA 2018-01-13 17:01:46 EST
Since I see no way to resolve this without breaking the spec, closing as won't fix.