GP-487 Fix pasting multi-line string into python console

This commit is contained in:
dev747368
2020-12-15 15:14:38 -05:00
parent 8be90db260
commit 0fad371a83
5 changed files with 400 additions and 138 deletions

View File

@@ -245,8 +245,14 @@ public class GhidraPythonInterpreter extends InteractiveInterpreter {
* @param str The string to print.
*/
void printErr(String str) {
getSystemState().stderr.invoke("write", new PyString(str + "\n"));
getSystemState().stderr.invoke("flush");
try {
getSystemState().stderr.invoke("write", new PyString(str + "\n"));
getSystemState().stderr.invoke("flush");
}
catch (PyException e) {
// if the python interp state's stdin/stdout/stderr is messed up, it can throw an error
Msg.error(this, "Failed to write to stderr", e);
}
}
/**

View File

@@ -59,6 +59,8 @@ import resources.ResourceManager;
public class PythonPlugin extends ProgramPlugin
implements InterpreterConnection, OptionsChangeListener {
private final static int INPUT_THREAD_SHUTDOWN_TIMEOUT_MS = 1000;
private InterpreterConsole console;
private GhidraPythonInterpreter interpreter;
private PythonScript interactiveScript;
@@ -202,7 +204,8 @@ public class PythonPlugin extends ProgramPlugin
PythonCodeCompletionFactory.setupOptions(this, options);
}
else {
inputThread.dispose();
inputThread.shutdown();
inputThread = null;
interpreter.cleanup();
interpreter = GhidraPythonInterpreter.get();
}
@@ -278,7 +281,7 @@ public class PythonPlugin extends ProgramPlugin
// Terminate the input thread
if (inputThread != null) {
inputThread.dispose();
inputThread.shutdown();
inputThread = null;
}

View File

@@ -28,10 +28,11 @@ class PythonPluginInputThread extends Thread {
private static int generationCount = 0;
private PythonPlugin plugin;
private final PythonPlugin plugin;
private final AtomicBoolean moreInputWanted = new AtomicBoolean(false);
private final AtomicBoolean shutdownRequested = new AtomicBoolean(false);
private final InputStream consoleStdin;
private PythonPluginExecutionThread pythonExecutionThread;
private AtomicBoolean moreInputWanted;
private AtomicBoolean shouldContinue;
/**
* Creates a new python input thread that gets a line of python input from the given plugin.
@@ -41,8 +42,7 @@ class PythonPluginInputThread extends Thread {
PythonPluginInputThread(PythonPlugin plugin) {
super("Python plugin input thread (generation " + ++generationCount + ")");
this.plugin = plugin;
this.moreInputWanted = new AtomicBoolean(false);
this.shouldContinue = new AtomicBoolean(true);
this.consoleStdin = plugin.getConsole().getStdin();
}
/**
@@ -56,28 +56,13 @@ class PythonPluginInputThread extends Thread {
@Override
public void run() {
try (BufferedReader reader =
new BufferedReader(new InputStreamReader(plugin.getConsole().getStdin()))) {
while (shouldContinue.get()) {
// Read a line from the console. Do it non-blocking so we can exit the thread
// if we were instructed to not continue.
String line;
if (plugin.getConsole().getStdin().available() > 0) {
line = reader.readLine();
}
else {
try {
Thread.sleep(50);
}
catch (InterruptedException e) {
// Nothing to do...just continue.
}
continue;
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(consoleStdin))) {
String line;
while (!shutdownRequested.get() && (line = reader.readLine()) != null) {
// Execute the line in a new thread
pythonExecutionThread = new PythonPluginExecutionThread(plugin, line, moreInputWanted);
pythonExecutionThread =
new PythonPluginExecutionThread(plugin, line, moreInputWanted);
pythonExecutionThread.start();
try {
@@ -90,9 +75,10 @@ class PythonPluginInputThread extends Thread {
}
// Set the prompt appropriately
plugin.getConsole().setPrompt(
moreInputWanted.get() ? plugin.getInterpreter().getSecondaryPrompt()
: plugin.getInterpreter().getPrimaryPrompt());
plugin.getConsole()
.setPrompt(
moreInputWanted.get() ? plugin.getInterpreter().getSecondaryPrompt()
: plugin.getInterpreter().getPrimaryPrompt());
}
}
catch (IOException e) {
@@ -103,9 +89,17 @@ class PythonPluginInputThread extends Thread {
}
/**
* Disposes of the thread by telling it to not continue asking for input.
* Causes the the background thread's run() loop to exit.
* <p>
* Causes background thread's exit by closing the inputstream it is looping on.
*/
void dispose() {
shouldContinue.set(false);
void shutdown() {
try {
shutdownRequested.set(true);
consoleStdin.close();
}
catch (IOException e) {
// shouldn't happen, ignore
}
}
}