mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
terminal.c's from_backend() no longer calls term_out(), because
term_out() can in turn call ldisc_send() which calls back to from_backend() when local echo is enabled. This was giving rise to crazy re-entrancy stuff and stack overflows. Instead from_backend() deposits its data in a bufchain which term_out() empties the next time it's called. [originally from svn r1276]
This commit is contained in:
parent
8c532d7668
commit
6364ff3e71
9
putty.h
9
putty.h
@ -93,15 +93,6 @@ typedef HDC Context;
|
|||||||
|
|
||||||
GLOBAL int rows, cols, savelines;
|
GLOBAL int rows, cols, savelines;
|
||||||
|
|
||||||
#define INBUF_SIZE 2048
|
|
||||||
GLOBAL unsigned char inbuf[INBUF_SIZE];
|
|
||||||
GLOBAL int inbuf_head;
|
|
||||||
|
|
||||||
#define OUTBUF_SIZE 2048
|
|
||||||
#define OUTBUF_MASK (OUTBUF_SIZE-1)
|
|
||||||
GLOBAL unsigned char outbuf[OUTBUF_SIZE];
|
|
||||||
GLOBAL int outbuf_head, outbuf_reap;
|
|
||||||
|
|
||||||
GLOBAL int has_focus;
|
GLOBAL int has_focus;
|
||||||
|
|
||||||
GLOBAL int in_vbell;
|
GLOBAL int in_vbell;
|
||||||
|
2
scp.c
2
scp.c
@ -375,8 +375,6 @@ int from_backend(int is_stderr, char *data, int datalen)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inbuf_head = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is before the real session begins, just return.
|
* If this is before the real session begins, just return.
|
||||||
*/
|
*/
|
||||||
|
63
terminal.c
63
terminal.c
@ -86,6 +86,7 @@ typedef struct {
|
|||||||
#define incpos(p) ( (p).x == cols ? ((p).x = 0, (p).y++, 1) : ((p).x++, 0) )
|
#define incpos(p) ( (p).x == cols ? ((p).x = 0, (p).y++, 1) : ((p).x++, 0) )
|
||||||
#define decpos(p) ( (p).x == 0 ? ((p).x = cols, (p).y--, 1) : ((p).x--, 0) )
|
#define decpos(p) ( (p).x == 0 ? ((p).x = cols, (p).y--, 1) : ((p).x--, 0) )
|
||||||
|
|
||||||
|
static bufchain inbuf; /* terminal input buffer */
|
||||||
static pos curs; /* cursor */
|
static pos curs; /* cursor */
|
||||||
static pos savecurs; /* saved cursor position */
|
static pos savecurs; /* saved cursor position */
|
||||||
static int marg_t, marg_b; /* scroll margins */
|
static int marg_t, marg_b; /* scroll margins */
|
||||||
@ -973,20 +974,38 @@ static void do_osc(void)
|
|||||||
*/
|
*/
|
||||||
void term_out(void)
|
void term_out(void)
|
||||||
{
|
{
|
||||||
int c, inbuf_reap;
|
int c, unget;
|
||||||
|
unsigned char localbuf[256], *chars;
|
||||||
|
int nchars = 0;
|
||||||
|
|
||||||
/*
|
unget = -1;
|
||||||
* Optionally log the session traffic to a file. Useful for
|
|
||||||
* debugging and possibly also useful for actual logging.
|
while (nchars > 0 || bufchain_size(&inbuf) > 0) {
|
||||||
*/
|
if (unget == -1) {
|
||||||
if (cfg.logtype == LGTYP_DEBUG)
|
if (nchars == 0) {
|
||||||
for (inbuf_reap = 0; inbuf_reap < inbuf_head; inbuf_reap++) {
|
void *ret;
|
||||||
logtraffic((unsigned char) inbuf[inbuf_reap], LGTYP_DEBUG);
|
bufchain_prefix(&inbuf, &ret, &nchars);
|
||||||
|
if (nchars > sizeof(localbuf))
|
||||||
|
nchars = sizeof(localbuf);
|
||||||
|
memcpy(localbuf, ret, nchars);
|
||||||
|
bufchain_consume(&inbuf, nchars);
|
||||||
|
chars = localbuf;
|
||||||
|
assert(chars != NULL);
|
||||||
|
}
|
||||||
|
c = *chars++;
|
||||||
|
nchars--;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Optionally log the session traffic to a file. Useful for
|
||||||
|
* debugging and possibly also useful for actual logging.
|
||||||
|
*/
|
||||||
|
if (cfg.logtype == LGTYP_DEBUG)
|
||||||
|
logtraffic((unsigned char) &c, LGTYP_DEBUG);
|
||||||
|
} else {
|
||||||
|
c = unget;
|
||||||
|
unget = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (inbuf_reap = 0; inbuf_reap < inbuf_head; inbuf_reap++) {
|
|
||||||
c = inbuf[inbuf_reap];
|
|
||||||
|
|
||||||
/* Note only VT220+ are 8-bit VT102 is seven bit, it shouldn't even
|
/* Note only VT220+ are 8-bit VT102 is seven bit, it shouldn't even
|
||||||
* be able to display 8-bit characters, but I'll let that go 'cause
|
* be able to display 8-bit characters, but I'll let that go 'cause
|
||||||
* of i18n.
|
* of i18n.
|
||||||
@ -1029,7 +1048,7 @@ void term_out(void)
|
|||||||
case 4:
|
case 4:
|
||||||
case 5:
|
case 5:
|
||||||
if ((c & 0xC0) != 0x80) {
|
if ((c & 0xC0) != 0x80) {
|
||||||
inbuf_reap--;
|
unget = c;
|
||||||
c = UCSERR;
|
c = UCSERR;
|
||||||
utf_state = 0;
|
utf_state = 0;
|
||||||
break;
|
break;
|
||||||
@ -2480,7 +2499,6 @@ void term_out(void)
|
|||||||
check_selection(curs, cursplus);
|
check_selection(curs, cursplus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inbuf_head = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -3358,18 +3376,15 @@ int term_ldisc(int option)
|
|||||||
*/
|
*/
|
||||||
int from_backend(int is_stderr, char *data, int len)
|
int from_backend(int is_stderr, char *data, int len)
|
||||||
{
|
{
|
||||||
while (len--) {
|
bufchain_add(&inbuf, data, len);
|
||||||
if (inbuf_head >= INBUF_SIZE)
|
|
||||||
term_out();
|
|
||||||
inbuf[inbuf_head++] = *data++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We process all stdout/stderr data immediately we receive it,
|
* term_out() always completely empties inbuf. Therefore,
|
||||||
* and don't return until it's all gone. Therefore, there's no
|
* there's no reason at all to return anything other than zero
|
||||||
* reason at all to return anything other than zero from this
|
* from this function, because there _can't_ be a question of
|
||||||
* function.
|
* the remote side needing to wait until term_out() has cleared
|
||||||
*
|
* a backlog.
|
||||||
|
*
|
||||||
* This is a slightly suboptimal way to deal with SSH2 - in
|
* This is a slightly suboptimal way to deal with SSH2 - in
|
||||||
* principle, the window mechanism would allow us to continue
|
* principle, the window mechanism would allow us to continue
|
||||||
* to accept data on forwarded ports and X connections even
|
* to accept data on forwarded ports and X connections even
|
||||||
@ -3379,7 +3394,7 @@ int from_backend(int is_stderr, char *data, int len)
|
|||||||
* portability. So we manage stdout buffering the old SSH1 way:
|
* portability. So we manage stdout buffering the old SSH1 way:
|
||||||
* if the terminal processing goes slowly, the whole SSH
|
* if the terminal processing goes slowly, the whole SSH
|
||||||
* connection stops accepting data until it's ready.
|
* connection stops accepting data until it's ready.
|
||||||
*
|
*
|
||||||
* In practice, I can't imagine this causing serious trouble.
|
* In practice, I can't imagine this causing serious trouble.
|
||||||
*/
|
*/
|
||||||
return 0;
|
return 0;
|
||||||
|
12
window.c
12
window.c
@ -525,12 +525,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
|
|
||||||
session_closed = FALSE;
|
session_closed = FALSE;
|
||||||
|
|
||||||
/*
|
|
||||||
* Set up the input and output buffers.
|
|
||||||
*/
|
|
||||||
inbuf_head = 0;
|
|
||||||
outbuf_reap = outbuf_head = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare the mouse handler.
|
* Prepare the mouse handler.
|
||||||
*/
|
*/
|
||||||
@ -660,8 +654,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
timer_id = 0;
|
timer_id = 0;
|
||||||
}
|
}
|
||||||
HideCaret(hwnd);
|
HideCaret(hwnd);
|
||||||
if (inbuf_head)
|
term_out();
|
||||||
term_out();
|
|
||||||
term_update();
|
term_update();
|
||||||
ShowCaret(hwnd);
|
ShowCaret(hwnd);
|
||||||
|
|
||||||
@ -1392,8 +1385,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
|||||||
case WM_TIMER:
|
case WM_TIMER:
|
||||||
if (pending_netevent)
|
if (pending_netevent)
|
||||||
enact_pending_netevent();
|
enact_pending_netevent();
|
||||||
if (inbuf_head)
|
term_out();
|
||||||
term_out();
|
|
||||||
noise_regular();
|
noise_regular();
|
||||||
HideCaret(hwnd);
|
HideCaret(hwnd);
|
||||||
term_update();
|
term_update();
|
||||||
|
Loading…
Reference in New Issue
Block a user