undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler;
import java.nio.file.Path;
public interface CoreInfoGatherer {
void gatherCoreInfo(HtmlSection section, Path core);
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler;
import java.io.PrintWriter;
import java.util.concurrent.TimeUnit;
public class ElapsedTimePrinter implements AutoCloseable {
private final String name;
private final PrintWriter out;
private final Stopwatch stopwatch;
public ElapsedTimePrinter(Stopwatch stopwatch, String name,
PrintWriter out) {
this.stopwatch = stopwatch;
this.name = name;
this.out = out;
stopwatch.start();
}
@Override
public void close() {
stopwatch.stop();
out.printf("%s took %d s%n", name,
TimeUnit.NANOSECONDS.toSeconds(stopwatch.getElapsedTimeNs()));
}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler;
public interface EnvironmentInfoGatherer {
void gatherEnvironmentInfo(HtmlSection section);
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler;
import jdk.test.failurehandler.action.ActionHelper;
import jdk.test.failurehandler.value.InvalidValueException;
import java.io.PrintWriter;
import java.nio.file.Path;
import java.util.Properties;
public final class GathererFactory {
private final Path workdir;
private final Path[] jdks;
private final PrintWriter log;
private final String osName;
public GathererFactory(String osName, Path workdir, PrintWriter log, Path... jdks) {
this.osName = osName;
this.workdir = workdir;
this.log = log;
this.jdks = jdks;
}
public EnvironmentInfoGatherer getEnvironmentInfoGatherer() {
return create();
}
public ProcessInfoGatherer getProcessInfoGatherer() {
return create();
}
public CoreInfoGatherer getCoreInfoGatherer() {
return create();
}
private ToolKit create() {
Properties osProperty = Utils.getProperties(osName);
try {
ActionHelper helper = new ActionHelper(workdir, "config", osProperty, jdks);
// os-specific action set must be last, b/c they can kill the process
return new ToolKit(helper, log, "common", osName);
} catch (InvalidValueException e) {
throw new IllegalStateException("can't create tool kit", e);
}
}
}

View file

@ -0,0 +1,145 @@
/*
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
public class HtmlPage implements AutoCloseable {
static final String STYLE_SHEET_FILENAME = "failure-handler-style.css";
static final String SCRIPT_FILENAME = "failure-handler-script.js";
private final PrintWriter writer;
private final HtmlSection rootSection;
/**
* Constructs a {@code HtmlPage}
*
* @param dir The directory into which the HTML file and related resources will be created
* @param htmlFileName The HTML file name
* @param append if {@code true} then the content will be appended to the file represented
* by the {@code htmlFileName}, else the {@code htmlFileName} will be overwritten
* with the new content
* @throws IllegalArgumentException if {@code dir} is not a directory or if the
* {@code htmlFileName} is {@linkplain String#isBlank() blank}
* @throws IOException if there is an error constructing file resource(s) for this HTML page
*/
public HtmlPage(final Path dir, final String htmlFileName, final boolean append)
throws IOException {
Objects.requireNonNull(dir, "directory cannot be null");
Objects.requireNonNull(htmlFileName, "HTML file name cannot be null");
if (!Files.isDirectory(dir)) {
throw new IllegalArgumentException(dir + " is not a directory");
}
if (htmlFileName.isBlank()) {
throw new IllegalArgumentException("HTML file name cannot be blank");
}
final FileWriter fileWriter = new FileWriter(dir.resolve(htmlFileName).toFile(), append);
this.writer = new PrintWriter(fileWriter, true);
createScriptFile(dir);
createStyleSheetFile(dir);
rootSection = new HtmlSection(writer);
}
@Override
public void close() {
writer.close();
}
public HtmlSection getRootSection() {
return rootSection;
}
private static void createStyleSheetFile(final Path destDir) throws IOException {
final Path styleSheet = destDir.resolve(STYLE_SHEET_FILENAME);
if (Files.exists(styleSheet)) {
return;
}
final String content = """
div { display:none;}
""";
Files.writeString(styleSheet, content);
}
private static void createScriptFile(final Path destDir) throws IOException {
final Path script = destDir.resolve(SCRIPT_FILENAME);
if (Files.exists(script)) {
return;
}
final String content = """
function doShow(e) {
while (e != null) {
if (e.tagName == 'DIV') {
e.style.display = 'block';
}
e = e.parentNode;
}
}
function showHandler(event) {
elementId = this.dataset.show;
elementToShow = document.getElementById(elementId);
doShow(elementToShow);
}
function toggleHandler(event) {
toggleElementId = this.dataset.toggle;
elementToToggle = document.getElementById(toggleElementId);
d = elementToToggle.style.display;
if (d == 'block') {
elementToToggle.style.display = 'none';
} else {
doShow(elementToToggle);
}
}
function bodyLoadHandler() {
const index = location.href.indexOf("#");
if (index != -1) {
doShow(document.getElementById(location.href.substring(index + 1)));
}
// elements that require the "toggleHandler" function to be registered
// as an event handler for the onclick event
const requiringToggleHandler = document.querySelectorAll("[data-toggle]");
for (const e of requiringToggleHandler) {
e.addEventListener("click", toggleHandler);
}
// elements that require the "showHandler" function to be registered
// as an event handler for the onclick event
const requiringShowHandler = document.querySelectorAll("[data-show]");
for (const e of requiringShowHandler) {
e.addEventListener("click", showHandler);
}
}
// register a onload event handler
window.addEventListener("DOMContentLoaded", bodyLoadHandler);
""";
Files.writeString(script, content);
}
}

View file

@ -0,0 +1,220 @@
/*
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler;
import java.io.FilterWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class HtmlSection {
protected final HtmlSection rootSection;
protected final String id;
protected final String name;
public PrintWriter getWriter() {
return textWriter;
}
protected final PrintWriter pw;
protected final PrintWriter textWriter;
protected boolean closed;
private HtmlSection child;
public HtmlSection(PrintWriter pw) {
this(pw, "", null, null);
}
private HtmlSection(PrintWriter pw, String id, String name, HtmlSection rootSection) {
this.pw = pw;
textWriter = new PrintWriter(new HtmlFilterWriter(pw), true);
this.id = id;
this.name = name;
child = null;
// main
if (rootSection == null) {
this.rootSection = this;
this.pw.println("<html>");
this.pw.println("<head>");
this.pw.println(
"<link href=\"" + HtmlPage.STYLE_SHEET_FILENAME + "\" rel=\"stylesheet\" type=\"text/css\" />");
this.pw.println(
"<script src=\"" + HtmlPage.SCRIPT_FILENAME + "\" type=\"text/javascript\" ></script>");
this.pw.println("</head>");
this.pw.println("<body>");
} else {
this.rootSection = rootSection;
this.pw.print("<ul>");
}
}
public HtmlSection createChildren(String section) {
if (child != null) {
if (child.name.equals(section)) {
return child;
}
child.close();
}
child = new SubSection(this, section, rootSection);
return child;
}
protected final void removeChild(HtmlSection child) {
if (this.child == child) {
this.child = null;
}
}
public void close() {
closeChild();
if (closed) {
return;
}
closed = true;
if (rootSection == this) {
pw.println("</body>");
pw.println("</html>");
pw.close();
} else {
pw.println("</ul>");
}
}
protected final void closeChild() {
if (child != null) {
child.close();
child = null;
}
}
public void link(HtmlSection section, String child, String name) {
String path = section.id;
if (path.isEmpty()) {
path = child;
} else if (child != null) {
path = String.format("%s.%s", path, child);
}
pw.printf("<a href=\"#%1$s\" data-show=\"%1$s\" >%2$s</a>%n",
path, name);
}
/**
* Creates a {@code <a href></a>} link with {@code targetAddress} being the value for {@code href}
* and the {@code linkText} being the text for the link.
*
* @param targetAddress the target address
* @param linkText the text for the link
*/
public void createLink(String targetAddress, String linkText) {
pw.printf("<a href=\"%1$s\">%2$s</a>%n", targetAddress, linkText);
}
public HtmlSection createChildren(String[] sections) {
int i = 0;
int n = sections.length;
HtmlSection current = this;
for (; i < n && current.child != null;
++i, current = current.child) {
if (!sections[i].equals(current.child.name)) {
break;
}
}
for (; i < n; ++i) {
current = current.createChildren(sections[i]);
}
return current;
}
private static class SubSection extends HtmlSection {
private final HtmlSection parent;
public SubSection(HtmlSection parent, String name,
HtmlSection rootSection) {
super(parent.pw,
parent.id.isEmpty()
? name
: String.format("%s.%s", parent.id, name),
name, rootSection);
this.parent = parent;
pw.printf("<li><a name='%1$s'/><a href='#%1$s' data-toggle=\"%1$s\" >%2$s</a><div id='%1$s'><code><pre>",
id, name);
}
@Override
public void close() {
closeChild();
if (closed) {
return;
}
pw.print("</pre></code></div></li><!-- " + id + "-->");
parent.removeChild(this);
super.close();
}
}
private static class HtmlFilterWriter extends FilterWriter {
public HtmlFilterWriter(PrintWriter pw) {
super(pw);
}
@Override
public void write(int c) throws IOException {
switch (c) {
case '<':
super.write("&lt;", 0, 4);
break;
case '>':
super.write("&gt;", 0, 4);
break;
case '"':
super.write("&quot;", 0, 5);
break;
case '&':
super.write("&amp;", 0, 4);
break;
default:
super.write(c);
}
}
@Override
public void write(char[] cbuf, int off, int len) throws IOException {
for (int i = off; i < len; ++i){
write(cbuf[i]);
}
}
@Override
public void write(String str, int off, int len) throws IOException {
for (int i = off; i < len; ++i){
write(str.charAt(i));
}
}
}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler;
public interface ProcessInfoGatherer {
void gatherProcessInfo(HtmlSection section, long pid);
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler;
public final class Stopwatch {
protected boolean isResultAvailable;
protected boolean isRunning;
private long startTimeNs;
private long stopTimeNs;
public Stopwatch() {
isResultAvailable = false;
}
/**
* Starts measuring time.
*/
public void start() {
startTimeNs = System.nanoTime();
isRunning = true;
}
/**
* Stops measuring time.
*/
public void stop() {
if (!isRunning) {
throw new IllegalStateException(" hasn't been started");
}
stopTimeNs = System.nanoTime();
isRunning = false;
isResultAvailable = true;
}
/**
* @return time in nanoseconds measured between
* calls of {@link #start()} and {@link #stop()} methods.
*
* @throws IllegalStateException if called without preceding
* {@link #start()} {@link #stop()} method
*/
public long getElapsedTimeNs() {
if (isRunning) {
throw new IllegalStateException("hasn't been stopped");
}
if (!isResultAvailable) {
throw new IllegalStateException("was not run");
}
return stopTimeNs - startTimeNs;
}
}

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler;
import jdk.test.failurehandler.action.ActionSet;
import jdk.test.failurehandler.action.ActionHelper;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Deque;
import java.util.zip.GZIPInputStream;
public class ToolKit implements EnvironmentInfoGatherer, ProcessInfoGatherer, CoreInfoGatherer {
private final List<ActionSet> actions = new ArrayList<>();
private final ActionHelper helper;
private final PrintWriter log;
public ToolKit(ActionHelper helper, PrintWriter log, String... names) {
this.helper = helper;
this.log = log;
for (String name : names) {
actions.add(new ActionSet(helper, log, name));
}
}
@Override
public void gatherEnvironmentInfo(HtmlSection section) {
for (ActionSet set : actions) {
set.gatherEnvironmentInfo(section);
}
}
@Override
public void gatherCoreInfo(HtmlSection section, Path core) {
if (core.getFileName().toString().endsWith(".gz")) {
Path unpackedCore = Path.of(core.toString().replace(".gz", ""));
try (GZIPInputStream gzis = new GZIPInputStream(Files.newInputStream(core))) {
Files.copy(gzis, unpackedCore);
for (ActionSet set : actions) {
set.gatherCoreInfo(section, unpackedCore);
}
Files.delete(unpackedCore);
} catch (IOException ioe) {
log.printf("Unexpected exception whilc opening %s", core.getFileName().toString());
ioe.printStackTrace(log);
}
} else {
for (ActionSet set : actions) {
set.gatherCoreInfo(section, core);
}
}
}
@Override
public void gatherProcessInfo(HtmlSection section, long pid) {
// as some of actions can kill a process, we need to get children of all
// test process first, and run the actions starting from the leaves
// and going up by the process tree
Deque<Long> orderedPids = new LinkedList<>();
Queue<Long> testPids = new LinkedList<>();
testPids.add(pid);
HtmlSection ptreeSection = section.createChildren("test_processes");
for (Long p = testPids.poll(); p != null; p = testPids.poll()) {
orderedPids.addFirst(p);
List<Long> children = helper.getChildren(ptreeSection, p);
if (!children.isEmpty()) {
HtmlSection s = ptreeSection.createChildren("" + p);
for (Long c : children) {
s.link(section, c.toString(), c.toString());
}
testPids.addAll(children);
}
}
for (Long p : orderedPids) {
for (ActionSet set : actions) {
set.gatherProcessInfo(section, p);
}
}
}
}

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.Properties;
public final class Utils {
private static final int BUFFER_LENGTH = 1024;
public static String prependPrefix(String prefix, String name) {
return (prefix == null || prefix.isEmpty())
? name
: (name == null || name.isEmpty())
? prefix
: String.format("%s.%s", prefix, name);
}
public static void copyStream(InputStream in, OutputStream out)
throws IOException {
int n;
byte[] buffer = new byte[BUFFER_LENGTH];
while ((n = in.read(buffer)) != -1) {
out.write(buffer, 0, n);
}
out.flush();
}
public static void copyStream(Reader in, Writer out)
throws IOException {
int n;
char[] buffer = new char[BUFFER_LENGTH];
while ((n = in.read(buffer)) != -1) {
out.write(buffer, 0, n);
}
out.flush();
}
public static Properties getProperties(String name) {
Properties properties = new Properties();
String resourceName = String.format(
"/%s.%s", name.toLowerCase(), "properties");
InputStream stream = Utils.class.getResourceAsStream(resourceName);
if (stream == null) {
throw new IllegalStateException(String.format(
"resource '%s' doesn't exist%n", resourceName));
}
try {
try {
properties.load(stream);
} finally {
stream.close();
}
} catch (IOException e) {
throw new IllegalStateException(String.format(
"can't read resource '%s' : %s%n",
resourceName, e.getMessage()), e);
}
return properties;
}
private Utils() { }
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.action;
import jdk.test.failurehandler.HtmlSection;
public interface Action {
boolean isJavaOnly();
HtmlSection getSection(HtmlSection section);
ActionParameters getParameters();
}

View file

@ -0,0 +1,404 @@
/*
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.action;
import jdk.test.failurehandler.value.InvalidValueException;
import jdk.test.failurehandler.value.Value;
import jdk.test.failurehandler.value.ValueHandler;
import jdk.test.failurehandler.HtmlSection;
import jdk.test.failurehandler.Stopwatch;
import jdk.test.failurehandler.Utils;
import java.io.BufferedReader;
import java.io.CharArrayReader;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
public class ActionHelper {
private final Path workDir;
@Value(name = "execSuffix")
private String executableSuffix = "";
private Path[] paths;
private final PatternAction getChildren;
public ActionHelper(Path workDir, String prefix, Properties properties,
Path... jdks) throws InvalidValueException {
this.workDir = workDir.toAbsolutePath();
getChildren = new PatternAction(null,
Utils.prependPrefix(prefix, "getChildren"), properties);
ValueHandler.apply(this, properties, prefix);
String[] pathStrings = System.getenv("PATH").split(File.pathSeparator);
paths = new Path[pathStrings.length];
for (int i = 0; i < paths.length; ++i) {
paths[i] = Paths.get(pathStrings[i]);
}
addJdks(jdks);
}
public List<Long> getChildren(HtmlSection section, long pid) {
String pidStr = "" + pid;
ProcessBuilder pb = getChildren.prepareProcess(section, this, pidStr);
HtmlSection childrenSection = getChildren.getSection(section);
PrintWriter log = childrenSection.getWriter();
CharArrayWriter writer = new CharArrayWriter();
ExitCode code = run(childrenSection, log, writer, pb, getChildren.getParameters());
Reader output = new CharArrayReader(writer.toCharArray());
if (!ExitCode.OK.equals(code)) {
log.println("WARNING: get children pids action failed");
try {
Utils.copyStream(output, log);
} catch (IOException e) {
e.printStackTrace(log);
}
return Collections.emptyList();
}
List<Long> result = new ArrayList<>();
try {
try (BufferedReader reader = new BufferedReader(output)) {
String line;
while ((line = reader.readLine()) != null) {
String value = line.trim();
if (value.isEmpty()) {
// ignore empty lines
continue;
}
try {
result.add(Long.valueOf(value));
} catch (NumberFormatException e) {
log.printf("WARNING: can't parse child pid %s : %s%n",
line, e.getMessage());
e.printStackTrace(log);
}
}
}
} catch (IOException e) {
e.printStackTrace(log);
}
return result;
}
public ProcessBuilder prepareProcess(PrintWriter log, String app,
String... args) {
File appBin = findApp(app);
if (appBin == null) {
log.printf("ERROR: can't find %s in %s.%n",
app, Arrays.toString(paths));
return null;
}
List<String> command = new ArrayList<>(args.length + 1);
command.add(appBin.toString());
Collections.addAll(command, args);
return new ProcessBuilder()
.command(command)
.directory(workDir.toFile());
}
public File findApp(String app) {
String name = app + executableSuffix;
for (Path pathElem : paths) {
File result = pathElem.resolve(name).toFile();
if (result.exists()) {
return result;
}
}
return null;
}
private void addJdks(Path[] jdkPaths) {
if (jdkPaths != null && jdkPaths.length != 0) {
Path[] result = new Path[jdkPaths.length + paths.length];
for (int i = 0; i < jdkPaths.length; ++i) {
result[i] = jdkPaths[i].resolve("bin");
}
System.arraycopy(paths, 0, result, jdkPaths.length, paths.length);
paths = result;
}
}
private ExitCode run(HtmlSection section, PrintWriter log, Writer out, ProcessBuilder pb,
ActionParameters params) {
char[] lineChars = new char[40];
Arrays.fill(lineChars, '-');
String line = new String(lineChars);
Stopwatch stopwatch = new Stopwatch();
stopwatch.start();
log.printf("%s%n[%tF %<tT] %s timeout=%s in %s%n%1$s%n", line, new Date(), pb.command(), params.timeout, pb.directory());
Process process;
KillerTask killer;
ExitCode result = ExitCode.NEVER_STARTED;
try {
process = pb.start();
killer = new KillerTask(process);
killer.schedule(params.timeout);
Utils.copyStream(new InputStreamReader(process.getInputStream()),
out);
try {
result = new ExitCode(process.waitFor());
} catch (InterruptedException e) {
log.println("WARNING: interrupted when waiting for the tool:%n");
e.printStackTrace(log);
} finally {
killer.cancel();
}
if (killer.hasTimedOut()) {
log.printf(
"WARNING: tool timed out: killed process after %d ms%n",
params.timeout);
result = ExitCode.TIMED_OUT;
}
} catch (IOException e) {
log.printf("WARNING: caught IOException while running tool%n");
e.printStackTrace(log);
result = ExitCode.LAUNCH_ERROR;
}
stopwatch.stop();
log.printf("%s%n[%tF %<tT] exit code: %d time: %d ms%n%1$s%n",
line, new Date(), result.value,
TimeUnit.NANOSECONDS.toMillis(stopwatch.getElapsedTimeNs()));
// upon successful completion of the action, generate links to any successArtifacts
// that have been declared for this action
if (ExitCode.OK.equals(result) && params.successArtifacts != null) {
final StringTokenizer t = new StringTokenizer(params.successArtifacts, ",");
while (t.hasMoreTokens()) {
final String artifactPath = t.nextToken().trim();
if (artifactPath.isEmpty()) {
continue;
}
// create a link to the artifact
section.createLink(artifactPath, artifactPath);
}
}
return result;
}
public void runPatternAction(SimpleAction action, HtmlSection section) {
if (action != null) {
HtmlSection subSection = action.getSection(section);
PrintWriter log = subSection.getWriter();
ProcessBuilder pb = action.prepareProcess(log, this);
exec(subSection, pb, action.getParameters());
}
}
public void runPatternAction(PatternAction action, HtmlSection section,
String value) {
if (action != null) {
ProcessBuilder pb = action.prepareProcess(section, this, value);
HtmlSection subSection = action.getSection(section);
exec(subSection, pb, action.getParameters());
}
}
public boolean isJava(long pid, PrintWriter log) {
ProcessBuilder pb = prepareProcess(log, "jps", "-q");
if (pb == null) {
return false;
}
pb.redirectErrorStream(true);
boolean result = false;
String pidStr = "" + pid;
try {
Process process = pb.start();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null){
if (pidStr.equals(line)) {
result = true;
}
}
}
process.waitFor();
} catch (IOException e) {
log.printf("WARNING: can't run jps : %s%n", e.getMessage());
e.printStackTrace(log);
} catch (InterruptedException e) {
log.printf("WARNING: interrupted%n");
e.printStackTrace(log);
}
return result;
}
private static class KillerTask extends TimerTask {
private static final Timer WATCHDOG = new Timer("WATCHDOG", true);
private final Process process;
private boolean timedOut;
public KillerTask(Process process) {
this.process = process;
}
public void run() {
try {
process.exitValue();
} catch (IllegalThreadStateException e) {
process.destroyForcibly();
timedOut = true;
}
}
public boolean hasTimedOut() {
return timedOut;
}
public void schedule(long timeout) {
if (timeout > 0) {
WATCHDOG.schedule(this, timeout);
}
}
}
private void exec(HtmlSection section, ProcessBuilder process,
ActionParameters params) {
if (process == null) {
return;
}
PrintWriter sectionWriter = section.getWriter();
if (params.repeat > 1) {
// hold on to the original command and successArtifacts values which potentially
// contain the %iterCount token, since we need to replace it with different value
// on each iteration
String originalSuccessArtifacts = params.successArtifacts;
List<String> originalCommand = process.command();
for (int i = 0, n = params.repeat; i < n; ++i) {
HtmlSection iteration = section.createChildren(
String.format("iteration_%d", i));
PrintWriter writer = iteration.getWriter();
// use the original values with the token (if any)
params.successArtifacts = originalSuccessArtifacts;
process.command(originalCommand);
// replace the %iterCount token (if any)
prepareIteration(i, process, params);
ExitCode exitCode = run(section, writer, writer, process, params);
if (params.stopOnError && !ExitCode.OK.equals(exitCode)) {
sectionWriter.printf(
"ERROR: non zero exit code[%d] -- break.",
exitCode.value);
break;
}
// sleep, if this is not the last iteration
if (i < n - 1) {
try {
Thread.sleep(params.pause);
} catch (InterruptedException e) {
sectionWriter.printf(
"WARNING: interrupted while sleeping between invocations");
e.printStackTrace(sectionWriter);
}
}
}
} else {
prepareIteration(0, process, params);
run(section, section.getWriter(), section.getWriter(), process, params);
}
}
// replaces the occurrences of %iterCount from the process builder command/arguments
// and the action params' "successArtifacts" paths, with the iteration count
private void prepareIteration(int iterationCount, ProcessBuilder pb,
ActionParameters actionParams) {
List<String> command = new ArrayList<>();
for (String arg : pb.command()) {
arg = arg.replaceAll("%iterCount", String.valueOf(iterationCount)) ;
command.add(arg);
}
pb.command(command);
String successArtifacts = actionParams.successArtifacts;
if (successArtifacts != null) {
actionParams.successArtifacts = successArtifacts.replaceAll("%iterCount",
String.valueOf(iterationCount));
}
}
/**
* Special values for prepareProcess exit code.
*
* <p>Can we clash with normal codes?
* On Linux, only [0..255] are returned.
* On Windows, prepareProcess exit codes are stored in unsigned int.
* On MacOSX no limits (except it should fit C int type)
* are defined in the exit() man pages.
*/
private static class ExitCode {
/** Process exits gracefully */
public static final ExitCode OK = new ExitCode(0);
/** Error launching prepareProcess */
public static final ExitCode LAUNCH_ERROR = new ExitCode(-1);
/** Application prepareProcess has been killed by watchdog due to timeout */
public static final ExitCode TIMED_OUT = new ExitCode(-2);
/** Application prepareProcess has never been started due to program logic */
public static final ExitCode NEVER_STARTED = new ExitCode(-3);
public final int value;
private ExitCode(int value) {
this.value = value;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ExitCode exitCode = (ExitCode) o;
return value == exitCode.value;
}
@Override
public int hashCode() {
return value;
}
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.action;
import jdk.test.failurehandler.value.DefaultValue;
import jdk.test.failurehandler.value.Value;
public class ActionParameters {
@Value (name = "repeat")
@DefaultValue (value = "1")
public int repeat = 1;
@Value (name = "pause")
@DefaultValue (value = "500")
public long pause = 500;
@Value (name = "stopOnError")
@DefaultValue (value = "false")
public boolean stopOnError = false;
@Value (name = "timeout")
@DefaultValue (value = "" + 20_000L)
public long timeout = -1L;
@Value (name = "successArtifacts")
@DefaultValue (value = "")
public String successArtifacts = "";
public ActionParameters() { }
}

View file

@ -0,0 +1,145 @@
/*
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.action;
import jdk.test.failurehandler.CoreInfoGatherer;
import jdk.test.failurehandler.ProcessInfoGatherer;
import jdk.test.failurehandler.EnvironmentInfoGatherer;
import jdk.test.failurehandler.HtmlSection;
import jdk.test.failurehandler.Utils;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.zip.GZIPInputStream;
public class ActionSet implements ProcessInfoGatherer, EnvironmentInfoGatherer, CoreInfoGatherer {
private static final String ENVIRONMENT_PROPERTY = "environment";
private static final String ON_PID_PROPERTY = "onTimeout";
private static final String CORES_PROPERTY = "cores";
private final ActionHelper helper;
public String getName() {
return name;
}
private final String name;
private final List<SimpleAction> environmentActions;
private final List<PatternAction> processActions;
private final List<PatternAction> coreActions;
public ActionSet(ActionHelper helper, PrintWriter log, String name) {
this.helper = helper;
this.name = name;
Properties p = Utils.getProperties(name);
environmentActions = getSimpleActions(log, p, ENVIRONMENT_PROPERTY);
processActions = getPatternActions(log, p, ON_PID_PROPERTY);
coreActions = getPatternActions(log, p, CORES_PROPERTY);
}
private List<SimpleAction> getSimpleActions(PrintWriter log, Properties p,
String key) {
String[] tools = getTools(log, p, key);
List<SimpleAction> result = new ArrayList<>(tools.length);
for (String tool : tools) {
try {
SimpleAction action = new SimpleAction(
Utils.prependPrefix(name, tool), tool, p);
result.add(action);
} catch (Exception e) {
log.printf("ERROR: %s cannot be created : %s %n",
tool, e.getMessage());
e.printStackTrace(log);
}
}
return result;
}
private List<PatternAction> getPatternActions(PrintWriter log,
Properties p, String key) {
String[] tools = getTools(log, p, key);
List<PatternAction> result = new ArrayList<>(tools.length);
for (String tool : tools) {
try {
PatternAction action = new PatternAction(
Utils.prependPrefix(name, tool), tool, p);
result.add(action);
} catch (Exception e) {
log.printf("ERROR: %s cannot be created : %s %n",
tool, e.getMessage());
e.printStackTrace(log);
}
}
return result;
}
private String[] getTools(PrintWriter writer, Properties p, String key) {
String value = p.getProperty(key);
if (value == null) {
writer.printf("ERROR: '%s' property is not set%n", key);
return new String[]{};
}
if (value.isEmpty()) {
return new String[]{};
}
return value.split(" ");
}
@Override
public void gatherProcessInfo(HtmlSection section, long pid) {
String pidStr = "" + pid;
for (PatternAction action : processActions) {
if (action.isJavaOnly()) {
if (helper.isJava(pid, section.getWriter())) {
helper.runPatternAction(action, section, pidStr);
}
} else {
helper.runPatternAction(action, section, pidStr);
}
}
}
@Override
public void gatherEnvironmentInfo(HtmlSection section) {
for (SimpleAction action : environmentActions) {
helper.runPatternAction(action, section);
}
}
@Override
public void gatherCoreInfo(HtmlSection section, Path core) {
for (PatternAction action : coreActions) {
helper.runPatternAction(action, section, core.toString());
}
}
}

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.action;
import jdk.test.failurehandler.value.InvalidValueException;
import jdk.test.failurehandler.HtmlSection;
import jdk.test.failurehandler.value.Value;
import jdk.test.failurehandler.value.ValueHandler;
import java.util.Properties;
public class PatternAction implements Action {
@Value(name = "pattern")
private String pattern = null;
private final SimpleAction action;
private final String[] originalArgs;
private final String originalSuccessArtifacts;
public PatternAction(String id, Properties properties)
throws InvalidValueException {
this(id, id, properties);
}
public PatternAction(String name, String id, Properties properties)
throws InvalidValueException {
action = new SimpleAction(name != null ? ("pattern." + name) : "pattern", id, properties);
ValueHandler.apply(this, properties, id);
originalArgs = action.args.clone();
ActionParameters params = action.getParameters();
// just like the "args" the "successArtifacts" param can also contain pattern that
// this PatternAction will (sometimes repeatedly) replace, so we keep track of
// the original (un-replaced text)
originalSuccessArtifacts = params == null ? null : params.successArtifacts;
}
public ProcessBuilder prepareProcess(HtmlSection section,
ActionHelper helper, String value) {
action.sections[0] = value;
section = getSection(section);
String[] args = action.args;
System.arraycopy(originalArgs, 0, args, 0, originalArgs.length);
for (int i = 0, n = args.length; i < n; ++i) {
args[i] = args[i].replace(pattern, value) ;
}
for (int i = 0, n = args.length; i < n; ++i) {
args[i] = args[i].replace("%java", helper.findApp("java").getAbsolutePath());
}
// replace occurrences of the pattern in the "successArtifacts" param
if (originalSuccessArtifacts != null) {
action.getParameters().successArtifacts = originalSuccessArtifacts.replaceAll(pattern,
value);
}
return action.prepareProcess(section.getWriter(), helper);
}
@Override
public HtmlSection getSection(HtmlSection section) {
return action.getSection(section);
}
@Override
public ActionParameters getParameters() {
return action.getParameters();
}
@Override
public boolean isJavaOnly() {
return action.isJavaOnly();
}
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.action;
import jdk.test.failurehandler.HtmlSection;
import jdk.test.failurehandler.value.InvalidValueException;
import jdk.test.failurehandler.value.SubValues;
import jdk.test.failurehandler.value.Value;
import jdk.test.failurehandler.value.ValueHandler;
import jdk.test.failurehandler.value.DefaultValue;
import java.io.PrintWriter;
import java.util.Properties;
public class SimpleAction implements Action {
/* package-private */ final String[] sections;
@Value(name = "javaOnly")
@DefaultValue(value = "false")
private boolean javaOnly = false;
@Value (name = "app")
private String app = null;
@Value (name = "args")
@DefaultValue (value = "")
/* package-private */ String[] args = new String[]{};
@SubValues(prefix = "params")
private final ActionParameters params;
public SimpleAction(String id, Properties properties)
throws InvalidValueException {
this(id, id, properties);
}
public SimpleAction(String name, String id, Properties properties)
throws InvalidValueException {
sections = name.split("\\.");
this.params = new ActionParameters();
ValueHandler.apply(this, properties, id);
}
public ProcessBuilder prepareProcess(PrintWriter log, ActionHelper helper) {
ProcessBuilder process = helper.prepareProcess(log, app, args);
if (process != null) {
process.redirectErrorStream(true);
}
return process;
}
@Override
public boolean isJavaOnly() {
return javaOnly;
}
@Override
public HtmlSection getSection(HtmlSection section) {
return section.createChildren(sections);
}
@Override
public ActionParameters getParameters() {
return params;
}
}

View file

@ -0,0 +1,154 @@
/*
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.jtreg;
import com.sun.javatest.Harness;
import com.sun.javatest.Parameters;
import com.sun.javatest.TestResult;
import com.sun.javatest.regtest.config.RegressionParameters;
import jdk.test.failurehandler.*;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Stream;
/**
* The jtreg test execution observer, which gathers info about
* system and dumps it to a file.
*/
public class GatherDiagnosticInfoObserver implements Harness.Observer {
public static final String LOG_FILENAME = "environment.log";
public static final String ENVIRONMENT_OUTPUT = "environment.html";
public static final String CORES_OUTPUT = "cores.html";
private Path compileJdk;
private Path testJdk;
/*
* The harness calls this method after each test.
*/
@Override
public void finishedTest(TestResult tr) {
if (!tr.getStatus().isError() && !tr.getStatus().isFailed()) {
return;
}
String jtrFile = tr.getFile().toString();
final Path workDir = Paths.get(
jtrFile.substring(0, jtrFile.lastIndexOf('.')));
workDir.toFile().mkdir();
String name = getClass().getName();
PrintWriter log1;
boolean needClose = false;
try {
log1 = new PrintWriter(new FileWriter(
workDir.resolve(LOG_FILENAME).toFile(), true), true);
needClose = true;
} catch (IOException e) {
log1 = new PrintWriter(System.out);
log1.printf("ERROR: %s cannot open log file %s", name,
LOG_FILENAME);
e.printStackTrace(log1);
}
final PrintWriter log = log1;
try {
log.printf("%s ---%n", name);
GathererFactory gathererFactory = new GathererFactory(
OS.current().family, workDir, log,
testJdk, compileJdk);
gatherEnvInfo(workDir, name, log,
gathererFactory.getEnvironmentInfoGatherer());
// generate a cores.html file after parsing the core dump files (if any)
List<Path> coreFiles;
try (Stream<Path> paths = Files.walk(workDir)) {
coreFiles = paths.filter(Files::isRegularFile)
.filter(f -> (f.getFileName().toString().contains("core")
|| f.getFileName().toString().contains("mdmp")))
.toList();
}
gatherCoreInfo(workDir, name, coreFiles, log, gathererFactory.getCoreInfoGatherer());
} catch (Throwable e) {
log.printf("ERROR: exception in observer %s:", name);
e.printStackTrace(log);
} finally {
log.printf("--- %s%n", name);
if (needClose) {
log.close();
} else {
log.flush();
}
}
}
private void gatherCoreInfo(Path workDir, String name, List<Path> coreFiles,
PrintWriter log, CoreInfoGatherer gatherer) {
if (coreFiles.isEmpty()) {
return;
}
try (HtmlPage html = new HtmlPage(workDir, CORES_OUTPUT, true)) {
try (ElapsedTimePrinter timePrinter
= new ElapsedTimePrinter(new Stopwatch(), name, log)) {
// gather information from the contents of each core file
for (Path coreFile : coreFiles) {
gatherer.gatherCoreInfo(html.getRootSection(), coreFile);
}
}
} catch (Throwable e) {
log.printf("ERROR: exception in %s observer while gathering information from"
+ " core dump file", name);
e.printStackTrace(log);
}
}
private void gatherEnvInfo(Path workDir, String name, PrintWriter log,
EnvironmentInfoGatherer gatherer) {
try (HtmlPage html = new HtmlPage(workDir, ENVIRONMENT_OUTPUT, true)) {
try (ElapsedTimePrinter timePrinter
= new ElapsedTimePrinter(new Stopwatch(), name, log)) {
gatherer.gatherEnvironmentInfo(html.getRootSection());
}
} catch (Throwable e) {
log.printf("ERROR: exception in observer on getting environment "
+ "information %s:", name);
e.printStackTrace(log);
}
}
/*
* The harness calls this method one time per run, not per test.
*/
@Override
public void startingTestRun(Parameters params) {
RegressionParameters rp = (RegressionParameters) params;
compileJdk = rp.getCompileJDK().getAbsoluteFile().toPath();
testJdk = rp.getTestJDK().getAbsoluteFile().toPath();
}
}

View file

@ -0,0 +1,99 @@
/*
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.jtreg;
import com.sun.javatest.regtest.TimeoutHandler;
import jdk.test.failurehandler.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Path;
/**
* A timeout handler for jtreg, which gathers information about the timed out
* process and its children.
*/
public class GatherProcessInfoTimeoutHandler extends TimeoutHandler {
private static final String LOG_FILENAME = "processes.log";
private static final String OUTPUT_FILENAME = "processes.html";
public GatherProcessInfoTimeoutHandler(PrintWriter jtregLog, File outputDir,
File testJdk) {
super(jtregLog, outputDir, testJdk);
}
/**
* Runs various actions for jtreg timeout handler.
*
* <p>Please see method code for the actions.
*/
@Override
protected void runActions(Process process, long pid)
throws InterruptedException {
Path workDir = outputDir.toPath();
String name = getClass().getName();
PrintWriter actionsLog;
try {
// try to open a separate file for action log
actionsLog = new PrintWriter(new FileWriter(
workDir.resolve(LOG_FILENAME).toFile(), true), true);
} catch (IOException e) {
// use jtreg log as a fallback
actionsLog = log;
actionsLog.printf("ERROR: %s cannot open log file %s : %s", name,
LOG_FILENAME, e.getMessage());
}
try {
actionsLog.printf("%s ---%n", name);
runGatherer(name, actionsLog, pid);
} finally {
actionsLog.printf("--- %s%n", name);
// don't close jtreg log
if (actionsLog != log) {
actionsLog.close();
} else {
log.flush();
}
}
}
private void runGatherer(String name, PrintWriter log, long pid) {
Path workDir = outputDir.toPath();
try (HtmlPage html = new HtmlPage(workDir, OUTPUT_FILENAME, true)) {
ProcessInfoGatherer gatherer = new GathererFactory(
OS.current().family,
workDir, log, testJdk.toPath()).getProcessInfoGatherer();
try (ElapsedTimePrinter timePrinter
= new ElapsedTimePrinter(new Stopwatch(), name, log)) {
gatherer.gatherProcessInfo(html.getRootSection(), pid);
}
} catch (Throwable e) {
log.printf("ERROR: exception in timeout handler %s:", name);
e.printStackTrace(log);
}
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.jtreg;
// Stripped down version of jtreg internal class com.sun.javatest.regtest.config.OS
class OS {
public final String family;
private static OS current;
public static OS current() {
if (current == null) {
String name = System.getProperty("os.name");
current = new OS(name);
}
return current;
}
private OS(String name) {
if (name.startsWith("AIX")) {
family = "aix";
} else if (name.startsWith("Linux")) {
family = "linux";
} else if (name.startsWith("Mac") || name.startsWith("Darwin")) {
family = "mac";
} else if (name.startsWith("Windows")) {
family = "windows";
} else {
// use first word of name
family = name.replaceFirst("^([^ ]+).*", "$1");
}
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.value;
import java.lang.reflect.Array;
import java.util.Objects;
public class ArrayParser implements ValueParser {
private final ValueParser parser;
public ArrayParser(ValueParser parser) {
Objects.requireNonNull(parser);
this.parser = parser;
}
@Override
public Object parse(Class<?> type, String value, String delimiter) {
Class<?> component = type.getComponentType();
if (component.isArray()) {
throw new IllegalArgumentException(
"multidimensional array fields aren't supported");
}
String[] values = (value == null || value.isEmpty())
? new String[]{}
: value.split(delimiter);
Object result = Array.newInstance(component, values.length);
for (int i = 0, n = values.length; i < n; ++i) {
Array.set(result, i, parser.parse(component, values[i], delimiter));
}
return result;
}
}

View file

@ -0,0 +1,120 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.value;
import java.util.HashMap;
import java.util.Map;
public class DefaultParser implements ValueParser {
private static final Map<Class<?>, BasicParser> PARSERS = new HashMap<>();
static {
BasicParser.init();
}
@Override
public Object parse(Class<?> type, String value, String s) {
if (type.isArray()) {
return new ArrayParser(this).parse(type, value, s);
}
ValueParser parser = PARSERS.get(type);
if (parser == null) {
throw new IllegalArgumentException("can't find parser for "
+ type.getName());
}
return parser.parse(type, value, s);
}
private static enum BasicParser implements ValueParser {
BOOL(boolean.class, Boolean.class) {
@Override
public Object parse(Class<?> type, String value, String s) {
return Boolean.valueOf(value);
}
},
BYTE(byte.class, Byte.class) {
@Override
public Object parse(Class<?> type, String value, String s) {
return Byte.decode(value);
}
},
CHAR(char.class, Character.class) {
@Override
public Object parse(Class<?> type, String value, String s) {
if (value.length() != 1) {
throw new IllegalArgumentException(
String.format("can't cast %s to char", value));
}
return value.charAt(0);
}
},
SHORT(short.class, Short.class) {
@Override
public Object parse(Class<?> type, String value, String s) {
return Short.decode(value);
}
},
INT(int.class, Integer.class) {
@Override
public Object parse(Class<?> type, String value, String s) {
return Integer.decode(value);
}
},
LONG(long.class, Long.class) {
@Override
public Object parse(Class<?> type, String value, String s) {
return Long.decode(value);
}
},
FLOAT(float.class, Float.class) {
@Override
public Object parse(Class<?> type, String value, String s) {
return Float.parseFloat(value);
}
},
DOUBLE(double.class, Double.class) {
@Override
public Object parse(Class<?> type, String value, String s) {
return Double.parseDouble(value);
}
},
STRING(String.class, Object.class) {
@Override
public Object parse(Class<?> type, String value, String s) {
return value;
}
};
private BasicParser(Class<?>... classes) {
for (Class<?> aClass : classes) {
DefaultParser.PARSERS.put(aClass, this);
}
}
private static void init() {
// no-op used to provoke <cinit>
}
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.value;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.FIELD)
public @interface DefaultValue {
String value();
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.value;
public class InvalidValueException extends Exception {
public InvalidValueException() { }
public InvalidValueException(String message) {
super(message);
}
public InvalidValueException(String s, Throwable e) {
super(s, e);
}
public InvalidValueException(Throwable cause) {
super(cause);
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.value;
import java.io.File;
public class PathValueParser implements ValueParser {
@Override
public Object parse(Class<?> type, String value, String delimiter) {
if (type.isArray()) {
return new ArrayParser(this).parse(type, value, delimiter);
}
return new File(value).toPath();
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.value;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.FIELD)
public @interface SubValues {
String prefix();
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.value;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.FIELD)
public @interface Value {
String name();
Class<? extends ValueParser> parser() default DefaultParser.class;
}

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.value;
import jdk.test.failurehandler.Utils;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Objects;
import java.util.Properties;
public final class ValueHandler {
public static <T> void apply(T object, Properties properties,
String prefix) throws InvalidValueException {
Objects.requireNonNull(object, "object cannot be null");
Objects.requireNonNull(properties, "properties cannot be null");
Class<?> aClass = object.getClass();
while (aClass != null) {
for (Field field : aClass.getDeclaredFields()) {
Value p = field.getAnnotation(Value.class);
if (p != null) {
applyToField(p, object, field, properties, prefix);
} else {
SubValues sub
= field.getAnnotation(SubValues.class);
if (sub != null) {
getAccess(field);
try {
apply(field.get(object), properties,
Utils.prependPrefix(prefix, sub.prefix()));
} catch (IllegalAccessException e) {
throw new InvalidValueException(String.format(
"can't apply sub properties to %s.",
field.getName()));
}
}
}
}
aClass = aClass.getSuperclass();
}
}
private static void applyToField(Value property, Object object,
Field field, Properties properties, String prefix)
throws InvalidValueException {
getAccess(field);
if (Modifier.isFinal(field.getModifiers())) {
throw new InvalidValueException(
String.format("field '%s' is final", field));
}
String name = Utils.prependPrefix(prefix, property.name());
String value = getProperty(properties, prefix, property.name());
if (value == null) {
DefaultValue defaultValue
= field.getAnnotation(DefaultValue.class);
value = defaultValue == null ? null : defaultValue.value();
}
if (value == null) {
throw new InvalidValueException(String.format(
"can't set '%s', because properties don't have '%s'.",
field.getName(), name));
}
String delimiter = getProperty(properties,
Utils.prependPrefix(prefix, property.name()), "delimiter");
delimiter = delimiter == null ? " " : delimiter;
Class<? extends ValueParser> parserClass = property.parser();
try {
field.set(object, parserClass.getDeclaredConstructor().newInstance().parse(
field.getType(), value, delimiter));
} catch (ReflectiveOperationException | IllegalArgumentException e) {
throw new InvalidValueException(
String.format("can't set field '%s' : %s",
field.getName(), e.getMessage()), e);
}
}
private static String getProperty(Properties properties,
String prefix, String name) {
if (prefix == null || prefix.isEmpty()) {
return properties.getProperty(name);
}
int index = prefix.length();
do {
String value = properties.getProperty(
Utils.prependPrefix(prefix.substring(0, index), name));
if (value != null) {
return value;
}
index = prefix.lastIndexOf('.', index - 1);
} while (index > 0);
return properties.getProperty(name);
}
private static void getAccess(Field field) {
int modifiers = field.getModifiers();
if (!Modifier.isPublic(modifiers)) {
field.setAccessible(true);
}
}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.failurehandler.value;
public interface ValueParser {
Object parse(Class<?> type, String value, String delimiter);
}

View file

@ -0,0 +1,97 @@
#
# Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
pattern=%p
javaOnly=true
args=%p
################################################################################
# process info to gather
################################################################################
# It's important to retain the order of these actions and run the thread dump
# generating commands before the rest, to allow for capturing the test
# process' call stack as soon as the timeout has occurred. That reduces the chances
# of the test completing and thus missing crucial details from the thread dump
# while these timeout actions were being run.
onTimeout=\
thread_dump \
jinfo \
jcmd.compiler.codecache jcmd.compiler.codelist \
jcmd.compiler.queue \
jcmd.vm.classloader_stats jcmd.vm.stringtable \
jcmd.vm.symboltable jcmd.vm.uptime jcmd.vm.dynlibs \
jcmd.vm.system_properties jcmd.vm.info \
jcmd.gc.heap_info jcmd.gc.class_histogram jcmd.gc.finalizer_info jcmd.thread.dump_to_file jcmd.thread.vthread_scheduler \
jstack jhsdb.jstack.live.default jhsdb.jstack.live.mixed
jinfo.app=jinfo
jcmd.app=jcmd
jcmd.compiler.codecache.args=%p Compiler.codecache
jcmd.compiler.codelist.args=%p Compiler.codelist
jcmd.compiler.queue.args=%p Compiler.queue
jcmd.vm.classloader_stats.args=%p VM.classloader_stats
jcmd.vm.stringtable.args=%p VM.stringtable
jcmd.vm.symboltable.args=%p VM.symboltable
jcmd.vm.uptime.args=%p VM.uptime
jcmd.vm.dynlibs.args=%p VM.dynlibs
jcmd.vm.system_properties.args=%p VM.system_properties
jcmd.vm.info.args=%p VM.info
jcmd.gc.class_histogram.args=%p GC.class_histogram
jcmd.gc.finalizer_info.args=%p GC.finalizer_info
jcmd.gc.heap_info.args=%p GC.heap_info
jcmd.thread.dump_to_file.args=%p Thread.dump_to_file -format=json JavaThread.dump.%p.%iterCount
jcmd.thread.dump_to_file.params.repeat=6
jcmd.thread.dump_to_file.params.successArtifacts=JavaThread.dump.%p.%iterCount
jcmd.thread.vthread_scheduler.args=%p Thread.vthread_scheduler
# use jstack to generate one thread dump
thread_dump.app=jstack
thread_dump.args=-e -l %p
jstack.app=jstack
jstack.args=-e -l %p
jstack.params.repeat=5
jhsdb.app=jhsdb
jhsdb.jstack.live.default.args=jstack --pid %p
jhsdb.jstack.live.default.params.repeat=6
jhsdb.jstack.live.mixed.args=jstack --mixed --pid %p
jhsdb.jstack.live.mixed.params.repeat=6
cores=jhsdb.jstack.core.default jhsdb.jstack.core.mixed
# Assume that java standard laucher has been used
jhsdb.jstack.core.default.args=jstack --core %p --exe %java
jhsdb.jstack.core.mixed.args=jstack --mixed --core %p --exe %java
################################################################################
# environment info to gather
################################################################################
environment=jps
jps.app=jps
jps.args=-mlv
################################################################################

View file

@ -0,0 +1,155 @@
#
# Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
config.execSuffix=
config.getChildren.pattern=%p
config.getChildren.app=ps
config.getChildren.args=--no-headers -o pid --ppid %p
################################################################################
# process info to gather
################################################################################
onTimeout=\
native.pmap.normal native.pmap.everything \
native.files native.locks \
native.stack native.core
################################################################################
native.pattern=%p
native.javaOnly=false
native.args=%p
native.pmap.app=pmap
native.pmap.normal.args=-p %p
native.pmap.everything.args=-XXp %p
native.files.app=lsof
native.files.args=-p %p
native.locks.app=lslocks
native.locks.args=-u --pid %p
native.stack.app=gdb
native.stack.args=--pid=%p\0-batch\0-ex\0info threads\0-ex\0thread apply all backtrace
native.stack.args.delimiter=\0
native.stack.params.repeat=6
# has to be the last command
native.core.app=bash
# The below trick was found on https://stackoverflow.com/a/41613532
native.core.args=-c\0kill -ABRT %p && tail --pid=%p -f /dev/null
native.core.args.delimiter=\0
native.core.timeout=600000
cores=native.gdb
native.gdb.app=gdb
# Assume that java standard laucher has been used
native.gdb.args=%java\0-c\0%p\0-batch\0-ex\0info threads\0-ex\0thread apply all backtrace
native.gdb.args.delimiter=\0
################################################################################
# environment info to gather
################################################################################
environment=\
users.current users.logged users.last \
disk \
env \
ulimit \
system.dmesg system.sysctl \
process.top process.ps \
memory.free memory.vmstat.default memory.vmstat.statistics \
memory.vmstat.slabinfo memory.vmstat.disk \
memory.proc_meminfo memory.proc_vmstat \
memory.thp \
files \
locks \
net.sockets net.statistics net.ifconfig net.hostsfile \
screenshot
################################################################################
users.current.app=id
users.current.args=-a
users.logged.app=who
users.logged.args=-a
users.last.app=last
users.last.args=-10
disk.app=df
disk.args=-h
env.app=env
ulimit.app=bash
ulimit.args=-c\0ulimit -a
ulimit.args.delimiter=\0
system.dmesg.app=dmesg
system.sysctl.app=sysctl
system.sysctl.args=-a
process.top.app=top
process.top.args=-b -n 1
process.ps.app=ps
process.ps.args=-eo pid,pcpu,cputime,start,pmem,vsz,rssize,stackp,stat,sgi_p,wchan,user,args
memory.free.app=free
memory.free.args=-h
memory.vmstat.app=vmstat
memory.vmstat.default.args=3 3
memory.vmstat.statistics.args=-s
memory.vmstat.slabinfo.args=-m
memory.vmstat.disk.args=-d
memory.proc_meminfo.app=bash
memory.proc_meminfo.args=-c\0cat /proc/meminfo
memory.proc_meminfo.delimiter=\0
memory.proc_vmstat.app=bash
memory.proc_vmstat.args=-c\0cat /proc/vmstat
memory.proc_vmstat.delimiter=\0
memory.thp.app=bash
memory.thp.args=-c\0cat /sys/kernel/mm/transparent_hugepage/{enabled,defrag,shmem_enabled}
memory.thp.delimiter=\0
files.app=lsof
locks.app=lslocks
locks.args=-u
net.sockets.app=netstat
net.sockets.args=-aeeopv
net.statistics.app=netstat
net.statistics.args=-sv
net.ifconfig.app=ifconfig
net.ifconfig.args=-a
net.hostsfile.app=cat
net.hostsfile.args=/etc/hosts
screenshot.app=bash
screenshot.args=-c\0\
echo '\
var robot = new java.awt.Robot();\
var ge = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment();\
var bounds = ge.getDefaultScreenDevice().getDefaultConfiguration().getBounds();\
var capture = robot.createScreenCapture(bounds);\
var file = new java.io.File("screen.png");\
javax.imageio.ImageIO.write(capture, "png", file);\
' | jshell -
screenshot.args.delimiter=\0
################################################################################

View file

@ -0,0 +1,153 @@
#
# Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
config.execSuffix=
config.getChildren.pattern=%p
config.getChildren.app=pgrep
config.getChildren.args=-P %p
################################################################################
# process info to gather
################################################################################
onTimeout=\
native.DevToolsSecurity \
native.vmmap native.heap native.leaks native.spindump \
native.stack native.core
################################################################################
native.pattern=%p
native.javaOnly=false
native.args=%p
native.DevToolsSecurity.app=DevToolsSecurity
native.DevToolsSecurity.args=--status
# spindump requires root privileges
native.spindump.app=sudo
native.spindump.args=spindump %p -stdout
native.vmmap.app=bash
native.vmmap.delimiter=\0
native.vmmap.args=-c\0DevToolsSecurity --status | grep -q enabled && vmmap %p
native.leaks.app=bash
native.leaks.delimiter=\0
native.leaks.args=-c\0DevToolsSecurity --status | grep -q enabled && leaks %p
native.heap.app=bash
native.heap.delimiter=\0
native.heap.args=-c\0DevToolsSecurity --status | grep -q enabled && heap %p
native.stack.app=bash
native.stack.delimiter=\0
native.stack.params.repeat=6
native.stack.args=-c\0DevToolsSecurity --status | grep -q enabled && lldb -o 'attach %p' -o 'thread backtrace all' -o 'detach' -o 'quit'
# has to be the last command
native.core.app=bash
# The below trick was found on https://stackoverflow.com/a/41613532
native.core.args=-c\0kill -ABRT %p && lsof -p %p +r 1 &>/dev/null
native.core.delimiter=\0
native.core.timeout=600000
cores=native.lldb
native.lldb.app=lldb
native.lldb.delimiter=\0
# Core files can be very big and take a long time to load on macosx-aarch64.
# The 20 seconds default timeout is not nearly enough.
native.lldb.timeout=120000
# Assume that java standard laucher has been used
native.lldb.args=--core\0%p\0%java\0-o\0thread backtrace all\0-o\0quit
################################################################################
# environment info to gather
################################################################################
environment=\
users.current users.logged users.last \
disk \
env \
ulimit \
system.dmesg system.sysctl \
process.ps process.top \
memory.vmstat \
files \
net.netstat.anv net.netstat.av net.netstat.aL net.netstat.m net.netstat.s net.netstat.g net.netstat.r \
net.ifconfig net.hostsfile \
fw.up \
scutil.nwi scutil.proxy \
screenshot
################################################################################
users.current.app=id
users.current.args=-a
users.logged.app=who
users.logged.args=-a
users.last.app=last
users.last.args=-10
disk.app=df
disk.args=-h
env.app=env
ulimit.app=bash
ulimit.args=-c\0ulimit -a
ulimit.args.delimiter=\0
system.dmesg.app=sudo
system.dmesg.args=dmesg
system.sysctl.app=sysctl
system.sysctl.args=-a
process.ps.app=ps
process.ps.args=-Meo pid,pcpu,cputime,start,pmem,vsz,rss,state,wchan,user,args
process.top.app=top
process.top.args=-l 2
memory.vmstat.app=vm_stat
memory.vmstat.args=-c 3 3
files.app=lsof
net.netstat.app=netstat
net.netstat.av.args=-av
net.netstat.anv.args=-anv
net.netstat.aL.args=-aL
net.netstat.m.args=-mm
net.netstat.s.args=-s
net.netstat.g.args=-gs
net.netstat.r.args=-rn
net.ifconfig.app=ifconfig
net.ifconfig.args=-a
net.hostsfile.app=cat
net.hostsfile.args=/etc/hosts
scutil.app=scutil
scutil.nwi.args=--nwi
scutil.proxy.args=--proxy
screenshot.app=screencapture
screenshot.args=-x screen1.png screen2.png screen3.png screen4.png screen5.png
fw.app=/usr/libexec/ApplicationFirewall/socketfilterfw
fw.up.args=--getglobalstate
################################################################################

View file

@ -0,0 +1,143 @@
#
# Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
config.execSuffix=.exe
config.getChildren.app=powershell
config.getChildren.pattern=%p
config.getChildren.args.delimiter=\0
config.getChildren.args=-NoLogo\0-Command\0"Get-CimInstance Win32_Process -Filter \\\"ParentProcessId = %p\\\" | Select-Object ProcessId" | tail -n+4
################################################################################
# process info to gather
################################################################################
onTimeout=\
native.info \
native.pmap.normal native.pmap.everything \
native.files native.locks \
native.stack native.core
################################################################################
native.pattern=%p
native.javaOnly=false
native.args=%p
native.info.app=powershell
native.info.delimiter=\0
native.info.args=-NoLogo\0-Command\0"Get-WmiObject Win32_Process -Filter \\\"ProcessId = %p\\\" | Format-List -Property *"
native.pmap.app=pmap
native.pmap.normal.args=%p
native.pmap.everything.args=-x %p
native.files.app=handle
native.files.args=-p %p
# TODO
native.locks.app=lslocks
native.locks.args=-u --pid %p
native.stack.app=cdb
native.stack.args=-c "~*kP n;qd" -p %p
native.stack.params.repeat=6
native.core.app=cdb
native.core.args=-c ".dump /mA core.%p;qd" -p %p
native.core.params.timeout=600000
cores=
################################################################################
# environment info to gather
################################################################################
environment=\
users.current users.logged \
disk \
env \
ulimit \
system.events.system system.events.application system.os \
process.top process.ps process.tasklist \
memory.free memory.vmstat.default memory.vmstat.statistics \
memory.vmstat.slabinfo memory.vmstat.disk \
files \
net.sockets net.statistics net.ipconfig net.hostsfile \
screenshot
################################################################################
users.current.app=id
users.current.args=-a
users.logged.app=query
users.logged.args=user
disk.app=df
disk.args=-h
env.app=env
ulimit.app=bash
ulimit.args=-c\0ulimit -a
ulimit.args.delimiter=\0
system.events.app=powershell
system.events.delimiter=\0
system.events.system.args=-NoLogo\0-Command\0Get-EventLog System -After (Get-Date).AddDays(-1) | Format-List
system.events.application.args=-NoLogo\0-Command\0Get-EventLog Application -After (Get-Date).AddDays(-1) | Format-List
system.os.app=powershell
system.os.delimiter=\0
system.os.args=-NoLogo\0-Command\0Get-WmiObject Win32_OperatingSystem | Format-List -Property *
process.top.app=top
process.top.args=-b -n 1
process.ps.app=ps
process.ps.args=-efW
process.tasklist.app=tasklist
process.tasklist.args=/V
memory.free.app=free
memory.vmstat.app=vmstat
memory.vmstat.statistics.args=-s
memory.vmstat.slabinfo.args=-m
memory.vmstat.disk.args=-d
files.app=openfiles
files.args=/query
net.sockets.app=bash
net.sockets.args=-c\0netstat -b -a -t -o || netstat -a -t -o
net.sockets.args.delimiter=\0
net.statistics.app=netstat
net.statistics.args=-s -e
net.ipconfig.app=ipconfig
net.ipconfig.args=/all
net.hostsfile.app=bash
net.hostsfile.args.delimiter=\0
net.hostsfile.args=-c\0cat $WINDIR/System32/drivers/etc/hosts
screenshot.app=bash
screenshot.args=-c\0\
echo '\
var robot = new java.awt.Robot();\
var ge = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment();\
var bounds = ge.getDefaultScreenDevice().getDefaultConfiguration().getBounds();\
var capture = robot.createScreenCapture(bounds);\
var file = new java.io.File(""screen.png"");\
javax.imageio.ImageIO.write(capture, ""png"", file);\
' | jshell -
screenshot.args.delimiter=\0
################################################################################