From 4a92b56b21aedd59eba10bfe67c863da54968786 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 23 Jan 2012 20:56:44 +0000 Subject: patch-3477449: segfault when mark out of -startline/-endline range --- ChangeLog | 6 ++++++ generic/tkText.c | 32 +++++++++++++++++++++++++++++--- generic/tkTextMark.c | 25 +++++++++++++++++++++++++ tests/textMark.test | 41 ++++++++++++++++++++++++++++++++++++++--- 4 files changed, 98 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index c501e63..6c9b7aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-01-?? Francois Vogel + + * generic/tkText.c: [Bug-1630271]: segfault/infinite loop + * generic/tkTextMark.c: when a mark is before -startline + * tests/textMark.test: + 2012-01-22 Francois Vogel * generic/tkTextMark.c: [Bug-3288113,3288121]: Missing marks/endless diff --git a/generic/tkText.c b/generic/tkText.c index d4bc065..d050170 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -2022,6 +2022,7 @@ ConfigureText( if (mask & TK_TEXT_LINE_RANGE) { int start, end, current; + TkTextIndex index1, index2, index3; /* * Line start and/or end have been adjusted. We need to validate the @@ -2048,13 +2049,15 @@ ConfigureText( return TCL_ERROR; } current = TkBTreeLinesTo(NULL, textPtr->topIndex.linePtr); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, NULL, start, 0, + &index1); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, NULL, end, 0, + &index2); if (current < start || current > end) { TkTextSearch search; - TkTextIndex index1, first, last; + TkTextIndex first, last; int selChanged = 0; - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, NULL, start, 0, - &index1); TkTextSetYView(textPtr, &index1, 0); /* @@ -2098,6 +2101,29 @@ ConfigureText( textPtr->abortSelections = 1; } } + + /* Indices are potentially obsolete after changing -startline and/or + * -endline, therefore increase the epoch. + * Also, clamp the insert and current (unshared) marks to the new + * -startline/-endline range limits of the widget. All other (shared) + * marks are unchanged. + */ + + textPtr->sharedTextPtr->stateEpoch++; + TkTextMarkNameToIndex(textPtr, "insert", &index3); + if (TkTextIndexCmp(&index3, &index1) < 0) { + textPtr->insertMarkPtr = TkTextSetMark(textPtr, "insert", &index1); + } + if (TkTextIndexCmp(&index3, &index2) > 0) { + textPtr->insertMarkPtr = TkTextSetMark(textPtr, "insert", &index2); + } + TkTextMarkNameToIndex(textPtr, "current", &index3); + if (TkTextIndexCmp(&index3, &index1) < 0) { + textPtr->currentMarkPtr = TkTextSetMark(textPtr, "current", &index1); + } + if (TkTextIndexCmp(&index3, &index2) > 0) { + textPtr->currentMarkPtr = TkTextSetMark(textPtr, "current", &index2); + } } /* diff --git a/generic/tkTextMark.c b/generic/tkTextMark.c index 55edb46..0e51e33 100644 --- a/generic/tkTextMark.c +++ b/generic/tkTextMark.c @@ -402,6 +402,8 @@ TkTextMarkNameToIndex( TkTextIndex *indexPtr) /* Index information gets stored here. */ { TkTextSegment *segPtr; + TkTextIndex index; + int start, end; if (textPtr == NULL) { return TCL_ERROR; @@ -420,6 +422,29 @@ TkTextMarkNameToIndex( segPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr); } TkTextMarkSegToIndex(textPtr, segPtr, indexPtr); + + /* If indexPtr refers to somewhere outside the -startline/-endline + * range limits of the widget, error out since the mark indeed is not + * reachable from this text widget (it may be reachable from a peer) + * (bug 1630271). + */ + + if (textPtr->start != NULL) { + start = TkBTreeLinesTo(NULL, textPtr->start); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, NULL, start, 0, + &index); + if (TkTextIndexCmp(indexPtr, &index) < 0) { + return TCL_ERROR; + } + } + if (textPtr->end != NULL) { + end = TkBTreeLinesTo(NULL, textPtr->end); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, NULL, end, 0, + &index); + if (TkTextIndexCmp(indexPtr, &index) > 0) { + return TCL_ERROR; + } + } return TCL_OK; } diff --git a/tests/textMark.test b/tests/textMark.test index 174f674..5faaabd 100644 --- a/tests/textMark.test +++ b/tests/textMark.test @@ -9,6 +9,7 @@ package require tcltest 2.1 eval tcltest::configure $argv tcltest::loadTestedCommands +#namespace import -force tcltest::test catch {destroy .t} text .t -width 20 -height 10 @@ -136,6 +137,40 @@ test textMark-6.1 {TkTextMarkSegToIndex} haveCourier12 { .t mark set d 1.4 list [.t index a] [.t index b] [.t index c ] [.t index d] } {1.2 1.2 1.2 1.4} +test textMark-6.2 {TkTextMarkNameToIndex, with mark outside -startline/-endline range - bug 1630271} -body { + .t mark set insert 1.0 + .t configure -startline 2 + set res [list [.t index insert] [.t index insert-1c] [.t get insert]] + .t mark set insert end + .t configure -endline 4 + lappend res [.t index insert] +} -cleanup { + .t configure -startline {} -endline {} +} -result {1.0 1.0 a 2.5} +test textMark-6.3 {TkTextMarkNameToIndex, with mark outside -startline/-endline range - bug 1630271} -body { + .t mark set mymark 1.0 + .t configure -startline 2 + list [catch {.t index mymark} msg] $msg +} -cleanup { + .t configure -startline {} -endline {} + .t mark unset mymark +} -result {1 {bad text index "mymark"}} +test textMark-6.4 {TkTextMarkNameToIndex, with mark outside -startline/-endline range - bug 1630271} -body { + .t mark set mymark 1.0 + .t configure -startline 2 + set res [list [catch {.t index mymark} msg] $msg] + lappend res [.pt index mymark] + .t configure -startline {} + .pt configure -startline 4 + lappend res [.t index mymark] + lappend res [catch {.pt index mymark} msg] $msg + lappend res [.t get mymark] + lappend res [catch {.pt get mymark} msg] $msg +} -cleanup { + .t configure -startline {} -endline {} + .pt configure -startline {} -endline {} + .t mark unset mymark +} -result {1 {bad text index "mymark"} 1.0 1.0 1 {bad text index "mymark"} L 1 {bad text index "mymark"}} catch {eval {.t mark unset} [.t mark names]} test textMark-7.1 {MarkFindNext - invalid mark name} haveCourier12 { @@ -180,8 +215,8 @@ test textMark-7.9 {MarkFindNext - mark set in a text widget and retrieved from a .t mark unset {*}[.t mark names] } -body { .t mark set mymark 1.0 - set res [list [.pt mark next 1.0] [.pt mark next mymark] [.pt mark next insert]] -} -result {mymark insert current} + lsort [list [.pt mark next 1.0] [.pt mark next mymark] [.pt mark next insert]] +} -result {current insert mymark} test textMark-8.1 {MarkFindPrev - invalid mark name} -constraints haveCourier12 -setup { .t mark unset {*}[.t mark names] @@ -242,7 +277,7 @@ test textMark-8.9 {MarkFindPrev - mark set in a text widget and retrieved from a .t mark unset {*}[.t mark names] } -body { .t mark set mymark 1.0 - set res [list [.pt mark prev end] [.pt mark prev current] [.pt mark prev insert]] + lsort [list [.pt mark prev end] [.pt mark prev current] [.pt mark prev insert]] } -result {current insert mymark} catch {destroy .t} -- cgit v0.12