Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions containersQa/108_HUM151_jreCompile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash
set -ex
set -o pipefail

## resolve folder of this script, following all symlinks,
## http://stackoverflow.com/questions/59895/can-a-bash-script-tell-what-directory-its-stored-in
SCRIPT_SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SCRIPT_SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
SCRIPT_DIR="$( cd -P "$( dirname "$SCRIPT_SOURCE" )" && pwd )"
SCRIPT_SOURCE="$(readlink "$SCRIPT_SOURCE")"
# if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
[[ $SCRIPT_SOURCE != /* ]] && SCRIPT_SOURCE="$SCRIPT_DIR/$SCRIPT_SOURCE"
done
readonly SCRIPT_DIR="$( cd -P "$( dirname "$SCRIPT_SOURCE" )" && pwd )"

source $SCRIPT_DIR/testlib.bash

parseArguments "$@"
processArguments
setup
tryJreCompilation 2>&1| tee $REPORT_FILE
111 changes: 111 additions & 0 deletions containersQa/InProcessCompileDemo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//17 and up, originally by [email protected].

import javax.tools.*;
import javax.tools.JavaFileObject.Kind;
import java.net.URI;
import java.util.*;

public class InProcessCompileDemo {
public static void main(String[] args) throws Exception {
String jvmVersion="17";
if (args.length>0) {
jvmVersion=args[0];
}
String className = "Hello";
String sourceCode = """
public class Hello {
public static void main(String[] args) {
System.out.println("Hello from in-memory compiled code!");
}
}
""";

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
if (compiler == null) {
System.err.println("❌ No system compiler found — you're probably on a stripped JRE.");
return;
}
System.out.println("✅ Compiler loaded: " + compiler.getClass().getName());

// in-memory source
JavaFileObject source = new StringJavaFileObject(className, sourceCode);

// file manager that captures class bytes in memory
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
StandardJavaFileManager std = compiler.getStandardFileManager(diagnostics, null, null);
MemoryFileManager memFM = new MemoryFileManager(std);

// compile for a specific release (22 here)
JavaCompiler.CompilationTask task = compiler.getTask(
null, memFM, diagnostics,
List.of("--release", jvmVersion), null, List.of(source));

boolean ok = task.call();
diagnostics.getDiagnostics().forEach(System.out::println);

if (!ok) {
System.out.println("❌ Compilation failed");
return;
}
System.out.println("✅ Compilation succeeded");

// load and run main()
ClassLoader loader = new MemoryClassLoader(memFM.getClassBytes());
Class<?> hello = loader.loadClass(className);
hello.getMethod("main", String[].class).invoke(null, (Object) new String[0]);
}

// ===== Helpers =====

// Source stored entirely in memory
static final class StringJavaFileObject extends SimpleJavaFileObject {
private final String code;
StringJavaFileObject(String className, String code) {
super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.code = code;
}
@Override public CharSequence getCharContent(boolean ignoreEncodingErrors) { return code; }
}

// Captures compiled class bytes in memory
static final class MemoryFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
private final Map<String, ByteArrayJavaFileObject> classFiles = new HashMap<>();
MemoryFileManager(StandardJavaFileManager fileManager) { super(fileManager); }
@Override
public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) {
ByteArrayJavaFileObject file = new ByteArrayJavaFileObject(className, kind);
classFiles.put(className, file);
return file;
}
Map<String, byte[]> getClassBytes() {
Map<String, byte[]> out = new HashMap<>();
for (var e : classFiles.entrySet()) out.put(e.getKey(), e.getValue().getBytes());
return out;
}
}

// Holds class bytes
static final class ByteArrayJavaFileObject extends SimpleJavaFileObject {
private final java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
ByteArrayJavaFileObject(String name, Kind kind) {
super(URI.create("mem:///" + name.replace('.', '/') + kind.extension), kind);
}
@Override public java.io.OutputStream openOutputStream() { return out; }
byte[] getBytes() { return out.toByteArray(); }
}

// ClassLoader that defines classes from captured bytes
static final class MemoryClassLoader extends ClassLoader {
private final Map<String, byte[]> classes;
MemoryClassLoader(Map<String, byte[]> classes) {
super(InProcessCompileDemo.class.getClassLoader());
this.classes = classes;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] bytes = classes.get(name);
if (bytes == null) throw new ClassNotFoundException(name);
return defineClass(name, bytes, 0, bytes.length);
}
}
}
27 changes: 27 additions & 0 deletions containersQa/testlib.bash
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ function pretest() {
SKIPPED2="!skipped! no local maven !skipped!"
SKIPPED3="!skipped! broken right now !skipped!"
SKIPPED4="!skipped! jre only testing does not support this feature."
SKIPPED44="!skipped! jdk only testing does not support this feature."
SKIPPED5="!skipped! reproducers security now must be enabled by OTOOL_RUN_SECURITY_REPRODUCERS=true"
SKIPPED6="!skipped! rhel 7 based images do not support this functionality."
SKIPPED7="!skipped! rhel 7 Os version of Podman does not support this functionality."
Expand All @@ -100,12 +101,21 @@ function setup() {
# With the addition of a JRE Runtime container we should not run for full jdk features like
# Maven, S2i, Javac.
function skipIfJreExecution() {
# maybe replace OTOOL_jresdk with check on javac command?
if [ "$OTOOL_jresdk" == "jre" ] ; then
echo "$SKIPPED4"
exit
fi
}

function skipIfJdkExecution() {
# maybe replace OTOOL_jresdk with check on javac command?
if [ "$OTOOL_jresdk" == "jdk" ] ; then
echo "$SKIPPED44"
exit
fi
}

# Use this flag to skip tests when executing on a Rhel 7 host. In some cases backend container
# functionality the tests are looking for is not available in that version.
function skipIfRhel7Execution() {
Expand Down Expand Up @@ -218,6 +228,10 @@ function runOnBaseDirBash() {
$PD_PROVIDER run -i $HASH bash -c "$1"
}

function runOnBaseDirBashWithMount() {
$PD_PROVIDER run -v=$LIBCQA_SCRIPT_DIR:/testsDir -i $HASH bash -c "$1"
}

function runOnBaseDirBashOtherUser() {
$PD_PROVIDER run -i -u 12324 $HASH bash -c "$1"
}
Expand Down Expand Up @@ -1130,3 +1144,16 @@ function assertCryptoProviders() {
runOnBaseDirBash "$commandProviders" 2>&1| tee $REPORT_FILE
set -x
}


function tryJreCompilation() {
runOnBaseDirBashWithMount "ls /testsDir | grep \\.java$"
local v=$(runOnBaseDirBashWithMount "java -version " 2>&1 | grep "openjdk version" | head -n 1)
if echo "$v" | grep '"1.8' || echo "$v" | grep '"11' ; then
echo '!skipped! Skipping runtime compilation on 8 and 11'
exit 0
else
echo '17+, going on'
fi
runOnBaseDirBashWithMount "java /testsDir/InProcessCompileDemo.java"
}