Textarea and <div contenteditable> on the same page lead to content preferences being written without user interaction.

RESOLVED FIXED in Firefox 43



Spelling checker
2 years ago
2 years ago


(Reporter: Jorg K (GMT+2), Assigned: Jorg K (GMT+2))


(Blocks: 1 bug, {regression})


Firefox Tracking Flags

(firefox43 fixed)



(3 attachments, 2 obsolete attachments)



2 years ago
Created attachment 8660200 [details]
Test page showing the bug.

Open the enclosed page. There is a textarea followed by a <div contenteditable>. Click on the textarea.

Having compiled editor/composer/nsEditorSpellCheck.cpp with DEBUG_DICT set, I get this debug:

***** mPreferredLang (element) |en|
***** Assigned from element/doc |en|
***** Setting of |en| failed (or it wasn't available)
***** Trying preference value |en-GB| since it matches language code
***** Writing content preferences for |en-GB|
***** Storing spellchecker.dictionary |en-GB|

As one can clearly see, the content preference is set and also the "spellchecker.dictionary" preference is set, just by visiting a page and without any further user interaction. This is REALLY bad, since we advertised, that content preferences are only written when the user sets a dictionary. Also "spellchecker.dictionary" should only be set at that time.

Further analysis: Here is the callstack when that case happens:
nsEditorSpellCheck::SetCurrentDictionary() Line 616	C++
nsEditorSpellCheck::CheckCurrentDictionary() Line 657	C++
nsEditor::Observe() Line 1336	C++
nsObserverList::NotifyObservers() Line 114	C++
nsObserverService::NotifyObservers() Line 319	C++
mozHunspell::SetDictionary() Line 236	C++
mozSpellChecker::SetCurrentDictionary() Line 412	C++
nsEditorSpellCheck::SetCurrentDictionary() Line 636	C++
nsEditorSpellCheck::TryDictionary() Line 765	C++
nsEditorSpellCheck::DictionaryFetched() Line 917	C++ <======
DictionaryFetcher::HandleCompletion() Line 137	C++

CheckCurrentDictionary() is called and inside it GetCurrentDictionary() is called with return an empty one, so it picks the first from the list, in this case en-GB, and sets it.

Weird is that nsEditor::Observe() does NOT call nsEditorSpellCheck::CheckCurrentDictionary() directly, it calls mInlineSpellChecker->SpellCheckRange(nullptr); and this comes from extensions/spellcheck/src/mozInlineSpellChecker.cpp, however, this doesn't show up on the stack. Oh, I see, the spell check is run asynchronously.

It is also weird that this happens, since nsEditorSpellCheck::DictionaryFetched() is on the stack and there is a gate around setting the content preferences that has the following comment:

  // The purpose of mUpdateDictionaryRunning is to avoid doing all of this if
  // UpdateCurrentDictionary's helper method DictionaryFetched, which calls us,
  // is on the stack. In other words: Only do this, if the user manually selected a
  // dictionary to use.
  if (!mUpdateDictionaryRunning) {

However, the debugger shows that mUpdateDictionaryRunning is false.

This must have to do with the fact that there are two editors on the page, a text area and a <div contenteditable>.

Comment 1

2 years ago
This is really bad. On another bug someone said that content preferences and "spellchecker.dictionary" got written just by visiting a site, and I didn't want to believe it. But here I have the proof. All our good clean-up work is in vain and the attempt to explain to the user what's going on, since due to this bug here, content preferences and "spellchecker.dictionary" are written where they shouldn't be written.

What seems to happen is that nsEditorSpellCheck::DictionaryFetched() is called to retrieve the dictionary of an element. It selects en-GB, since the element "en". Then it calls into the Hunspell stuff, with in turn notifies the observers. One observer calls CheckCurrentDictionary(), it decides that the current dictionary is empty and sets the first one from the list, en-GB, and that really gets set, with content preferences and everything.

Somehow the gate failed, since, if at 3:00 AM I read correctly, there is one gate per editor, but here we have two editors in the test case.

By the looks of it, while setting the dictionary for element A, the observer of element B gets called first. It isn't fully initialised, since the mSpellCheckingEngine is NULL here:
Hence the current dictionary is returned empty.

Or maybe I'm interpreting it wrong.

This is not a regression we caused, this can be reproduced with the current FF 40.

This bug may well be a root cause of the confusion surrounding the spell checking. Many pages have more than one editor, so this case is not uncommon.

What do you say?
Flags: needinfo?(bugs)

Comment 2

2 years ago
Sorry, nsEditorSpellCheck::CheckCurrentDictionary() *is* called from the observer at:
Not at line 1336 as shown in the stack above.

Comment 3

2 years ago
Created attachment 8660258 [details] [diff] [review]
Obvious fix to a fatal problem.

Robert, can you please review this obvious one line fix to a fatal problem.
Obviously, when implementing content preferences in bug 678842 this was overlooked. See bug 678842 comment #17 and

The call to SetCurrentDictionary is missing the gate, which has fatal consequences. My bet is that this is the root cause to much dictionary confusion, since this stores content preferences *at random*.

This fix shouldn't affect anything, since nothing should rely on this faulty behaviour. I'm trying it anyway, just to be sure: https://treeherder.mozilla.org/#/jobs?repo=try&revision=a275329c3ad5
Flags: needinfo?(bugs)
Attachment #8660258 - Flags: review?(roc)


2 years ago
Assignee: nobody → mozilla

Comment 4

2 years ago
Created attachment 8660259 [details] [diff] [review]
Obvious fix to a fatal problem.

Oops. Fixed spelling of patch comment.
Attachment #8660258 - Attachment is obsolete: true
Attachment #8660258 - Flags: review?(roc)
Attachment #8660259 - Flags: review?(roc)

Comment 5

2 years ago
https://treeherder.mozilla.org/#/jobs?repo=try&revision=a275329c3ad5 is completely green.

Comment 6

2 years ago
STR, you don't need a debug build or anything:
- Remove content-prefs.sqlite from your profile.
- Start FF and open attachment 8660200 [details].
- Click into the textarea.
- Now inspect content-prefs.sqlite with your favourite SQLite viewer.
  You will find bug1204147.bmoattachments.org in the groups table.
Comment on attachment 8660259 [details] [diff] [review]
Obvious fix to a fatal problem.

Review of attachment 8660259 [details] [diff] [review]:

Please supply a test. Thanks!!!
Attachment #8660259 - Flags: review?(roc) → review+

Comment 8

2 years ago
I was afraid you'd say that. Sorry, but do we need a test for every obvious coding problem in the system? It's almost a miracle that this regression from bug 678842 was detected at all after four years!

This event driven (focus) and asynchronous (spell check) stuff is fiendish complicated, and as you can see in bug 697981 (working on which discovered this), tests that run on Windows might not run on Linux due to some timing issues.

Here we have the problem of two observers being triggered, one of them isn't quite ready, so if runs through the erroneous code. How can I guarantee that the same order of execution is taking place in the test as in my manual debugging? I'll see what I can do.
Flags: needinfo?(roc)
Keywords: checkin-needed, leave-open, regression
The test doesn't have to always show the problem on every platform. It just has to sometimes show the problem on at least one platform.
Flags: needinfo?(roc)


2 years ago
Keywords: checkin-needed, leave-open

Comment 10

2 years ago
Created attachment 8660593 [details] [diff] [review]
Test case.

On Windows, the test fails if the code patch is *not* applied.
Debug and inspection with the SQLite browser show the content preference was written.

With the code patch, the test passes.

Sadly, the test is rather quirky, since the <div contenteditable> badly spits into our broth.

Attachment #8660593 - Flags: review?(roc)
Comment on attachment 8660593 [details] [diff] [review]
Test case.

Review of attachment 8660593 [details] [diff] [review]:

Attachment #8660593 - Flags: review?(roc) → review+

Comment 12

2 years ago
Created attachment 8660622 [details] [diff] [review]
Test case (v2)

Carrying forward Robert's r+.

Robert: Thanks!

Changed the introductory comment (use interdiff to see it).
Attachment #8660622 - Flags: review+


2 years ago
Attachment #8660593 - Attachment is obsolete: true

Comment 13

2 years ago
Try https://treeherder.mozilla.org/#/jobs?repo=try&revision=87cf383c7eb3 is green.
Test is provided. Everyone is happy. Let's squash this nasty bug and land the two patches.

Dear Sheriff, no special instructions here. Apply in any order.
Keywords: checkin-needed


2 years ago
Blocks: 1073827

Comment 14

2 years ago
Keywords: checkin-needed

Comment 15

2 years ago
If you look at bug 1204540 comment #2 you can see that this fix here fixes five more cases of content preferences being written erroneously in our editor/composer/test test suite (mochitest-o "other").
Last Resolved: 2 years ago
status-firefox43: --- → fixed
Resolution: --- → FIXED
Target Milestone: --- → mozilla43


2 years ago
Duplicate of this bug: 1193293
You need to log in before you can comment on or make changes to this bug.