Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix flaky/broken DSF GDB tests #985

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ on: [push, pull_request]
jobs:
build:

runs-on: ubuntu-20.04
timeout-minutes: 90
runs-on: ubuntu-24.04
timeout-minutes: 120

steps:
- uses: actions/checkout@v4
Expand Down
9 changes: 8 additions & 1 deletion docker/scripts/download-build-gdb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ jlevel="${default_jlevel}"

# Supported versions
# Note starting in GDB 9.x the .x is the patch release, so for example we have 9.2 in this list, but not 9.1.
default_versions="12.1 11.2 10.2 9.2 8.3.1 8.2.1 8.1.1 8.0.1 7.12.1 7.11.1 7.10.1 7.9.1 7.8.2 7.7.1 7.6.2 7.5.1 7.4.1 7.3.1 7.2 7.1 7.0.1 6.8 6.7.1 6.6"
old_version="9.2 8.3.1 8.2.1 8.1.1 8.0.1 7.12.1 7.11.1 7.10.1 7.9.1 7.8.2 7.7.1 7.6.2 7.5.1 7.4.1 7.3.1 7.2 7.1 7.0.1 6.8 6.7.1 6.6"
default_versions="16.1 15.2 14.2 13.2 12.1 11.2 10.2"

# Is set to "echo" if we are doing a dry-run.
dryrun=""
Expand Down Expand Up @@ -65,6 +66,8 @@ function help_and_exit() {
echo ""
echo "Supported versions:"
echo " ${default_versions}"
echo "Older versions:"
echo " ${old_version}"
echo ""
echo "Examples:"
echo " Build versions 7.7.1 and 7.8.2:"
Expand All @@ -89,13 +92,17 @@ function echo_header() {
# $1: version number
function check_supported() {
local supported_pattern="@(${default_versions// /|})"
local old_pattern="@(${old_version// /|})"
local version="$1"

shopt -s extglob
case "$version" in
${supported_pattern})
# Supported, do nothing.
;;
${old_pattern})
# Supported, do nothing.
;;
*)
echo "Error: version ${version} is not supported by this script."
echo ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public String[] getDebuggerCommandLineArray() {
"--interpreter", "console", //$NON-NLS-1$ //$NON-NLS-2$

// Now trigger the new console towards our PTY.
"-ex", "new-ui mi " + fMIPty.getSlaveName(), //$NON-NLS-1$ //$NON-NLS-2$
"-ex", "new-ui mi2 " + fMIPty.getSlaveName(), //$NON-NLS-1$ //$NON-NLS-2$

// With GDB.7.12, pagination can lock up the whole debug session
// when using the full GDB console, so we turn it off.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -626,8 +626,8 @@ void parse(MITuple tuple) {
// Only supported starting with GDB 6.8
pending = true;
} else if (var.equals("script")) { //$NON-NLS-1$
if (value instanceof MITuple) {
parseCommands((MITuple) value);
if (value instanceof MITuple || value instanceof MIList) {
parseCommands(value);
}
} else if (var.equals("thread-groups")) { //$NON-NLS-1$
if (value instanceof MIList) {
Expand All @@ -639,8 +639,20 @@ void parse(MITuple tuple) {
}
}

void parseCommands(MITuple tuple) {
MIValue[] values = tuple.getMIValues();
void parseCommands(MIValue miValue) {
// "script" field of a breakpoint used to be output as a tuple (<= GDB 12),
// though it is a list. There are cases of flags that can be applied to
// get old or new behaviour too.
// This code handles both cases transparently.
// See https://sourceware.org/bugzilla/show_bug.cgi?id=24285
MIValue[] values;
if (miValue instanceof MITuple tuple) {
values = tuple.getMIValues();
} else if (miValue instanceof MIList list) {
values = list.getMIValues();
} else {
throw new IllegalStateException("miValue must be tuple or list"); //$NON-NLS-1$
}
StringBuilder cmds = new StringBuilder();
for (int i = 0; i < values.length; i++) {
MIValue value = values[i];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ int testUpdateIssue() {
/* testUpdateIssue_init */
a = 1.22;
a = 1.22; // this redundant line is here to ensure 3 steps after running to this func leaves locals visible
return 0;
}

int testUpdateIssue2() {
Expand All @@ -262,7 +263,8 @@ int testUpdateIssue2() {
z.d = 1.0;
/* testUpdateIssue2_init */
z.d = 1.22;
z.d = 1.22; // this redundant line is here to ensure 3 steps after running to this func leaves locals visible
z.d = 1.22; // this redundant line is here to ensure 3 steps after running to this func leaves locals visible
return 0;
}

int testConcurrentReadAndUpdateChild() {
Expand All @@ -273,6 +275,7 @@ int testConcurrentReadAndUpdateChild() {
z.d = 1;
/* testConcurrentReadAndUpdateChild_init */
z.d = 2;
return 0;
}

int testConcurrentUpdateOutOfScopeChildThenParent1() {
Expand All @@ -283,6 +286,7 @@ int testConcurrentUpdateOutOfScopeChildThenParent1() {
z.d = 1;
/* testConcurrentUpdateOutOfScopeChildThenParent1_init */
z.d = 1; // this redundant line is here to ensure 2 steps after running to this func leaves locals visible
return 0;
}

int testConcurrentUpdateOutOfScopeChildThenParent2() {
Expand All @@ -293,11 +297,13 @@ int testConcurrentUpdateOutOfScopeChildThenParent2() {
z.d = 2;
/* testConcurrentUpdateOutOfScopeChildThenParent2_init */
z.d = 2; // this redundant line is here to ensure 2 steps after running to this func leaves locals visible
return 0;
}

int testConcurrentUpdateOutOfScopeChildThenParent() {
testConcurrentUpdateOutOfScopeChildThenParent1();
testConcurrentUpdateOutOfScopeChildThenParent2();
return 0;
}

int testUpdateOfPointer() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ int envTest() {
char *home, *launchTest;
home = getenv("HOME");
launchTest = getenv("LAUNCHTEST");
return 0;
return 0; // END_ENV_TEST_LINE
}

int main (int argc, char *argv[])
Expand All @@ -29,7 +29,7 @@ int main (int argc, char *argv[])
var = 3;
var = 4; // three_steps_back_from_b_stopAtOther
var = 5;
stopAtOther(); // main_init
stopAtOther(); // MAIN_INIT_LINE
reverseTest(); // tests assume that every line between first and last
envTest(); // is steppable, so no blank lines allowed.
return 36; // LAST_LINE_IN_MAIN
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
int value() {
int a = 1; // VALUE_LINE
int value()
{ int a = 1; // VALUE_LINE
return 1;
}
Original file line number Diff line number Diff line change
@@ -1,82 +1,81 @@
#include "StepIntoSelection.h"

int foo() {
int i = 0; // FOO_LINE
int foo()
{ int i = 0; // FOO_LINE
return 1;
}

int bar(int i) {
int b = 0; // BAR_LINE
int bar(int i)
{ int b = 0; // BAR_LINE
return i + b;
}

int add(int a) {
return a + 1; // ADD_WITH_ARG_LINE
int add(int a)
{ return a + 1; // ADD_WITH_ARG_LINE
}

int add() {
return 1; // ADD_NO_ARG_LINE
int add()
{ return 1; // ADD_NO_ARG_LINE
}

int recursiveTest(int a) {
if (a == 1) return a;
int recursiveTest(int a)
{ if (a == 1) return a;

return a + recursiveTest(--a); // The test expects this line to be exactly 2 lines below the first line of the method
return a + recursiveTest(--a); // RECURSIVE_LINE
}

int sameLineTest() {
foo();
int sameLineTest()
{ foo();
return 0;
}

int sameLineBreakpointTest() {
bar(foo());
int sameLineBreakpointTest()
{ bar(foo());
return 0;
}

int doubleMethodTest() {
int a = 0;
bar(foo()); // The test expects this line to be one line below the star of the method
int doubleMethodTest()
{ int a = 0;
bar(foo()); // DOUBLE_METHOD_LINE
return 0;
}

int laterLineTest() {
int i = 0;
int laterLineTest()
{ int i = 0; // LATER_LINE_ENTRY_LINE
i++;
i++;
foo(); // The test expects this line to be exactly 3 lines below the first line of the method
foo(); // LATER_LINE_LINE
i++;
i++;
return 0;
}

int laterLineNotHitTest() {
int i = 0;
int laterLineNotHitTest()
{ int i = 0;
if (i==100) { // Won't hit
foo(); // The test expects this line to be exactly 2 lines below the first line of the method
foo(); // LATER_LINE_NOT_HIT_LINE
}
i++;
i++;
return 0;
}

int laterLineDifferentFileTest() {
int b = 0;
value(); // Must be one line below start of the method
// value() is from .h header file
int laterLineDifferentFileTest()
{ int b = 0;
value(); // LATER_LINE_DIFFERENT_FILE_LINE
return 0;
}

int differentFileTest() {

return 0;
int differentFileTest()
{ return 0;
}

int methodWithDiffArgsNumberTest() {
return add() + add(2);
int methodWithDiffArgsNumberTest()
{ return add() + add(2);
}

int main() {
sameLineTest();
int main()
{ sameLineTest();
laterLineTest();
laterLineNotHitTest();
doubleMethodTest();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@
import static org.junit.Assert.assertTrue;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.Reader;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
Expand Down Expand Up @@ -54,10 +57,12 @@
import org.eclipse.cdt.tests.dsf.gdb.tests.ITestConstants;
import org.eclipse.cdt.utils.spawner.ProcessFactory;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IBreakpointManager;
import org.eclipse.debug.core.ILaunch;
Expand All @@ -66,6 +71,8 @@
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.core.model.RuntimeProcess;
import org.eclipse.debug.internal.core.IInternalDebugCoreConstants;
import org.junit.After;
import org.junit.AfterClass;
Expand Down Expand Up @@ -659,7 +666,74 @@ protected void assertLaunchTerminates(GdbLaunch launch, boolean terminate) throw
@After
public void doAfterTest() throws Exception {
if (fLaunch != null) {
fLaunch.terminate();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PrintStream out = new PrintStream(byteArrayOutputStream, true, "UTF-8");
IProcess[] processes = fLaunch.getProcesses();

out.println("Processes: " + Arrays.toString(processes));
for (IProcess process : processes) {
out.println("Process: " + process);
if (process instanceof RuntimeProcess runtimeProcess) {
Field field = RuntimeProcess.class.getDeclaredField("fProcess");
field.trySetAccessible();
Process javaProcess = (Process) field.get(runtimeProcess);
out.println("javaProcess: " + javaProcess);
try {
List<ProcessHandle> descendants = javaProcess.descendants().collect(Collectors.toList());
out.println("descendants: " + descendants);
} catch (UnsupportedOperationException e) {
out.println("descendants unsupported");
}
} else {
out.println("Class: " + process.getClass());
}
if (process.isTerminated()) {
out.println("isTerminated: true");
out.println("exitValue: " + process.getExitValue());
} else {
out.println("isTerminated: false");
}
}
boolean failed = false;
for (IProcess process : processes) {
out.println("TERMINATING");
out.println("Process: " + process);

if (process instanceof RuntimeProcess runtimeProcess) {
Field field = RuntimeProcess.class.getDeclaredField("fProcess");
field.trySetAccessible();
Process javaProcess = (Process) field.get(runtimeProcess);
if (javaProcess == null) {
out.println("javaProcess: null");
} else {
javaProcess.destroy();
out.println("WAITING");
boolean waitFor = javaProcess.waitFor(1, TimeUnit.SECONDS);
out.println("waitFor: " + waitFor);
if (waitFor) {
out.println("exitValue: " + javaProcess.exitValue());
} else {
failed = true;
}
}
}
}
String info = byteArrayOutputStream.toString("UTF-8");
try {
fLaunch.terminate();
if (failed) {
throw new RuntimeException("Failed to terminate\ninfo:\n" + info);
}
} catch (DebugException e) {
IStatus status = e.getStatus();
if (status != null) {
String statusString = status.toString();
throw new RuntimeException("Received debug exception with: " + statusString + "\ninfo:\n" + info,
e);
} else {
throw new RuntimeException("Received debug with no status\ninfo:\n" + info, e);
}
}
assertLaunchTerminates();
fLaunch = null;
}
Expand Down
Loading
Loading