Revision: 10354 https://osdn.net/projects/ttssh2/scm/svn/commits/10354 Author: zmatsuo Date: 2022-11-09 23:13:52 +0900 (Wed, 09 Nov 2022) Log Message: ----------- ランダムデータを表示させるとクラッシュする - `cat /dev/urandom` でテスト - 制御文字(C0,C1)はバッファに入れないようにした - 全角文字に上書き時にバッファ外へアクセスしていた - バッファ上で文字のコピーを行ったとき結合などで長くなった文字のコピーを行っていなかった - バッファの開放(free())が重複して行われてしまう原因になっていた - 代替画面バッファを使用した際メモリリークが発生していた - 全角より大きな文字の扱い(TODO) - 全角(=2cellの文字)より大きな文字(3cell以上)が現れることがある - 現在3cell以上の文字の扱いをケアしていない - IsBuffFullWidth(), AttrKanji など ticket #45763 Ticket Links: ------------ https://osdn.net/projects/ttssh2/tracker/detail/45763 Modified Paths: -------------- trunk/teraterm/teraterm/buffer.c -------------- next part -------------- Modified: trunk/teraterm/teraterm/buffer.c =================================================================== --- trunk/teraterm/teraterm/buffer.c 2022-11-06 15:35:13 UTC (rev 10353) +++ trunk/teraterm/teraterm/buffer.c 2022-11-09 14:13:52 UTC (rev 10354) @@ -49,6 +49,8 @@ #include "asprintf.h" #include "ttcstd.h" +#define ENABLE_CELL_INDEX 0 + // \x83o\x83b\x83t\x83@\x93\xE0\x82̔\xBC\x8Ap1\x95\xB6\x8E\x9A\x95\xAA\x82̏\xEE\x95\xF1 typedef struct { char32_t u32; @@ -70,6 +72,9 @@ unsigned char attr; unsigned char attr2; unsigned short ansi_char; +#if ENABLE_CELL_INDEX + int idx; // \x83Z\x83\x8B\x92ʂ\xB5\x94ԍ\x86 +#endif } buff_char_t; #define BuffXMax TermWidthMax @@ -79,7 +84,7 @@ #define BuffYMax 500000 #define BuffSizeMax (BuffYMax * 80) -// 1\x95\xB6\x8E\x9A\x82\xA0\x82\xBD\x82\xE8\x82̗̈\xE6\x8Dő\xE5\x83T\x83C\x83Y +// 1\x95\xB6\x8E\x9A\x82\xA0\x82\xBD\x82\xE8\x82̃R\x83\x93\x83r\x83l\x81[\x83V\x83\x87\x83\x93\x83o\x83b\x83t\x83@\x8Dő\xE5\x83T\x83C\x83Y #define MAX_CHAR_SIZE 100 // status line @@ -123,22 +128,90 @@ static void BuffDrawLineI(int DrawX, int DrawY, int SY, int IStart, int IEnd); static void BuffDrawLineIPrn(int SY, int IStart, int IEnd); +/** + * buff_char_t \x82\xF0 rel\x83Z\x83\x8B\x88ړ\xAE\x82\xB7\x82\xE9 + * + * @param CodeBuffW_ \x95\xB6\x8E\x9A\x83o\x83b\x83t\x83@\x82̐擪\x83|\x83C\x83\x93\x83^ + * @param BufferSize_ \x95\xB6\x8E\x9A\x83o\x83b\x83t\x83@\x82̃T\x83C\x83Y(buff_char_t\x92P\x88\xCA) + * @param p \x88ړ\xAE\x82\xB3\x82\xB9\x82\xE9\x83|\x83C\x83\x93\x83^ + * @param rel \x88ړ\xAE\x97\xCA + * @retval \x88ړ\xAE\x8C\xE3\x82̃|\x83C\x83\x93\x83^ + */ +static buff_char_t *GetPtrRel(buff_char_t *CodeBuffW_, size_t BufferSize_, buff_char_t *p, int rel) +{ + ptrdiff_t idx = (ptrdiff_t)(p - CodeBuffW_) + rel; + for (;;) { + if (idx < 0) { + idx += BufferSize_; + } + else if (idx >= (ptrdiff_t)BufferSize_) { + idx -= BufferSize_; + } + else { + break; + } + } + p = &CodeBuffW_[(int)idx]; + return p; +} + +static void FreeCombinationBuf(buff_char_t *b) +{ + if (b->pCombinationChars16 != NULL) { + free(b->pCombinationChars16); + b->pCombinationChars16 = NULL; + } + b->CombinationCharSize16 = 0; + b->CombinationCharCount16 = 0; + + if (b->pCombinationChars32 != NULL) { + free(b->pCombinationChars32); + b->pCombinationChars32 = NULL; + } + b->CombinationCharSize32 = 0; + b->CombinationCharCount32 = 0; +} + +static void DupCombinationBuf(buff_char_t *b) +{ + size_t size; + + size = b->CombinationCharSize16; + if (size > 0) { + wchar_t *new_buf = malloc(sizeof(wchar_t) * size); + memcpy(new_buf, b->pCombinationChars16, sizeof(wchar_t) * size); + b->pCombinationChars16 = new_buf; + } + size = b->CombinationCharSize32; + if (size > 0) { + char32_t *new_buf = malloc(sizeof(char32_t) * size); + memcpy(new_buf, b->pCombinationChars32, sizeof(char32_t) * size); + b->pCombinationChars32 = new_buf; + } +} + +static void CopyCombinationBuf(buff_char_t *dest, const buff_char_t *src) +{ + FreeCombinationBuf(dest); + + // \x8D\\x91\xA2\x91̂\xF0\x83R\x83s\x81[\x82\xB7\x82\xE9 +#if ENABLE_CELL_INDEX + int idx = dest->idx; +#endif + *dest = *src; +#if ENABLE_CELL_INDEX + dest->idx = idx; +#endif + + DupCombinationBuf(dest); +} + static void BuffSetChar2(buff_char_t *buff, char32_t u32, char property, BOOL half_width, char emoji) { size_t wstr_len; buff_char_t *p = buff; - if (p->pCombinationChars16 != NULL) { - free(p->pCombinationChars16); - p->pCombinationChars16 = NULL; - } - p->CombinationCharCount16 = 0; - p->CombinationCharSize16 = 0; - if (p->pCombinationChars32 != NULL) { - free(p->pCombinationChars32); - p->pCombinationChars32 = NULL; - } - p->CombinationCharCount32 = 0; - p->CombinationCharSize32 = 0; + + FreeCombinationBuf(p); p->WidthProperty = property; p->cell = half_width ? 1 : 2; p->u32 = u32; @@ -261,26 +334,19 @@ } } -// TODO: \x83\x8A\x81[\x83N\x94\xAD\x90\xB6 static void memcpyW(buff_char_t *dest, const buff_char_t *src, size_t count) { size_t i; - memcpy(dest, src, count * sizeof(buff_char_t)); - for (i=0; i<count; i++) { - buff_char_t *p = &dest[i]; - size_t size = p->CombinationCharSize16; - if (size > 0) { - wchar_t *new_buf = malloc(sizeof(wchar_t) * size); - memcpy(new_buf, p->pCombinationChars16, sizeof(wchar_t) * size); - p->pCombinationChars16 = new_buf; - } - size = p->CombinationCharSize32; - if (size > 0) { - char32_t *new_buf = malloc(sizeof(char32_t) * size); - memcpy(new_buf, p->pCombinationChars32, sizeof(char32_t) * size); - p->pCombinationChars32 = new_buf; - } + + if (dest == src || count == 0) { + return; } + + for (i = 0; i < count; i++) { + CopyCombinationBuf(dest, src); + dest++; + src++; + } } static void memsetW(buff_char_t *dest, wchar_t ch, unsigned char fg, unsigned char bg, unsigned char attr, unsigned char attr2, size_t count) @@ -298,7 +364,27 @@ static void memmoveW(buff_char_t *dest, const buff_char_t *src, size_t count) { - memmove(dest, src, count * sizeof(buff_char_t)); + size_t i; + + if (dest == src || count == 0) { + return; + } + + + if (dest < src) { + // \x91O\x82\xA9\x82\xE7\x83R\x83s\x81[\x82\xB7\x82\xE9? -> memcpyW() \x82\xC5ok + memcpyW(dest, src, count); + } + else { + // \x8C\xE3\x82납\x82\xE7\x83R\x83s\x81[\x82\xB7\x82\xE9 + dest += count - 1; + src += count - 1; + for (i = 0; i < count; i++) { + CopyCombinationBuf(dest, src); + dest--; + src--; + } + } } static BOOL IsBuffPadding(const buff_char_t *b) @@ -395,6 +481,14 @@ } memset(&CodeDestW[0], 0, NewSize * sizeof(buff_char_t)); +#if ENABLE_CELL_INDEX + { + int i; + for (i = 0; i < NewSize; i++) { + CodeDestW[i].idx = i; + } + } +#endif memsetW(&CodeDestW[0], 0x20, AttrDefaultFG, AttrDefaultBG, AttrDefault, AttrDefault, NewSize); if ( CodeBuffW != NULL ) { if ( NumOfColumns > Nx ) { @@ -545,25 +639,14 @@ } } -static void FreeCombinationBuffer(void) +void FreeBuffer(void) { int i; + for (i = 0; i < NumOfColumns * NumOfLinesInBuff; i++) { - buff_char_t *b = &CodeBuffW[i]; - if (b->pCombinationChars16 != NULL) { - free(b->pCombinationChars16); - b->pCombinationChars16 = NULL; - } - if (b->pCombinationChars32 != NULL) { - free(b->pCombinationChars32); - b->pCombinationChars32 = NULL; - } + FreeCombinationBuf(&CodeBuffW[i]); } -} -void FreeBuffer(void) -{ - FreeCombinationBuffer(); BuffLock = 1; UnlockBuffer(); if (CodeBuffW != NULL) { @@ -2674,8 +2757,8 @@ static buff_char_t *IsCombiningChar(int x, int y, BOOL wrap, unsigned int u32, int *combine) { buff_char_t *p = NULL; // NULL\x82̂Ƃ\xAB\x81A\x91O\x82̕\xB6\x8E\x9A\x82͂Ȃ\xA2 - LONG LinePtr = GetLinePtr(PageStart+y); - buff_char_t *CodeLineW = &CodeBuffW[LinePtr]; + LONG LinePtr_ = GetLinePtr(PageStart+y); + buff_char_t *CodeLineW = &CodeBuffW[LinePtr_]; int combine_type; // 0 or 1 or 2 combine_type = (u32 == 0x200d) ? 1 : 0; // U+200d = \x83[\x83\x8D\x95\x9D\x90ڍ\x87\x8Eq,ZERO WIDTH JOINER(ZWJ) @@ -2700,7 +2783,7 @@ } else { // padding\x82ł͂Ȃ\xA2\x83Z\x83\x8B\x82\xF0\x92T\x82\xB7 - x = LeftHalfOfDBCS(LinePtr, x - 1); // 1cell\x91O\x82\xA9\x82璲\x82ׂ\xE9 + x = LeftHalfOfDBCS(LinePtr_, x - 1); // 1cell\x91O\x82\xA9\x82璲\x82ׂ\xE9 if (!IsBuffPadding(&CodeLineW[x])) { p = &CodeLineW[x]; } @@ -2817,6 +2900,12 @@ OutputDebugPrintfW(L"BuffPutUnicode(U+%06x,(%d,%d)\n", u32, CursorX, CursorY); #endif + if (u32 < 0x20 || (0x80 <= u32 && u32 <= 0x9f)) { + // C0/C1 Controls \x82͕\xB6\x8E\x9A\x82Ƃ\xB5\x82ď\x88\x97\x9D\x82\xB5\x82Ȃ\xA2 + //assert(FALSE); // \x93\xFC\x82\xC1\x82Ă\xAD\x82\xE9\x82̂͂\xA8\x82\xA9\x82\xB5\x82\xA2 + return 0; + } + if (ts.EnableContinuedLineCopy && CursorX == 0 && (CodeLineW[0].attr & AttrLineContinued)) { Attr.Attr |= AttrLineContinued; } @@ -2826,11 +2915,13 @@ p = IsCombiningChar(CursorX, CursorY, Wrap, u32, &combining_type); if (p != NULL || combining_type != 0) { // \x8C\x8B\x8D\x87\x82\xB7\x82\xE9 + BOOL add_base_char = FALSE; move_x = 0; // \x83J\x81[\x83\\x83\x8B\x88ړ\xAE\x97\xCA=0 if (p == NULL) { // \x91O\x82̂\xE0\x82\xB6(\x8A\xEE\x92ꕶ\x8E\x9A)\x82\xAA\x82Ȃ\xA2\x82̂Ɍ\x8B\x8D\x87\x95\xB6\x8E\x9A\x82\xAA\x8Fo\x82Ă\xAB\x82\xBD\x82Ƃ\xAB // NBSP(non-breaking space) U+00A0 \x82Ɍ\x8B\x8D\x87\x82\xB3\x82\xB9\x82\xE9 + add_base_char = TRUE; p = &CodeLineW[CursorX]; BuffSetChar(p, 0xa0, 'H'); @@ -2861,14 +2952,18 @@ } // \x83J\x81[\x83\\x83\x8B\x88ʒu\x82̕\xB6\x8E\x9A\x82\xCD Padding\x82ɂ\xB7\x82\xE9 - // \x82\xBD\x82\xBE\x82\xB5\x8Ds\x96\x96\x82̂Ƃ\xAB\x82\xCDPadding\x82\xF0\x93\xFC\x82\xEA\x82Ȃ\xA2 + // \x82\xBD\x82\xBE\x82\xB5\x8E\x9F\x82̎\x9E\x82\xCD Padding \x82\xF0\x93\xFC\x82\xEA\x82Ȃ\xA2 + // - \x8Ds\x96\x96\x82̂Ƃ\xAB (TODO \x82\xB1\x82̏\xF0\x8C\x8F\x82͕s\x97v?) + // - \x8A\xEE\x92ꕶ\x8E\x9A\x82\xAA\x82\xA0\x82\xE9\x8F\xF3\x91ԂŁASpacing Mark\x95\xB6\x8E\x9A(\x83J\x81[\x83\\x83\x8B\x82\xAA+1\x88ړ\xAE\x82\xB7\x82錋\x8D\x87\x95\xB6\x8E\x9A)\x82\xAA\x93\xFC\x97͂\xB3\x82ꂽ\x82Ƃ\xAB if (CursorX < NumOfColumns - 1) { - BuffSetChar(&CodeLineW[CursorX], 0, 'H'); - CodeLineW[CursorX].Padding = TRUE; - CodeLineW[CursorX].attr = Attr.Attr; - CodeLineW[CursorX].attr2 = Attr.Attr2; - CodeLineW[CursorX].fg = Attr.Fore; - CodeLineW[CursorX].bg = Attr.Back; + if (add_base_char == FALSE) { + BuffSetChar(&CodeLineW[CursorX], 0, 'H'); + CodeLineW[CursorX].Padding = TRUE; + CodeLineW[CursorX].attr = Attr.Attr; + CodeLineW[CursorX].attr2 = Attr.Attr2; + CodeLineW[CursorX].fg = Attr.Fore; + CodeLineW[CursorX].bg = Attr.Back; + } } } @@ -2934,10 +3029,11 @@ } // \x8C\xBB\x8D݂̈ʒu\x82\xAA\x91S\x8Ap\x82̍\xB6\x91\xA4 && \x93\xFC\x97͕\xB6\x8E\x9A\x82\xAA\x94\xBC\x8Ap ? if (half_width && IsBuffFullWidth(p)) { - // \x91S\x8Ap\x82\xF0\x83X\x83y\x81[\x83X\x82ɒu\x82\xAB\x8A\xB7\x82\xA6\x82\xE9 - assert(CursorX < NumOfColumns - 1); // \x8Ds\x96\x96\x82ɑS\x8Ap\x82̍\xB6\x82͂\xB1\x82Ȃ\xA2 + // \x8Ds\x96\x96\x82ɑS\x8Ap(2cell)\x88ȏ\xE3\x82̕\xB6\x8E\x9A\x82\xAA\x91\xB6\x8D݂\xB7\x82\xE9\x89\\x90\xAB\x82\xAA\x82\xA0\x82\xE9 BuffSetChar(p, ' ', 'H'); - BuffSetChar(p + 1, ' ', 'H'); + if (CursorX < NumOfColumns - 1) { + BuffSetChar(p + 1, ' ', 'H'); + } if (StrChangeCount == 0) { StrChangeCount = 3; StrChangeStart = CursorX; @@ -2951,11 +3047,17 @@ } } } - // \x8E\x9F\x82̕\xB6\x8E\x9A\x82\xAA\x91S\x8Ap && \x93\xFC\x97͕\xB6\x8E\x9A\x82\xAA\x91S\x8Ap ? - if (!Insert && !half_width && IsBuffFullWidth(p + 1)) { - // \x91S\x8Ap\x82\xF0\x92ׂ\xB7 - BuffSetChar(p + 1, ' ', 'H'); - BuffSetChar(p + 2, ' ', 'H'); + + { + buff_char_t *p1 = GetPtrRel(CodeBuffW, BufferSize, p, 1); + + // \x8E\x9F\x82̕\xB6\x8E\x9A\x82\xAA\x91S\x8Ap && \x93\xFC\x97͕\xB6\x8E\x9A\x82\xAA\x91S\x8Ap ? + if (!Insert && !half_width && IsBuffFullWidth(p1)) { + // \x91S\x8Ap\x82\xF0\x92ׂ\xB7 + buff_char_t *p2 = GetPtrRel(CodeBuffW, BufferSize, p1, 1); + BuffSetChar(p1, ' ', 'H'); + BuffSetChar(p2, ' ', 'H'); + } } if (Insert) { @@ -3045,13 +3147,13 @@ else { if ((Attr.AttrEx & AttrPadding) != 0) { // \x8Bl\x82ߕ\xA8 - buff_char_t *p = &CodeLineW[CursorX]; - BuffSetChar(p, u32, 'H'); - p->Padding = TRUE; - CodeLineW[CursorX].attr = Attr.Attr; - CodeLineW[CursorX].attr2 = Attr.Attr2; - CodeLineW[CursorX].fg = Attr.Fore; - CodeLineW[CursorX].bg = Attr.Back; + buff_char_t *b = &CodeLineW[CursorX]; + BuffSetChar(b, u32, 'H'); + b->Padding = TRUE; + b->attr = Attr.Attr; + b->attr2 = Attr.Attr2; + b->fg = Attr.Fore; + b->bg = Attr.Back; move_x = 1; } else { @@ -3085,13 +3187,13 @@ if (!half_width) { // \x91S\x8Ap\x82̎\x9E\x82͎\x9F\x82̃Z\x83\x8B\x82͋l\x82ߕ\xA8 if (CursorX < NumOfColumns - 1) { - buff_char_t *p = &CodeLineW[CursorX + 1]; - BuffSetChar(p, 0, 'H'); - p->Padding = TRUE; - CodeLineW[CursorX + 1].attr = 0; - CodeLineW[CursorX + 1].attr2 = 0; - CodeLineW[CursorX + 1].fg = 0; - CodeLineW[CursorX + 1].bg = 0; + buff_char_t *b = &CodeLineW[CursorX + 1]; + BuffSetChar(b, 0, 'H'); + b->Padding = TRUE; + b->attr = 0; + b->attr2 = 0; + b->fg = 0; + b->bg = 0; } } } @@ -3264,7 +3366,7 @@ { unsigned short ansi_char = b->ansi_char; int i; - int cell = b->cell; + char cell = b->cell; int c = 0; if (ansi_char < 0x100) { bufA[lenA] = ansi_char & 0xff; @@ -4977,13 +5079,10 @@ DispSetCurCharAttr(Attr); } -// TODO void BuffSaveScreen(void) { - PCHAR CodeDest, AttrDest, AttrDest2, AttrDestFG, AttrDestBG; buff_char_t *CodeDestW; LONG ScrSize; - size_t AllocSize; LONG SrcPtr, DestPtr; int i; @@ -4990,15 +5089,9 @@ if (SaveBuff == NULL) { ScrSize = NumOfColumns * NumOfLines; // 1\x89\xE6\x96ʕ\xAA\x82̃o\x83b\x83t\x83@\x82̕ۑ\xB6\x90\x94 // \x91S\x89\xE6\x96ʕ\xAA\x82̃o\x83C\x83g\x90\x94 - AllocSize = ScrSize * (5+sizeof(buff_char_t)); - SaveBuff = malloc(AllocSize); + SaveBuff = calloc(sizeof(buff_char_t), ScrSize); if (SaveBuff != NULL) { - CodeDest = SaveBuff; - AttrDest = CodeDest + ScrSize; - AttrDest2 = AttrDest + ScrSize; - AttrDestFG = AttrDest2 + ScrSize; - AttrDestBG = AttrDestFG + ScrSize; - CodeDestW = (buff_char_t *)(AttrDestBG + ScrSize); + CodeDestW = (buff_char_t *)SaveBuff; SaveBuffX = NumOfColumns; SaveBuffY = NumOfLines; @@ -5018,41 +5111,17 @@ void BuffRestoreScreen(void) { - PCHAR CodeSrc, AttrSrc, AttrSrc2, AttrSrcFG, AttrSrcBG; buff_char_t *CodeSrcW; - LONG ScrSize; LONG SrcPtr, DestPtr; int i, CopyX, CopyY; _CrtCheckMemory(); if (SaveBuff != NULL) { - CodeSrc = SaveBuff; - ScrSize = SaveBuffX * SaveBuffY; + CodeSrcW = (buff_char_t*)SaveBuff; - AttrSrc = CodeSrc + ScrSize; - AttrSrc2 = AttrSrc + ScrSize; - AttrSrcFG = AttrSrc2 + ScrSize; - AttrSrcBG = AttrSrcFG + ScrSize; - CodeSrcW = (buff_char_t*)(AttrSrcBG + ScrSize); - CopyX = (SaveBuffX > NumOfColumns) ? NumOfColumns : SaveBuffX; CopyY = (SaveBuffY > NumOfLines) ? NumOfLines : SaveBuffY; - DestPtr = GetLinePtr(PageStart); - for (i=0; i<CopyY; i++) { - buff_char_t *p = &CodeBuffW[DestPtr]; - int j; - for (j=0; j<CopyX; j++) { - if (p->CombinationCharSize16 > 0) { - free(p->pCombinationChars16); - } - if (p->CombinationCharSize32 > 0) { - free(p->pCombinationChars32); - } - } - DestPtr = NextLinePtr(DestPtr); - } - SrcPtr = 0; DestPtr = GetLinePtr(PageStart); @@ -5067,8 +5136,7 @@ } BuffUpdateRect(WinOrgX,WinOrgY,WinOrgX+WinWidth-1,WinOrgY+WinHeight-1); - free(SaveBuff); - SaveBuff = NULL; + BuffDiscardSavedScreen(); } _CrtCheckMemory(); } @@ -5076,6 +5144,13 @@ void BuffDiscardSavedScreen(void) { if (SaveBuff != NULL) { + int i; + buff_char_t *b = (buff_char_t *)SaveBuff; + + for (i = 0; i < SaveBuffX * SaveBuffY; i++) { + FreeCombinationBuf(&b[i]); + } + free(SaveBuff); SaveBuff = NULL; }