Race condition in cursor move.
The method WordComposer.moveCursorByAndReturnIfInsideComposingWord() iterates through all the code points in the word that's currently being composed, and it tries to adjust the cursor position by a given amount (left or right). It copies the code points to a new array while processing. But the code point count comes from a member variable. If the member variable changes while the method is processing the copy of the code points, it can run over the length of the code point array. Bug 18876474. Change-Id: Ib3a2d90a4e82b76d381efa774e6b3d6bca99c869
This commit is contained in:
parent
8472b36886
commit
69c04cadc7
1 changed files with 10 additions and 8 deletions
|
@ -232,31 +232,33 @@ public final class WordComposer {
|
||||||
* @return true if the cursor is still inside the composing word, false otherwise.
|
* @return true if the cursor is still inside the composing word, false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean moveCursorByAndReturnIfInsideComposingWord(final int expectedMoveAmount) {
|
public boolean moveCursorByAndReturnIfInsideComposingWord(final int expectedMoveAmount) {
|
||||||
int actualMoveAmountWithinWord = 0;
|
int actualMoveAmount = 0;
|
||||||
int cursorPos = mCursorPositionWithinWord;
|
int cursorPos = mCursorPositionWithinWord;
|
||||||
// TODO: Don't make that copy. We can do this directly from mTypedWordCache.
|
// TODO: Don't make that copy. We can do this directly from mTypedWordCache.
|
||||||
final int[] codePoints = StringUtils.toCodePointArray(mTypedWordCache);
|
final int[] codePoints = StringUtils.toCodePointArray(mTypedWordCache);
|
||||||
if (expectedMoveAmount >= 0) {
|
if (expectedMoveAmount >= 0) {
|
||||||
// Moving the cursor forward for the expected amount or until the end of the word has
|
// Moving the cursor forward for the expected amount or until the end of the word has
|
||||||
// been reached, whichever comes first.
|
// been reached, whichever comes first.
|
||||||
while (actualMoveAmountWithinWord < expectedMoveAmount && cursorPos < mCodePointSize) {
|
while (actualMoveAmount < expectedMoveAmount && cursorPos < codePoints.length) {
|
||||||
actualMoveAmountWithinWord += Character.charCount(codePoints[cursorPos]);
|
actualMoveAmount += Character.charCount(codePoints[cursorPos]);
|
||||||
++cursorPos;
|
++cursorPos;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Moving the cursor backward for the expected amount or until the start of the word
|
// Moving the cursor backward for the expected amount or until the start of the word
|
||||||
// has been reached, whichever comes first.
|
// has been reached, whichever comes first.
|
||||||
while (actualMoveAmountWithinWord > expectedMoveAmount && cursorPos > 0) {
|
while (actualMoveAmount > expectedMoveAmount && cursorPos > 0) {
|
||||||
--cursorPos;
|
--cursorPos;
|
||||||
actualMoveAmountWithinWord -= Character.charCount(codePoints[cursorPos]);
|
actualMoveAmount -= Character.charCount(codePoints[cursorPos]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the actual and expected amounts differ, we crossed the start or the end of the word
|
// If the actual and expected amounts differ, we crossed the start or the end of the word
|
||||||
// so the result would not be inside the composing word.
|
// so the result would not be inside the composing word.
|
||||||
if (actualMoveAmountWithinWord != expectedMoveAmount) return false;
|
if (actualMoveAmount != expectedMoveAmount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
mCursorPositionWithinWord = cursorPos;
|
mCursorPositionWithinWord = cursorPos;
|
||||||
mCombinerChain.applyProcessedEvent(mCombinerChain.processEvent(mEvents,
|
mCombinerChain.applyProcessedEvent(mCombinerChain.processEvent(
|
||||||
Event.createCursorMovedEvent(cursorPos)));
|
mEvents, Event.createCursorMovedEvent(cursorPos)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue