Bug 332637 - Dead Code detection removing code that isn't dead
Summary: Dead Code detection removing code that isn't dead
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.6.1   Edit
Hardware: PC Windows XP
: P3 major (vote)
Target Milestone: 3.6.2   Edit
Assignee: Stephan Herrmann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-12-15 09:39 EST by jason.j.kirchhoff CLA
Modified: 2013-07-31 06:37 EDT (History)
6 users (show)

See Also:
daniel_megert: pmc_approved+
amj87.iitr: review+


Attachments
Source Code (1.03 KB, text/java)
2010-12-15 09:41 EST, jason.j.kirchhoff CLA
no flags Details
draft patch (2.32 KB, patch)
2010-12-15 15:10 EST, Ayushman Jain CLA
no flags Details | Diff
proposed patch (10.81 KB, patch)
2010-12-15 18:24 EST, Stephan Herrmann CLA
no flags Details | Diff
same patch, but for 3.6.x (12.47 KB, patch)
2010-12-16 11:00 EST, Stephan Herrmann CLA
no flags Details | Diff
rectified fix for 3.7 (4.29 KB, patch)
2010-12-17 02:16 EST, Ayushman Jain CLA
no flags Details | Diff
rectified fix for 3.6.2 (15.83 KB, patch)
2010-12-17 02:23 EST, Ayushman Jain CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description jason.j.kirchhoff CLA 2010-12-15 09:39:42 EST
Build Identifier: M20100909-0800

See attached source code.

javac produces the following output:
Canceled after 3 times through the loop
number = 3
-1

Eclipse produces the following output:
Canceled after 3 times through the loop
-1

Eclipse is removing the if (number != null) block in the catch when it's not dead code.

Reproducible: Always

Steps to Reproduce:
1. Run attached code compiled with javac.
2. Run attached code compiled with Eclipse.
Comment 1 jason.j.kirchhoff CLA 2010-12-15 09:41:11 EST
Created attachment 185225 [details]
Source Code
Comment 2 Olivier Thomann CLA 2010-12-15 09:44:22 EST
Reproduced using HEAD.
Ayushman, please investigate.
This is a candidate for 3.6.2.
Comment 3 Ayushman Jain CLA 2010-12-15 12:17:54 EST
Seems like the return statement in the try block is causing a problem. Removing it corrects the false warning. Investigating.
Comment 4 Ayushman Jain CLA 2010-12-15 15:10:08 EST
Created attachment 185260 [details]
draft patch

Basically the return statement erases the null info captured in the try block with tryInfo, and that info instead gets captured in handlingContext.initsOnReturn. So when we try to calculate the catch block's catchInfo, using tryInfo turns out futile in the presence of return statement. I attempted to fix that using this patch, but this broke org.eclipse.jdt.core.tests.compiler.regression.NullReferenceTest.test1009(). This is because test1009() is yet another special case where the nullness of a variable is getting affected by an exception throwing method, and the return statement guarantees that the control can only go beyond the try block when the variable has been properly assigned. So the above fix seems insufficient. 

I'll continue investigating this tomorrow. Stephan, meanwhile if you happen to look at the patch and have a better idea of fixing it, let me know.
Comment 5 Stephan Herrmann CLA 2010-12-15 18:24:15 EST
Created attachment 185280 [details]
proposed patch

I do have a proposal :)

The difficulty comes from the difference between definite assignment
analysis (must be conservative as per JLS 16.2.15) and null-analysis
(which we want to perform with more precision).

The existing methods like FlowInfo.addPotentialInitializationsFrom(..)
cannot fully handle both analyses at the desired levels.
My patch does two things:
 - Introduce a new method FlowInfo.addNullInfoFrom(..) which only handles
   null info.
 - Change null-analysis for catch blocks of declared exceptions:
   Use nullInfoLessUnconditionalInfo for most cases and use null info *only*
   from the corresponding initsOnException, as this is the only way to enter
   the catch block.

The effect: the current problem is fixed and additionally three existing
tests now produce the errors that were originally intended.
Comment 6 Ayushman Jain CLA 2010-12-16 04:31:41 EST
(In reply to comment #5)
> Created an attachment (id=185280) [details] [diff]
> proposed patch
> 
> I do have a proposal :)

Thanks Stephan! The patch looks good to me and works for all cases I tried. Please go ahead and release it, once you've added the copyrights. I'm running the complete test suite once on my machine as well.
Comment 7 Ayushman Jain CLA 2010-12-16 06:28:42 EST
(In reply to comment #6)
> [..] I'm running the complete test suite once on my machine as well.

All compiler tests pass.
Comment 8 Stephan Herrmann CLA 2010-12-16 08:04:57 EST
Released for 3.7M5
Comment 9 jason.j.kirchhoff CLA 2010-12-16 08:07:17 EST
Will this also be in 3.6.2?
Comment 10 Stephan Herrmann CLA 2010-12-16 08:16:44 EST
(In reply to comment #9)
> Will this also be in 3.6.2?

I was just checking the behavior with older versions:
- the null-analysis has been wrong since day 1 (within 3.2.x)
- the generated code was still correct until 3.5.2
- only starting from 3.6.0 the compiler performs the wrong optimization

-> IMO we should backport the fix for 3.6.2 as this is a regression over 3.5.2.
The fix is small so backporting shouldn't be hard.

Olivier?
Comment 11 Olivier Thomann CLA 2010-12-16 08:39:45 EST
Daniel, +1 for 3.6.2?

I am in favor of a backport as this is a regression (see comment 10) and there is no workaround.
Comment 12 Dani Megert CLA 2010-12-16 09:55:55 EST
> Daniel, +1 for 3.6.2?
> I am in favor of a backport as this is a regression (see comment 10) and there
> is no workaround.
Removing code is not good. +1 for 3.6.2.
Comment 13 Dani Megert CLA 2010-12-16 09:56:18 EST
.
Comment 14 Stephan Herrmann CLA 2010-12-16 11:00:37 EST
Created attachment 185336 [details]
same patch, but for 3.6.x

Here's the same patch for R3.6_maintenance.
Comment 15 Stephan Herrmann CLA 2010-12-16 11:04:07 EST
Ayush, could you please review for 3.6.2?

I'm also currently running compiler.regression.TestAll.
Comment 16 Stephan Herrmann CLA 2010-12-16 11:07:09 EST
.
Comment 17 Ayushman Jain CLA 2010-12-17 02:16:02 EST
Created attachment 185401 [details]
rectified fix for 3.7

While reviewing this for 3.6.2 I noticed that we had missed out fixing a related issue in the presence of finally block. So in the example code, we still get bad code if we add a finally{} after the catch. 

This patch takes care of this and also adds a corresponding test.
I'll also add this in the fix for 3.6.2 and submit another patch. We should run the compiler tests for 3.7 and 3.6.2 again then.
Comment 18 Ayushman Jain CLA 2010-12-17 02:23:07 EST
Created attachment 185402 [details]
rectified fix for 3.6.2

Fix for R3_6_maintenance.
Comment 19 Stephan Herrmann CLA 2010-12-17 02:45:10 EST
(In reply to comment #17)
> Created an attachment (id=185401) [details]
> rectified fix for 3.7
> 
> While reviewing this for 3.6.2 I noticed that we had missed out fixing a
> related issue in the presence of finally block. So in the example code, we
> still get bad code if we add a finally{} after the catch. 

Good point.

> This patch takes care of this and also adds a corresponding test.
> I'll also add this in the fix for 3.6.2 and submit another patch. We should run
> the compiler tests for 3.7 and 3.6.2 again then.

Patches look good to me.
Comment 20 Ayushman Jain CLA 2010-12-17 04:42:51 EST
(In reply to comment #17)
> Created an attachment (id=185401) [details] [diff]
> rectified fix for 3.7

All compiler tests pass for 3.7, and all regression tests pass for 3.6.2. Stephan, i'll let you also look at the changes once and release both the patches. Thanks!
Comment 21 Stephan Herrmann CLA 2010-12-18 17:36:15 EST
After final scrutiny I agree with the latest patches.
I've released the additional fix from comment 17 into HEAD.
Comment 22 Stephan Herrmann CLA 2010-12-18 17:38:22 EST
Released to R3_6_maintenance for 3.6.2
Comment 23 Jay Arthanareeswaran CLA 2011-01-20 03:46:46 EST
Verified for 3.6.2 using build M20110119-0834
Comment 24 Olivier Thomann CLA 2011-09-14 12:38:15 EDT
Verified for 3.8M2
Comment 25 Holger Klene CLA 2013-07-30 18:24:13 EDT
This also affects null annotation-analysis in lines marked B and C, while line A is accepted (I assume as per the fix to bug 384380)
Version: 4.3.0
Build id: I20130605-2000

BTW: These errors can't be silenced by @SuppressWarnings("null") on method test()!



import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;

public abstract class Test {

    @NonNull
    Object nonNull = new Object();

    public void test() {
        final boolean debug = false;
        SEARCH: while (someCondition()) {
            final Object next = getNext();
            if (next == null) {
                continue SEARCH;
            }
            if (debug) {
                // this is accepted
                next.toString(); // A

                // Null type mismatch: required '@NonNull Object' but the provided value is inferred
                // as @Nullable
                nonNull = next; // B
                expectNonNull(next); // C
            }
        }
    }

    abstract void expectNonNull(@NonNull Object param);

    @Nullable
    abstract Object getNext();

    abstract boolean someCondition();

}
Comment 26 Dani Megert CLA 2013-07-31 06:09:11 EDT
(In reply to comment #25)
> This also affects null annotation-analysis in lines marked B and C, while
> line A is accepted (I assume as per the fix to bug 384380)

If this is supposed to report a bug, then please open a new bug. This one here is closed. Also, I don't see the relation to dead code.
Comment 27 Holger Klene CLA 2013-07-31 06:37:26 EDT
As the variable "debug" is constant false and never changes, the lines in question are effectively dead code.

But you're right, I copy my comment to the still open bug 406160 to represent the latest state on this group of three related bugs:

bug 406160
bug 384380
this bug 332637

I was reading them in parallel and typed my comment in the wrong place.