//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
package gov.nasa.jpf.vm;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import java.util.function.BiConsumer;
import java.util.function.Function;
import cmu.conditional.Conditional;
import cmu.conditional.One;
import de.fosd.typechef.featureexpr.FeatureExpr;
import gov.nasa.jpf.Config;
import gov.nasa.jpf.annotation.MJI;
/**
* MJI NativePeer class for java.lang.System library abstraction
*/
public class JPF_java_lang_System extends NativePeer {
@MJI
public void arraycopy__Ljava_lang_Object_2ILjava_lang_Object_2II__V(final MJIEnv env, int clsObjRef, Conditional<Integer> srcArrayRef, final Conditional<Integer> srcIdx,
final Conditional<Integer> dstArrayRef, final Conditional<Integer> dstIdx, final Conditional<Integer> length, FeatureExpr ctx) {
srcArrayRef.mapf(ctx, new BiConsumer<FeatureExpr, Integer>() {
@Override
public void accept(FeatureExpr ctx, final Integer srcArrayRef) {
dstArrayRef.mapf(ctx, new BiConsumer<FeatureExpr, Integer>() {
@Override
public void accept(FeatureExpr ctx, final Integer dstArrayRef) {
length.mapf(ctx, new BiConsumer<FeatureExpr, Integer>() {
@Override
public void accept(FeatureExpr ctx, final Integer length) {
if (ctx.isContradiction()) {
return;
}
if ((srcArrayRef.intValue() == MJIEnv.NULL) || (dstArrayRef.intValue() == MJIEnv.NULL)) {
env.throwException(ctx, "java.lang.NullPointerException");
return;
}
final ElementInfo eiSrc = env.getElementInfo(srcArrayRef);
final ElementInfo eiDst = env.getModifiableElementInfo(dstArrayRef);
try {
srcIdx.mapf(ctx, new BiConsumer<FeatureExpr, Integer>() {
@Override
public void accept(FeatureExpr ctx, final Integer srcIdx) {
dstIdx.mapf(ctx, new BiConsumer<FeatureExpr, Integer>() {
@Override
public void accept(FeatureExpr ctx, Integer dstIdx) {
if (ctx.isContradiction()) {
return;
}
eiDst.copyElements(ctx, env.getThreadInfo(), eiSrc, srcIdx, dstIdx, length);
}
});
}
});
} catch (IndexOutOfBoundsException iobx) {
env.throwException(ctx, "java.lang.IndexOutOfBoundsException", iobx.getMessage());
} catch (ArrayStoreException asx) {
env.throwException(ctx, "java.lang.ArrayStoreException", asx.getMessage());
}
}
});
}
});
}
});
}
@SuppressWarnings("deprecation")
@MJI
public int getenv__Ljava_lang_String_2__Ljava_lang_String_2 (MJIEnv env, int clsObjRef,
int keyRef, FeatureExpr ctx){
String k = env.getStringObject(ctx, keyRef);
String v = System.getenv(k);
if (v == null){
return MJIEnv.NULL;
} else {
return env.newString(ctx, v);
}
}
int createPrintStream (MJIEnv env, int clsObjRef, FeatureExpr ctx){
ThreadInfo ti = env.getThreadInfo();
// Instruction insn = ti.getPC().getValue();
// StackFrame frame = ti.getTopFrame();
ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("gov.nasa.jpf.ConsoleOutputStream");
// it's not really used, but it would be hack'ish to use a class whose
// super class hasn't been initialized yet
if (!ci.isRegistered()) {
ci.registerClass(ctx, ti);
}
if (!ci.isInitialized()) {
if (ci.initializeClass(ctx, ti)) {
env.repeatInvocation();
return MJIEnv.NULL;
}
}
return env.newObject(ctx, ci);
}
private int createInputStream(MJIEnv env, int clsObjRef, FeatureExpr ctx) {
ThreadInfo ti = env.getThreadInfo();
// Instruction insn = ti.getPC().getValue();
// StackFrame frame = ti.getTopFrame();
ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("gov.nasa.jpf.ConsoleInputStream");
// it's not really used, but it would be hack'ish to use a class whose
// super class hasn't been initialized yet
if (!ci.isRegistered()) {
ci.registerClass(ctx, ti);
}
if (!ci.isInitialized()) {
if (ci.initializeClass(ctx, ti)) {
env.repeatInvocation();
return MJIEnv.NULL;
}
}
return env.newObject(ctx, ci);
}
@MJI
public int createSystemIn____Ljava_io_InputStream_2 (MJIEnv env, int clsObjRef, FeatureExpr ctx){
return createInputStream(env,clsObjRef, ctx);
}
@MJI
public int createSystemOut____Ljava_io_PrintStream_2 (MJIEnv env, int clsObjRef, FeatureExpr ctx){
return createPrintStream(env,clsObjRef, ctx);
}
@MJI
public int createSystemErr____Ljava_io_PrintStream_2 (MJIEnv env, int clsObjRef, FeatureExpr ctx){
return createPrintStream(env,clsObjRef, ctx);
}
int getProperties (MJIEnv env, Properties p, FeatureExpr ctx){
int n = p.size() * 2;
int aref = env.newObjectArray("Ljava/lang/String;", n);
int i=0;
for (Map.Entry<Object,Object> e : p.entrySet() ){
env.setReferenceArrayElement(ctx,aref,
i++, new One<>(env.newString(ctx, e.getKey().toString())));
env.setReferenceArrayElement(ctx,aref,
i++, new One<>(env.newString(ctx, e.getValue().toString())));
}
return aref;
}
int getSysPropsFromHost (MJIEnv env, FeatureExpr ctx){
return getProperties(env, System.getProperties(), ctx);
}
int getSysPropsFromFile (MJIEnv env, FeatureExpr ctx){
Config conf = env.getConfig();
String cf = conf.getString("vm.sysprop.file", "system.properties");
if (cf != null){
try {
Properties p = new Properties();
FileInputStream fis = new FileInputStream(cf);
p.load(fis);
return getProperties(env, p, ctx);
} catch (IOException iox){
return MJIEnv.NULL;
}
}
//.. not yet
return MJIEnv.NULL;
}
static String JAVA_CLASS_PATH = "java.class.path";
@MJI
public String getSUTJavaClassPath(VM vm, FeatureExpr ctx) {
ClassInfo system = ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.System");
ThreadInfo ti = vm.getCurrentThread();
Heap heap = vm.getHeap();
ElementInfo eiClassPath = heap.newString(ctx, JAVA_CLASS_PATH, ti);
MethodInfo miGetProperty = system.getMethod("getProperty(Ljava/lang/String;)Ljava/lang/String;", true);
DirectCallStackFrame frame = miGetProperty.createDirectCallStackFrame(ctx, ti, 0);
frame.setReferenceArgument( ctx, 0, eiClassPath.getObjectRef(), null);
frame.setFireWall(); // we don't want exceptions to escape into the SUT
try {
ti.executeMethodHidden(frame);
} catch (UncaughtException e) {
ti.clearPendingException();
StackFrame caller = ti.popAndGetModifiableTopFrame(ctx);
caller.advancePC();
return null;
}
int ref = frame.peek(ctx).getValue();
ElementInfo metaResult = heap.get(ref);
String result = metaResult.asString().getValue();
return result;
}
int getSelectedSysPropsFromHost (MJIEnv env, FeatureExpr ctx){
Config conf = env.getConfig();
String keys[] = conf.getStringArray("vm.sysprop.keys");
if (keys == null){
String[] defKeys = {
"path.separator",
"line.separator",
"file.separator",
"user.name",
"user.dir",
"user.timezone",
"user.country",
"java.home",
"java.version",
"java.io.tmpdir",
JAVA_CLASS_PATH
//... and probably some more
// <2do> what about -Dkey=value commandline options
};
keys = defKeys;
}
int aref = env.newObjectArray("Ljava/lang/String;", keys.length * 2);
int i=0;
for (String s : keys) {
String v;
int idx = s.indexOf('/');
if (idx >0){ // this one is an explicit key/value pair from vm.system.properties
v = s.substring(idx+1);
s = s.substring(0,idx);
} else {
// the special beasts first (if they weren't overridden with vm.system.properties)
if (s == JAVA_CLASS_PATH) {
// maybe we should just use vm.classpath
// NOTE: the curent classloader at the point it has to be a system classloader.
ClassPath cp = ClassLoaderInfo.getCurrentClassLoader().getClassPath();
// <2do> should be consistent with path.separator (this is host VM notation)
v = cp.toString();
} else { // we bluntly grab it from the host VM properties
v = System.getProperty(s);
}
}
if (v != null){
env.setReferenceArrayElement(ctx,aref, i++, new One<>(env.newString(ctx, s)));
env.setReferenceArrayElement(ctx,aref, i++, new One<>(env.newString(ctx, v)));
}
}
return aref;
}
/**
* policy of how to initialize system properties of the system under test
*/
static enum SystemPropertyPolicy {
SELECTED, // copy host values for keys specified in
FILE,
HOST
};
@MJI
public int getKeyValuePairs_____3Ljava_lang_String_2 (MJIEnv env, int clsObjRef, FeatureExpr ctx){
Config conf = env.getConfig();
SystemPropertyPolicy sysPropSrc = conf.getEnum( "vm.sysprop.source", SystemPropertyPolicy.values(), SystemPropertyPolicy.HOST);
switch (sysPropSrc) {
case FILE:
return getSysPropsFromFile(env, ctx);
case HOST:
return getSysPropsFromHost(env, ctx);
case SELECTED:
return getSelectedSysPropsFromHost(env, ctx);
default:
throw new RuntimeException("Unsupported system prperty policy: " + sysPropSrc);
}
}
// <2do> - this break every app which uses time delta thresholds
// (sort of "if ((t2 - t1) > d)"). Ok, we can't deal with
// real time, but we could at least give some SystemState dependent
// increment
@MJI
public long currentTimeMillis____J (MJIEnv env, int clsObjRef, FeatureExpr ctx) {
return env.currentTimeMillis();
}
// <2do> - likewise. Java 1.5's way to measure relative time
@MJI
public long nanoTime____J (MJIEnv env, int clsObjRef, FeatureExpr ctx) {
return env.nanoTime();
}
// this works on the assumption that we sure break the transition, and
// then the search determines that it is an end state (all terminated)
@MJI
public void exit__I__V (MJIEnv env, int clsObjRef, int ret, FeatureExpr ctx) {
ThreadInfo ti = env.getThreadInfo();
env.getVM().terminateProcess(ti);
}
@MJI
public void gc____V (MJIEnv env, int clsObjRef, FeatureExpr ctx) {
env.getSystemState().activateGC();
}
@MJI
public Conditional<Integer> identityHashCode__Ljava_lang_Object_2__I (MJIEnv env, int clsObjRef, Conditional<Integer> objref, FeatureExpr ctx) {
return objref.map(new Function<Integer, Integer>() {
@Override
public Integer apply(Integer objref) {
return (objref ^ 0xABCD);
}
});
}
}