diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java index efc5a618b..05d34767c 100644 --- a/java/src/com/android/inputmethod/latin/Constants.java +++ b/java/src/com/android/inputmethod/latin/Constants.java @@ -158,6 +158,10 @@ public final class Constants { // A hint on how many characters to cache from the TextView. A good value of this is given by // how many characters we need to be able to almost always find the caps mode. public static final int EDITOR_CONTENTS_CACHE_SIZE = 1024; + // How many characters we accept for the recapitalization functionality. This needs to be + // large enough for all reasonable purposes, but avoid purposeful attacks. 100k sounds about + // right for this. + public static final int MAX_CHARACTERS_FOR_RECAPITALIZATION = 1024 * 100; // Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h public static final int DICTIONARY_MAX_WORD_LENGTH = 48; diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 4fac5ed2d..d4833f5fc 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -1139,15 +1139,21 @@ public final class InputLogic { if (!mConnection.hasSelection()) { return; // No selection } + final int selectionStart = mConnection.getExpectedSelectionStart(); + final int selectionEnd = mConnection.getExpectedSelectionEnd(); + final int numCharsSelected = selectionEnd - selectionStart; + if (numCharsSelected > Constants.MAX_CHARACTERS_FOR_RECAPITALIZATION) { + // We bail out if we have too many characters for performance reasons. We don't want + // to suck possibly multiple-megabyte data. + return; + } // If we have a recapitalize in progress, use it; otherwise, create a new one. if (!mRecapitalizeStatus.isActive() - || !mRecapitalizeStatus.isSetAt(mConnection.getExpectedSelectionStart(), - mConnection.getExpectedSelectionEnd())) { + || !mRecapitalizeStatus.isSetAt(selectionStart, selectionEnd)) { final CharSequence selectedText = mConnection.getSelectedText(0 /* flags, 0 for no styles */); if (TextUtils.isEmpty(selectedText)) return; // Race condition with the input connection - mRecapitalizeStatus.initialize(mConnection.getExpectedSelectionStart(), - mConnection.getExpectedSelectionEnd(), selectedText.toString(), + mRecapitalizeStatus.initialize(selectionStart, selectionEnd, selectedText.toString(), settingsValues.mLocale, settingsValues.mSpacingAndPunctuations.mSortedWordSeparators); // We trim leading and trailing whitespace. @@ -1155,11 +1161,8 @@ public final class InputLogic { } mConnection.finishComposingText(); mRecapitalizeStatus.rotate(); - final int numCharsDeleted = mConnection.getExpectedSelectionEnd() - - mConnection.getExpectedSelectionStart(); - mConnection.setSelection(mConnection.getExpectedSelectionEnd(), - mConnection.getExpectedSelectionEnd()); - mConnection.deleteSurroundingText(numCharsDeleted, 0); + mConnection.setSelection(selectionEnd, selectionEnd); + mConnection.deleteSurroundingText(numCharsSelected, 0); mConnection.commitText(mRecapitalizeStatus.getRecapitalizedString(), 0); mConnection.setSelection(mRecapitalizeStatus.getNewCursorStart(), mRecapitalizeStatus.getNewCursorEnd());