Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added the static method check in INVOKESTATIC.java #501

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

siddhesh0705
Copy link

What was fixed:

Static Method Check:
A check was added to INVOKESTATIC.java to verify if the method being invoked is static.
If the method is not static, the code now throws an IncompatibleClassChangeError, ensuring that incorrect method invocations are properly handled and aligned with JVM behavior.

Error Handling:
The system now correctly throws a java.lang.IncompatibleClassChangeError when a non-static method is invoked with the INVOKESTATIC instruction.

Tests Added:

Two tests were added to InvokeStaticTest.java to validate the changes made in INVOKESTATIC.java:

testInvokeStaticSuccess:
This test verifies that invoking a static method using INVOKESTATIC behaves correctly and does not throw any exceptions. Result: The test passed successfully, confirming that valid static method invocations work as expected.

testInvokeStaticFailure:
This test simulates an attempt to invoke a non-static method using INVOKESTATIC and ensures that JPF throws a java.lang.IncompatibleClassChangeError.

Result: The test failed with an AssertionError at InvokeStaticTest.java:33. This suggests that the current logic for detecting non-static method invocations with INVOKESTATIC requires further debugging or adjustments to correctly handle the failure scenario.

Test Summary:

Total tests: 2
Passed: 1 (testInvokeStaticSuccess)
Failed: 1 (testInvokeStaticFailure)

@cyrille-artho
Copy link
Member

Thank you for your pull request. I'm currently running the CI build to see the results on the CI server.
Could you please make a separate pull request for src/main/gov/nasa/jpf/jvm/bytecode/INVOKESTATIC.java? You fix a couple of formatting issues and typos there, and we want to separate that from new tests or functional changes. The reason for this is that we also are working on different branches to support other functionality (such as Java 17). If a patch changes a lot of lines of code, it may be difficult to merge.
If you separate a pull request for just these syntactic changes in src/main/gov/nasa/jpf/jvm/bytecode/INVOKESTATIC.java, it is easier to merge it later, as a smaller code change.

@siddhesh0705
Copy link
Author

Some of the tests are failing due to IST-related issues, and one of the tests, which I already mentioned in the description, is also failing

@cyrille-artho
Copy link
Member

The second added test case fails because the code runs normally. You can a regular dynamic method in a regular way, so the code in the test does not throw an exception.
For the test to work as intended, you have to compile all the code first, modify class D, recompile only that, and then run the second test. This is what makes this test difficult to orchestrate: You have to work with the Gradle build cycle and add a second phase where only that extra compilation step and the new test are executed.

@siddhesh0705
Copy link
Author

okay I will work on your suggested changes and will come back with the complete solution.

@siddhesh0705
Copy link
Author

package gov.nasa.jpf.jvm;

import gov.nasa.jpf.util.test.TestJPF;
import org.junit.Test;

public class InvokeStaticTest extends TestJPF {

// Class with a  method
public  class DStatic {
    public  String m(String s) {
        return s;
    }
}

// Class with a non- method
public  class DNonStatic {
    public String m(String s) {
        return s;
    }
}

@Test
public void testInvokeStaticSuccess() {
    if (verifyNoPropertyViolation()) {
        // Correctly invoking a  method using INVOKESTATIC
        DStatic.m("Hello, World!");
    }
}

@Test
public void testInvokeStaticFailure() {
    if (verifyUnhandledException("java.lang.IncompatibleClassChangeError")) {
        try {
            // Use reflection to attempt to invoke a non- method ally
            java.lang.reflect.Method method = DNonStatic.class.getDeclaredMethod("m", String.class);

            // Attempt to invoke the non- method without an instance (passing null)
            method.invoke(null, "This should fail");
        } catch (Exception e) {
            // Re-throw the cause of the exception if it's an InvocationTargetException
            Throwable cause = e.getCause();
            if (cause != null) {
                throw new RuntimeException(cause);
            } else {
                throw new RuntimeException(e);
            }
        }
    }
}

}

This is the test code I have added. Could you please review it and let me know where I might be going wrong?

@cyrille-artho
Copy link
Member

Hi,
I think it would be great if you could manage to get a test to work without having to re-compile a modified source file to provoke the problem we want to test against.
However, Java's reflection API is read-only, so you cannot make an instance method static with it. Simply invoking a dynamic method with a null instance does not make it static.
Perhaps there is a different way to make a method that's already loaded static, as JPF has its own method descriptors. I'm away this week without good Internet access, though, so I cannot check this in detail.

@siddhesh0705
Copy link
Author

siddhesh0705 commented Oct 13, 2024

Hi,

Thank you for the feedback. I understand now that using reflection to invoke a dynamic method with a null instance doesn't truly simulate a static method invocation. I'll look into JPF's method descriptors to see if there's a way to simulate this behavior directly, without modifying or recompiling the source code.

I'll also explore any existing JPF test cases or listeners that could help with this.

Thanks again for your guidance!

@cyrille-artho
Copy link
Member

What you could try to do is to change the STATIC modifier in the method descriptor that JPF uses: src/main/gov/nasa/jpf/vm/MethodInfo.java has a field modifiers. If you check that on a non-static method, modifiers & Modifier.STATIC is false. While this information is meant to be read-only, it might be possible to modify this information at run-time, as long as the method in question is not used by other tests. However, this would require a native peer to be able to access a method at JPF level. So it's only marginally easier than the two-step build process outlined above.

@siddhesh0705
Copy link
Author

Thank you for the detailed suggestion. I understand the approach now: modifying the modifiers field in MethodInfo to toggle the STATIC flag at runtime using a native peer. I'll investigate how to make this change and see if I can access and modify the method descriptor dynamically as you suggested.

I'll keep you updated on my progress.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants