Getting a strange error from JPF
stevenrbrandt opened this issue · comments
I'm getting this error when running JPF. Any idea what it's telling me?
java.lang.ArrayIndexOutOfBoundsException: 1
at gov.nasa.jpf.vm.NamedFields.setDoubleValue(NamedFields.java:164)
at gov.nasa.jpf.vm.FunctionObjectFactory.setFuncObjFields(FunctionObjectFactory.java:60)
at gov.nasa.jpf.vm.FunctionObjectFactory.getFunctionObject(FunctionObjectFactory.java:37)
at gov.nasa.jpf.jvm.bytecode.INVOKEDYNAMIC.execute(INVOKEDYNAMIC.java:121)
at gov.nasa.jpf.vm.ThreadInfo.executeInstruction(ThreadInfo.java:1908)
at gov.nasa.jpf.vm.ThreadInfo.executeTransition(ThreadInfo.java:1859)
at gov.nasa.jpf.vm.SystemState.executeNextTransition(SystemState.java:765)
at gov.nasa.jpf.vm.VM.forward(VM.java:1722)
at gov.nasa.jpf.search.Search.forward(Search.java:937)
at gov.nasa.jpf.search.DFSearch.search(DFSearch.java:79)
at gov.nasa.jpf.JPF.run(JPF.java:613)
at gov.nasa.jpf.JPF.start(JPF.java:189)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at gov.nasa.jpf.tool.Run.call(Run.java:85)
at gov.nasa.jpf.tool.RunJPF.main(RunJPF.java:116)
Hi,
This seems to be an internal error in JPF. Can you share a test case to reproduce this?
It may not be as small a test as you'd like, but here it is...
set -e
# Need java 1.8
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH="$JAVA_HOME/bin:$PATH"
# we want $jpf_root/bin/jpf to exist
export jpf_root=$PWD/jpf-core
if [ ! -d $jpf_root ]
then
git clone https://github.com/javapathfinder/jpf-core.git $jpf_root
pushd $jpf_root
bash ./gradlew
popd
fi
export experiment_root=$PWD
mkdir -p $PWD/account/source
mkdir -p $PWD/account/outputs
# We want our program called Main
cat > Main.java << EOF
import edu.lsu.cct.javalineer.sir.account.javalineer.Accounts;
import edu.lsu.cct.javalineer.MyPool;
public class Main {
public static void main(String[] args) {
System.out.println("Running code 1");
MyPool mp = new MyPool(1);
//mp.execute(()->{ System.out.println("Hello, world"); });
Accounts.main(args);
System.out.println("Done");
System.exit(0);
}
}
EOF
if [ ! -d javalineer ]
then
git clone -b sir https://github.com/max-morris/javalineer.git
fi
javac -d account/source/ Main.java $(find javalineer -name \*.java|grep -v /test/)
cat > runJPF.sh << EOF
#!/bin/bash
RANDOM_RUNS=1 #number of random search; default is 1
TIMELIMIT=1 #let the clock tick to ensure each random search is unique
USAGE="Usage: \$0 comp_dir search_type [number_of_runs]\ncomp_dir: orig/fixed\rsearch_type: default/random\
\nnumber_of_runs (optional): number of times JPF is invoked"
if [ "`echo "\t"`" == "\\t" ]
then
ECHOE="echo -e"
else
ECHOE="echo"
fi
if [ ! \${jpf_root} ]
then
echo "jpf_root is unset in the shell"
echo "please set jpf_root to point to your JPF installation"
echo "see README for more information:"
exit 2
fi
if [ ! \${experiment_root} ]
then
echo "experiment_root is unset in the shell"
echo "please set experiment_root to point to your experiment directory"
echo "see README for more information:"
exit 2
fi
if test \$# -lt 2
then
\$ECHOE \$USAGE
exit 0
fi
if test \$# -eq 3
then
case \${3} in
*[!0-9]* )
echo "number of JPF runs is non-numeric" >&2
\$ECHOE \$USAGE >&2
exit 5
;;
esac
RANDOM_RUNS=\$3
fi
subject_dir=\${experiment_root}/account
cd \${subject_dir}/source
if test \$1 = "orig"
then
if test \$2 = "default"
then
echo Invoking JPF
\${jpf_root}/bin/jpf +classpath=\${subject_dir}/source \
Main 1 1 12 2>&1 | tee \${subject_dir}/outputs/accountJPF.log
else
if test \$2 = "random"
then
echo Invoking JPF
#if using expect to limit the amount of time spent on a search
#set the TIMEOUT value below to the number of seconds
#the search should run and uncomment
TIMEOUT=3600
X=0 #loop counter
Z=\$RANDOM_RUNS #number of runs per test case
while [ \$X -lt \$Z ]
do
seed=\$RANDOM
echo "Seed: \$seed"
#Example of how to run JPF using expect to limit search time
#run JPF using expect - uncomment next four lines
#expect -c "set timeout \$TIMEOUT; set log_file \${subject_dir}/outputs/accountJPF\${seed}.log; spawn \
#\${jpf_root}/bin/jpf +classpath=\${subject_dir}/source \
#+cg.randomize_choices=path +cg.seed=\${seed} \
#Main 1 1 12 2>&1 |; log_file \${subject_dir}/outputs/accountJPF\${seed}.log; expect; log_file" \
#run JPF without expect
#comment out the following 4 lines if using expect above
\${jpf_root}/bin/jpf +classpath=\${subject_dir}/source \
+cg.randomize_choices=FIXED_SEED +cg.seed=\$seed \
Main 1 1 12 2>&1 | \
tee \${subject_dir}/outputs/accountJPF\$seed.log
X=\$((X+1))
#Random run requires a clock tick to make sure a new random
#number is generated
sleep \$TIMELIMIT
done
fi
fi
else
echo orig is the only option currently available
fi
EOF
bash -x ./runJPF.sh orig random 1
Thanks for the example. It is indeed a bit complex because it requires a library. Perhaps it's possible to provide a simplified example without that library, but of course creating that takes some time. I'll look into this when I have time.
I'm getting the very same error message on my side. What would you recommend to do?
Is there any way to download a stable version that does not have this issue? I obtained my current version from this repo's master branch and I see no releases here. So what can we do?
FYI I'm on opejdk ver 8 and on Ubuntu 20.04
I found the source of the problem. I was using java binary version 1.8 but javac one was the latest (17).
When set javac to ver 1.8 as well and recompiled my sources the error was gone.
Sorry for a false alarm
OK, thanks for confirming. I'll close this issue then.
Sorry, this issue should remain open. Unlike @zavalyshyn, I was using java 1.8 and got the error.
@cyrille-artho can we re-open it?
Correct me if I am wrong but isn't this an array index out of bound error on those below listed lines.
After checking this, I found that this application might reveal more than one bug (or unsupported feature) in JPF. I'm trying to reduce them into separate unit tests. And I'm going to concentrate on the java-10-gradle
branch first.
Steps to reproduce
- Clone and build the lib (the resulting jar file
javalineer.jar
will be located atjavalineer/build/libs/javalineer.jar
)
git clone -b sir https://github.com/max-morris/javalineer.git
cd javalineer
git checkout 38c225e03042a8bf3dd35c19e17d40dd7a17bcf7
rm -rf src/edu/lsu/cct/javalineer/test
./gradlew build
- Compile the
Main.java
with the jar filejavalineer.jar
// Main.java
import edu.lsu.cct.javalineer.sir.account.javalineer.Accounts;
import edu.lsu.cct.javalineer.MyPool;
public class Main {
public static void main(String[] args) {
System.out.println("Running code 1");
MyPool mp = new MyPool(1);
mp.execute(()->{ System.out.println("Hello, world"); });
Accounts.main(args);
System.out.println("Done");
System.exit(0);
}
}
javac -cp .:./javalineer.jar Main.java
- Run jpf (suppose
javalineer.jar
andMain.class
both reside in the directory/tmp/cp/
and we are in jpf's root directory)
java -Xmx1024m -ea \
--add-opens java.base/jdk.internal.misc=ALL-UNNAMED \
-jar ./build/RunJPF.jar \
+jpf-core.classpath='${jpf-core.classpath};/tmp/cp;/tmp/cp/javalineer.jar' \
Main
Running results
In java-10-gradle
branch, we will get the following error
====================================================== search started: 7/28/23, 9:52 PM
[WARNING] orphan NativePeer method: jdk.internal.misc.Unsafe.getUnsafe()Lsun/misc/Unsafe;
Running code 1
[SEVERE] JPF exception, terminating: not an int[]
---------------------- JPF error stack trace ---------------------
gov.nasa.jpf.JPFException: not an int[]
at gov.nasa.jpf.vm.ArrayFields.getIntValue(ArrayFields.java:94)
at gov.nasa.jpf.vm.ElementInfo.get1SlotField(ElementInfo.java:1164)
at gov.nasa.jpf.jvm.bytecode.GETFIELD.execute(GETFIELD.java:79)
at gov.nasa.jpf.vm.ThreadInfo.executeInstruction(ThreadInfo.java:1921)
at gov.nasa.jpf.vm.ThreadInfo.executeTransition(ThreadInfo.java:1872)
at gov.nasa.jpf.vm.SystemState.executeNextTransition(SystemState.java:765)
at gov.nasa.jpf.vm.VM.forward(VM.java:1721)
at gov.nasa.jpf.search.Search.forward(Search.java:579)
at gov.nasa.jpf.search.DFSearch.search(DFSearch.java:79)
at gov.nasa.jpf.JPF.run(JPF.java:613)
at gov.nasa.jpf.JPF.start(JPF.java:189)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at gov.nasa.jpf.tool.Run.call(Run.java:80)
at gov.nasa.jpf.tool.RunJPF.main(RunJPF.java:116)
---------------------- JPF error stack trace ---------------------
gov.nasa.jpf.JPFException: not an int[]
at gov.nasa.jpf.vm.ArrayFields.getIntValue(ArrayFields.java:94)
at gov.nasa.jpf.vm.ElementInfo.get1SlotField(ElementInfo.java:1164)
at gov.nasa.jpf.jvm.bytecode.GETFIELD.execute(GETFIELD.java:79)
at gov.nasa.jpf.vm.ThreadInfo.executeInstruction(ThreadInfo.java:1921)
at gov.nasa.jpf.vm.ThreadInfo.executeTransition(ThreadInfo.java:1872)
at gov.nasa.jpf.vm.SystemState.executeNextTransition(SystemState.java:765)
at gov.nasa.jpf.vm.VM.forward(VM.java:1721)
at gov.nasa.jpf.search.Search.forward(Search.java:579)
at gov.nasa.jpf.search.DFSearch.search(DFSearch.java:79)
at gov.nasa.jpf.JPF.run(JPF.java:613)
at gov.nasa.jpf.JPF.start(JPF.java:189)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at gov.nasa.jpf.tool.Run.call(Run.java:80)
at gov.nasa.jpf.tool.RunJPF.main(RunJPF.java:116)
During diagnosing this, I found a unit test that fails on java-10-gradle
branch:
interface I {
void foo();
}
@Test
public void testLocalCapture() throws Exception {
if (verifyNoPropertyViolation()) {
String s = "abc";
I i = () -> {
assertTrue("abc".equals(s));
};
i.foo();
}
}
I have another example where I ran into a similar error, in case it might help narrowing down the cause:
public class TestArrays {
public static void main(String[] args) {
final int[] x = {1, 2, 3, 4, 5};
Thread t1 = new Thread(() -> {
int[] b = new int[x.length];
});
t1.start();
try {
t1.join();
} catch (Exception e) {}
}
}
The error:
====================================================== search started: 8/1/23, 7:37 PM
[WARNING] orphan NativePeer method: jdk.internal.misc.Unsafe.getUnsafe()Lsun/misc/Unsafe;
[SEVERE] JPF exception, terminating: not an array: java.lang.Thread
---------------------- JPF error stack trace ---------------------
gov.nasa.jpf.JPFException: not an array: java.lang.Thread
at gov.nasa.jpf.vm.ElementInfo.arrayLength(ElementInfo.java:1564)
at gov.nasa.jpf.jvm.bytecode.ARRAYLENGTH.execute(ARRAYLENGTH.java:64)
at gov.nasa.jpf.vm.ThreadInfo.executeInstruction(ThreadInfo.java:1911)
at gov.nasa.jpf.vm.ThreadInfo.executeTransition(ThreadInfo.java:1861)
at gov.nasa.jpf.vm.SystemState.executeNextTransition(SystemState.java:765)
at gov.nasa.jpf.vm.VM.forward(VM.java:1721)
at gov.nasa.jpf.search.Search.forward(Search.java:579)
at gov.nasa.jpf.search.DFSearch.search(DFSearch.java:79)
at gov.nasa.jpf.JPF.run(JPF.java:613)
at gov.nasa.jpf.JPF.start(JPF.java:189)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at gov.nasa.jpf.tool.Run.call(Run.java:80)
at gov.nasa.jpf.tool.RunJPF.main(RunJPF.java:116)
---------------------- JPF error stack trace ---------------------
gov.nasa.jpf.JPFException: not an array: java.lang.Thread
at gov.nasa.jpf.vm.ElementInfo.arrayLength(ElementInfo.java:1564)
at gov.nasa.jpf.jvm.bytecode.ARRAYLENGTH.execute(ARRAYLENGTH.java:64)
at gov.nasa.jpf.vm.ThreadInfo.executeInstruction(ThreadInfo.java:1911)
at gov.nasa.jpf.vm.ThreadInfo.executeTransition(ThreadInfo.java:1861)
at gov.nasa.jpf.vm.SystemState.executeNextTransition(SystemState.java:765)
at gov.nasa.jpf.vm.VM.forward(VM.java:1721)
at gov.nasa.jpf.search.Search.forward(Search.java:579)
at gov.nasa.jpf.search.DFSearch.search(DFSearch.java:79)
at gov.nasa.jpf.JPF.run(JPF.java:613)
at gov.nasa.jpf.JPF.start(JPF.java:189)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at gov.nasa.jpf.tool.Run.call(Run.java:80)
at gov.nasa.jpf.tool.RunJPF.main(RunJPF.java:116)
Some additional info from my experiments - the error doesn't occur if I replace x.length
with a constant or an int
variable. The error also doesn't occur when I don't use threads.
Hi @samvid25, thanks a lot for your reporting and reduction work! And your case has the same root cause with the one I mentioned above. But don't worry, I have already figured out a fix for them. I'll create corresponding issue and PR ASAP.
Another failing unit test I found on java-10-gradle
branch during diagnosis this issue is:
interface I {
void foo();
}
@Test
public void testLocalCapture() throws Exception {
if (verifyNoPropertyViolation()) {
double d = 2.0;
I i = () -> {
assertTrue(d == 2.0);
};
i.foo();
}
}
Great, thanks!
Hi @cyrille-artho and @pparizek, with PR #381 and #382 (plus another simple native peer for java.util.concurrent.atomic.AtomicReference
with getAndSet()
implementation), the test case provided in this issue could run for a long time without crash.
It doesn't stop maybe because there are too many generated states. A partial evidence is that if we use gov.nasa.jpf.search.PathSearch
instead of gov.nasa.jpf.search.DFSearch
as search class, the test case runs to stop successfully (PathSearch
doesn't do backtrack).
IMHO, it could be a further enhancement to add native peers for classes under java.util.concurrent.atomic
package once and for all, which improves traceability. For now, maybe we could close this issue as completed.
OK, I'll close this issue, as a performance issue is not the same as a crash (if someone runs into this in a real example, we can open a new issue).