Write escape codes to children atomically

Ensure a partial escape code is never written
This commit is contained in:
Kovid Goyal 2018-08-29 09:01:52 +05:30
parent d1a76bbcd9
commit 0e248b3faa
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 43 additions and 14 deletions

View File

@ -246,9 +246,18 @@ add_child(ChildMonitor *self, PyObject *args) {
}
bool
schedule_write_to_child(unsigned long id, const char *data, size_t sz) {
schedule_write_to_child(unsigned long id, unsigned int num, ...) {
ChildMonitor *self = the_monitor;
bool found = false;
const char *data;
size_t sz = 0;
va_list ap;
va_start(ap, num);
for (unsigned int i = 0; i < num; i++) {
data = va_arg(ap, const char*);
sz += va_arg(ap, size_t);
}
va_end(ap);
children_mutex(lock);
for (size_t i = 0; i < self->count; i++) {
if (children[i].id == id) {
@ -266,8 +275,14 @@ schedule_write_to_child(unsigned long id, const char *data, size_t sz) {
screen->write_buf = PyMem_RawRealloc(screen->write_buf, screen->write_buf_sz);
if (screen->write_buf == NULL) { fatal("Out of memory."); }
}
memcpy(screen->write_buf + screen->write_buf_used, data, sz);
screen->write_buf_used += sz;
va_start(ap, num);
for (unsigned int i = 0; i < num; i++) {
data = va_arg(ap, const char*);
size_t dsz = va_arg(ap, size_t);
memcpy(screen->write_buf + screen->write_buf_used, data, dsz);
screen->write_buf_used += dsz;
}
va_end(ap);
if (screen->write_buf_sz > BUFSIZ && screen->write_buf_used < BUFSIZ) {
screen->write_buf_sz = BUFSIZ;
screen->write_buf = PyMem_RawRealloc(screen->write_buf, screen->write_buf_sz);
@ -288,7 +303,7 @@ needs_write(ChildMonitor UNUSED *self, PyObject *args) {
unsigned long id, sz;
const char *data;
if (!PyArg_ParseTuple(args, "ks#", &id, &data, &sz)) return NULL;
if (schedule_write_to_child(id, data, sz)) { Py_RETURN_TRUE; }
if (schedule_write_to_child(id, 1, data, (size_t)sz)) { Py_RETURN_TRUE; }
Py_RETURN_FALSE;
}

View File

@ -271,7 +271,7 @@ const char* cursor_as_sgr(Cursor*, Cursor*);
double monotonic();
PyObject* cm_thread_write(PyObject *self, PyObject *args);
bool schedule_write_to_child(unsigned long id, const char *data, size_t sz);
bool schedule_write_to_child(unsigned long id, unsigned int num, ...);
bool set_iutf8(int, bool);
color_type colorprofile_to_color(ColorProfile *self, color_type entry, color_type defval);

View File

@ -80,12 +80,12 @@ send_key_to_child(Window *w, int key, int mods, int action) {
const char *data = key_to_bytes(key, screen->modes.mDECCKM, screen->modes.mEXTENDED_KEYBOARD, mods, action);
if (data) {
if (screen->modes.mEXTENDED_KEYBOARD) {
if (*data == 1) schedule_write_to_child(w->id, (data + 1), 1);
if (*data == 1) schedule_write_to_child(w->id, 1, (data + 1), 1);
else write_escape_code_to_child(screen, APC, data + 1);
} else {
if (*data > 2 && data[1] == 0x1b && data[2] == '[') { // CSI code
write_escape_code_to_child(screen, CSI, data + 3);
} else schedule_write_to_child(w->id, (data + 1), *data);
} else schedule_write_to_child(w->id, 1, (data + 1), *data);
}
}
}
@ -141,7 +141,7 @@ on_key_input(int key, int scancode, int action, int mods, const char* text, int
return;
case 2: // commit text
if (text && *text) {
schedule_write_to_child(w->id, text, strlen(text));
schedule_write_to_child(w->id, 1, text, strlen(text));
debug("committed pre-edit text: %s\n", text);
} else debug("committed pre-edit text: (null)\n");
return;
@ -184,7 +184,7 @@ on_key_input(int key, int scancode, int action, int mods, const char* text, int
bool ok_to_send = action == GLFW_PRESS || action == GLFW_REPEAT || screen->modes.mEXTENDED_KEYBOARD;
if (ok_to_send) {
if (has_text) {
schedule_write_to_child(w->id, text, strlen(text));
schedule_write_to_child(w->id, 1, text, strlen(text));
debug("sent text to child\n");
} else {
send_key_to_child(w, key, mods, action);

View File

@ -499,10 +499,15 @@ select_graphic_rendition(Screen *self, unsigned int *params, unsigned int count,
} else cursor_from_sgr(self->cursor, params, count);
}
static inline void
write_to_test_child(Screen *self, const char *data, size_t sz) {
PyObject *r = PyObject_CallMethod(self->test_child, "write", "y#", data, sz); if (r == NULL) PyErr_Print(); Py_CLEAR(r);
}
static inline void
write_to_child(Screen *self, const char *data, size_t sz) {
if (self->window_id) schedule_write_to_child(self->window_id, data, sz);
if (self->test_child != Py_None) { PyObject *r = PyObject_CallMethod(self->test_child, "write", "y#", data, sz); if (r == NULL) PyErr_Print(); Py_CLEAR(r); }
if (self->window_id) schedule_write_to_child(self->window_id, 1, data, sz);
if (self->test_child != Py_None) { write_to_test_child(self, data, sz); }
}
void
@ -527,9 +532,18 @@ write_escape_code_to_child(Screen *self, unsigned char which, const char *data)
default:
fatal("Unknown escape code to write: %u", which);
}
write_to_child(self, prefix, strlen(prefix));
write_to_child(self, data, strlen(data));
if (suffix[0]) write_to_child(self, suffix, strlen(suffix));
if (self->window_id) {
if (suffix[0]) {
schedule_write_to_child(self->window_id, 3, prefix, strlen(prefix), data, strlen(data), suffix, strlen(suffix));
} else {
schedule_write_to_child(self->window_id, 2, prefix, strlen(prefix), data, strlen(data));
}
}
if (self->test_child != Py_None) {
write_to_test_child(self, prefix, strlen(prefix));
write_to_test_child(self, data, strlen(data));
if (suffix[0]) write_to_test_child(self, suffix, strlen(suffix));
}
}
static inline bool