thunderbird crashed on launch

Bug #948788 reported by Nick Barcet
48
This bug affects 6 people
Affects Status Importance Assigned to Milestone
Mozilla Firefox
Fix Released
Critical
atk1.0 (Ubuntu)
Fix Released
Critical
Unassigned
Precise
Fix Released
Critical
Unassigned
firefox (Ubuntu)
Fix Released
Undecided
Unassigned
Precise
Fix Released
Undecided
Unassigned

Bug Description

Lauching thunderbird directly results in a core-dump

ProblemType: Bug
DistroRelease: Ubuntu 12.04
Package: thunderbird 11.0~b4+build1-0ubuntu1
ProcVersionSignature: Ubuntu 3.2.0-18.28-generic 3.2.9
Uname: Linux 3.2.0-18-generic x86_64
AddonCompatCheckDisabled: False
AlsaVersion: Advanced Linux Sound Architecture Driver Version 1.0.24.
ApportVersion: 1.94-0ubuntu2
Architecture: amd64
ArecordDevices:
 **** List of CAPTURE Hardware Devices ****
 card 0: Intel [HDA Intel], device 0: CONEXANT Analog [CONEXANT Analog]
   Subdevices: 1/1
   Subdevice #0: subdevice #0
AudioDevicesInUse:
 USER PID ACCESS COMMAND
 /dev/snd/controlC0: nbarcet 2605 F.... pulseaudio
BuildID: 20120302135656
CRDA: Error: [Errno 2] No such file or directory
Card0.Amixer.info:
 Card hw:0 'Intel'/'HDA Intel at 0xf2620000 irq 45'
   Mixer name : 'Intel IbexPeak HDMI'
   Components : 'HDA:14f15069,17aa214c,00100302 HDA:80862804,17aa21b5,00100000'
   Controls : 27
   Simple ctrls : 9
Card29.Amixer.info:
 Card hw:29 'ThinkPadEC'/'ThinkPad Console Audio Control at EC reg 0x30, fw 6IHT39WW-1.14'
   Mixer name : 'ThinkPad EC 6IHT39WW-1.14'
   Components : ''
   Controls : 1
   Simple ctrls : 1
Card29.Amixer.values:
 Simple mixer control 'Console',0
   Capabilities: pswitch pswitch-joined penum
   Playback channels: Mono
   Mono: Playback [on]
Channel: beta
Date: Wed Mar 7 09:51:39 2012
EcryptfsInUse: Yes
ForcedLayersAccel: False
IncompatibleExtensions:
 EDS Contact Integration - <email address hidden>, Version=0.3.9, minVersion=7.0, maxVersion=11.0a1, Location=app-global, Type=extension, Active=Yes
 Dictionnaire français «Classique &amp; Réforme 1990» - <email address hidden>, Version=4.3, minVersion=5.0, maxVersion=10.*, Location=app-profile, Type=extension, Active=Yes
 Auto Select Latest Message (restartless) - ID=autoselectlatestmessage@vano, Version=1.0, minVersion=3.3a1pre, maxVersion=10.*, Location=app-profile, Type=extension, Active=Yes
 Quicktext - ID={8845E3B3-E8FB-40E2-95E9-EC40294818C4}, Version=0.9.11.1, minVersion=5.0b2pre, maxVersion=10.*, Location=app-profile, Type=extension, Active=Yes
 Google Contacts - ID={BDD92442-0534-4D6F-A966-BAB7D561D781}, Version=0.6.40, minVersion=3.1, maxVersion=10.*, Location=app-profile, Type=extension, Active=Yes
InstallationMedia: Ubuntu 12.04 LTS "Precise Pangolin" - Alpha amd64 (20120201.2)
ProcEnviron:
 LANGUAGE=en_US:en
 TERM=xterm
 PATH=(custom, user)
 LANG=en_US.UTF-8
 SHELL=/bin/bash
Profiles: Profile0 (Default) - LastVersion=11.0/20120302135656
RunningIncompatibleAddons: True
SourcePackage: thunderbird
UpgradeStatus: Upgraded to precise on 2012-02-16 (19 days ago)
dmi.bios.date: 02/01/2011
dmi.bios.vendor: LENOVO
dmi.bios.version: 6IET75WW (1.35 )
dmi.board.name: 2516CTO
dmi.board.vendor: LENOVO
dmi.board.version: Not Available
dmi.chassis.asset.tag: No Asset Information
dmi.chassis.type: 10
dmi.chassis.vendor: LENOVO
dmi.chassis.version: Not Available
dmi.modalias: dmi:bvnLENOVO:bvr6IET75WW(1.35):bd02/01/2011:svnLENOVO:pn2516CTO:pvrThinkPadT410:rvnLENOVO:rn2516CTO:rvrNotAvailable:cvnLENOVO:ct10:cvrNotAvailable:
dmi.product.name: 2516CTO
dmi.product.version: ThinkPad T410
dmi.sys.vendor: LENOVO

Related branches

Revision history for this message
Nick Barcet (nijaba) wrote :
Revision history for this message
Nick Barcet (nijaba) wrote :

Backtrace enclosed. Could be related to libatk having been updated prior to this.

Revision history for this message
Launchpad Janitor (janitor) wrote :

Status changed to 'Confirmed' because the bug affects multiple users.

Changed in thunderbird (Ubuntu):
status: New → Confirmed
Changed in thunderbird (Ubuntu Precise):
importance: Undecided → Critical
Changed in firefox (Ubuntu):
status: New → Confirmed
affects: thunderbird (Ubuntu Precise) → atk1.0 (Ubuntu Precise)
Revision history for this message
In , Chris Coulson (chrisccoulson) wrote :

Not sure whose bug this is, but atk 2.3.91 contains this commit which triggers a stack exhaustion crash in Firefox:

http://git.gnome.org/browse/atk/commit/?id=7ebaa51b17fbca385d9d1f3dd026bd4770852d9b

Firefox overloads AtkObject->get_name() with getNameCB() in nsAccessibleWrap.cpp, and getNameCB() calls atk_object_set_name().

See https://launchpad.net/bugs/948788. We've reverted the atk change in Ubuntu for the time being, but I guess this is going to hit other distro's too

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

Do you have stack crash?

Revision history for this message
In , Chris Coulson (chrisccoulson) wrote :
Revision history for this message
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package atk1.0 - 2.3.91-0ubuntu2

---------------
atk1.0 (2.3.91-0ubuntu2) precise; urgency=low

  * revert_set_name_change.patch: revert upstream change leading to
    get_name, set_name loops in firefox code (lp: #948788)
 -- Sebastien Bacher <email address hidden> Wed, 07 Mar 2012 12:34:25 +0100

Changed in atk1.0 (Ubuntu Precise):
status: Confirmed → Fix Released
Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

Oh, I see. We do lazy name setting so we do atk_object_set_name whenever we were asked for accessible name (atk_object_get_name). I'm not sure whether we have another option to do this lazily.

In general I think ATK code shouldn't allow the crash even if the server does something wrong. So simple reentrance guard on atk side should help. Alejandro?

Revision history for this message
In , Alejandro Piñeiro (apinheiro) wrote :

(In reply to alexander :surkov from comment #3)
> Oh, I see. We do lazy name setting so we do atk_object_set_name whenever we
> were asked for accessible name (atk_object_get_name). I'm not sure whether
> we have another option to do this lazily.

So AFAIU, your implementation of _get_name is calling _set_name, and ATK implementation of _set_name is calling _get_name, right?

> In general I think ATK code shouldn't allow the crash even if the server
> does something wrong. So simple reentrance guard on atk side should help.
> Alejandro?

What kind of reentrance guard? Do you have any example on Firefox code?

Anyway, as this week is a GNOME release week, I think that it would be safer to just revert that change, and make a new release, and we could think on solve this issue later (probably after GNOME 3.4).

Revision history for this message
JrZabott (jrzabott) wrote :

After upgrading every hour, my problem persists, can anyone give a tip?

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

(In reply to Alejandro Piñeiro from comment #4)
> (In reply to alexander :surkov from comment #3)
> > Oh, I see. We do lazy name setting so we do atk_object_set_name whenever we
> > were asked for accessible name (atk_object_get_name). I'm not sure whether
> > we have another option to do this lazily.
>
> So AFAIU, your implementation of _get_name is calling _set_name, and ATK
> implementation of _set_name is calling _get_name, right?

yes

> > In general I think ATK code shouldn't allow the crash even if the server
> > does something wrong. So simple reentrance guard on atk side should help.
> > Alejandro?
>
> What kind of reentrance guard? Do you have any example on Firefox code?

sorry for terms. I meant something like this

1015,7 +1015,7 @@ atk_object_set_name (AtkObject *accessible,
if (klass->set_name)
{
  static bool isReentrance = false;
  if (!isReentrance) {
    /* Do not notify for initial name setting. See bug 665870 */
    isReentrance = true;
    notify = (atk_object_get_name (accessible) != NULL);
    isReentrance = false;
  }
}

> Anyway, as this week is a GNOME release week, I think that it would be safer
> to just revert that change, and make a new release, and we could think on
> solve this issue later (probably after GNOME 3.4).

unfortunately that will discover Thunderbird crash

Revision history for this message
JrZabott (jrzabott) wrote :

I've tried... sudo apt-get install atk1.0, and it downloaded some libraries, and the problem persists...

Revision history for this message
JrZabott (jrzabott) wrote :

Sorry everybody, updated right now, problem solved, YOU ARE GREAT guys... :D

Revision history for this message
Alejandro Piñeiro (apinheiro) wrote :

BTW, a new upstream ATK release was done, reverting this change:

https://mail.gnome.org/archives/gnome-accessibility-devel/2012-March/msg00004.html

Thanks for the testing and for pinging me.

Revision history for this message
In , Alejandro Piñeiro (apinheiro) wrote :

FWIW, I have just made a new ATK release:

https://mail.gnome.org/archives/gnome-accessibility-devel/2012-March/msg00004.html

Thanks for pinging me with this issue.

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

after irc chat with Alejandro it seems we don't need to call atk_object_set_name at all. We override atkobject->get_name so we are guaranteed that we always deliver correct accessible name, in other words it doesn't make sense to call atk_object_set_name to change atkobject->accessible->name. Also calling the set_atk_object_name inside of atk_object_get_name could lead to weird things like described by this bug. Also it makes name_changed signal to fire what makes name_changed signal irrelevant (AT asks accessible name and additionally gets name_changed signal).

atkobject->accessible->name is used only by default implementation of get_name/set_name so we shouldn't care to keep accessible->name updated. Also we shouldn't worry to override atkobject->set_name because no one will call it.

changing bug summary

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

just remove atk_object_set_name instances

Revision history for this message
In , Ginn-chen-r (ginn-chen-r) wrote :

We used to use aAtkObj->name as a cache of accessible name, it was long long ago.

Since you said calling atk_object_set_name inside of atk_object_get_name could lead to werid things, I'm wondering whether we should do atk_object_set_parent in getParentCB(), hmm...

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

(In reply to Ginn Chen from comment #9)
> Since you said calling atk_object_set_name inside of atk_object_get_name
> could lead to werid things, I'm wondering whether we should do
> atk_object_set_parent in getParentCB(), hmm...

yeah, I thought about the same. But iirc we have a bug for that.

Revision history for this message
In , Ginn-chen-r (ginn-chen-r) wrote :

(In reply to alexander :surkov from comment #10
> yeah, I thought about the same. But iirc we have a bug for that.

You mean bug 730841?

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

(In reply to Ginn Chen from comment #11)
> (In reply to alexander :surkov from comment #10
> > yeah, I thought about the same. But iirc we have a bug for that.
>
> You mean bug 730841?

nah, bug 716865, at least it has some related discussion (btw, bug 730841 was a follow up from that bug).

Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :

(In reply to alexander :surkov from comment #8)
> just remove atk_object_set_name instances

I suspect we can do a little more cleanup while here, but I'm not sure atm.

you should also explicitly fire name change events right?

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

(In reply to Trevor Saunders (:tbsaunde) from comment #13)
> (In reply to alexander :surkov from comment #8)
> > just remove atk_object_set_name instances
>
> I suspect we can do a little more cleanup while here, but I'm not sure atm.

we have only two instances, it sounds like there's nothing to clean up

> you should also explicitly fire name change events right?

oh, right, we should emit a signal under EVENT_NAME_CHANGE case in nsAccessibleWrap::FirePlatformEvent

Revision history for this message
In , Ginn-chen-r (ginn-chen-r) wrote :

I think the solution is
1) We implement both getNameCB and setNameCB, make sure setNameCB won't get into getNameCB.
Same for parent, role, description, etc.
or
2) We never call atk_object_set_*(), we use object->xxx = blahblahblah, in our code.

However, IMHO,
atk_object_set_name should just use accessible->name.
If an implementation need to call abstract atk_object_get_name instead, it must have implemented atk_object_set_name too.

Revision history for this message
Matthias Klose (doko) wrote :

fixed for firefox as mentioned by Xerxes in bug #948788.

Changed in firefox (Ubuntu Precise):
status: Confirmed → Fix Released
Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

(In reply to Ginn Chen from comment #15)
> I think the solution is
> 1) We implement both getNameCB and setNameCB, make sure setNameCB won't get
> into getNameCB.

makes sense to be on safe side. I'm fine with that.

> Same for parent, role, description, etc.

I'd deal with them in follow ups. Otherwise it might be not a good first bug at all.

> or
> 2) We never call atk_object_set_*(), we use object->xxx = blahblahblah, in
> our code.

API said that object->xxx shouldn't be public (atk_object->accessible).

> However, IMHO,
> atk_object_set_name should just use accessible->name.

It doesn't sound like it's worth to cache accessible name since we always calculate the name on demand (also it's extra strings copy). In gecko we don't fire name_change event for every changed name. So we get hard times to update accessible->name. It sounds all we can do what we do now when we were asked for a name then update accessible->name.

So I think we should go with 1)

Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :

(In reply to alexander :surkov from comment #16)
> (In reply to Ginn Chen from comment #15)
> > I think the solution is
> > 1) We implement both getNameCB and setNameCB, make sure setNameCB won't get
> > into getNameCB.
>
> makes sense to be on safe side. I'm fine with that.

seems good to me.

> > Same for parent, role, description, etc.
>
> I'd deal with them in follow ups. Otherwise it might be not a good first bug
> at all.

yeah, but each of them can probably be there own good first bug.

Revision history for this message
In , Ginn-chen-r (ginn-chen-r) wrote :

(In reply to alexander :surkov from comment #16)
> > 2) We never call atk_object_set_*(), we use object->xxx = blahblahblah, in
> > our code.
>
> API said that object->xxx shouldn't be public (atk_object->accessible).
>

I don't think setting object->xxx in getXXXCB is using it as public.

> > However, IMHO,
> > atk_object_set_name should just use accessible->name.
>
> It doesn't sound like it's worth to cache accessible name since we always
> calculate the name on demand (also it's extra strings copy). In gecko we
> don't fire name_change event for every changed name. So we get hard times to
> update accessible->name. It sounds all we can do what we do now when we were
> asked for a name then update accessible->name.
>
> So I think we should go with 1)

I don't think we should cache it, but I think we should keep accessible->name updated.
We need to copy the string to gchar* anyway.

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

(In reply to Ginn Chen from comment #18)
> (In reply to alexander :surkov from comment #16)
> > > 2) We never call atk_object_set_*(), we use object->xxx = blahblahblah, in
> > > our code.
> >
> > API said that object->xxx shouldn't be public (atk_object->accessible).
> >
>
> I don't think setting object->xxx in getXXXCB is using it as public.

now - it doesn't since we use atk_object_set_name

> > So I think we should go with 1)
>
> I don't think we should cache it, but I think we should keep
> accessible->name updated.

this means a caching, no? Internally we don't keep calculated name, we always calculated it on demand. Why would we need to keep accessible->name updated and how we are going to do that if we don't use atk_object_set_name?

> We need to copy the string to gchar* anyway.

yep, just copy the string every time when we were asked. Doesn't sound good?

Revision history for this message
In , Ginn-chen-r (ginn-chen-r) wrote :

(In reply to alexander :surkov from comment #19)
> this means a caching, no? Internally we don't keep calculated name, we
> always calculated it on demand. Why would we need to keep accessible->name
> updated and how we are going to do that if we don't use atk_object_set_name?

Just use obj->name = xxx
And we saved g_strdup() here.

>
> > We need to copy the string to gchar* anyway.
>
> yep, just copy the string every time when we were asked. Doesn't sound good?

Actually it's not possible.
atk_object_get_name() returns const gchar*, caller will not free the return value.
We have to keep it somewhere in AtkObject, otherwise we leak.

Another benefit is we can easier see what the atk object was in gdb/dbx.

Changed in firefox:
importance: Unknown → Critical
status: Unknown → Confirmed
Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

(In reply to Ginn Chen from comment #20)

> > > We need to copy the string to gchar* anyway.
> >
> > yep, just copy the string every time when we were asked. Doesn't sound good?
>
> Actually it's not possible.
> atk_object_get_name() returns const gchar*, caller will not free the return
> value.
> We have to keep it somewhere in AtkObject, otherwise we leak.

I see

So if provide getName/setName implementation that will use accessible->name to store a value then would it be acceptable solution?

Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :

(In reply to alexander :surkov from comment #21)
> (In reply to Ginn Chen from comment #20)
>
> > > > We need to copy the string to gchar* anyway.
> > >
> > > yep, just copy the string every time when we were asked. Doesn't sound good?
> >
> > Actually it's not possible.
> > atk_object_get_name() returns const gchar*, caller will not free the return
> > value.
> > We have to keep it somewhere in AtkObject, otherwise we leak.
>
> I see
>
> So if provide getName/setName implementation that will use accessible->name
> to store a value then would it be acceptable solution?

or we could do what we do for a bunch of other atk methods reutrning const gchar* nd use nsAccessibleWrap::ReturnString() which keeps a static nsCString and returns a pointer into its buffer, and so requires caller of atk method to copy returned string before calling another atk function, which I think its very likely the bridge will always do.

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

(In reply to Trevor Saunders (:tbsaunde) from comment #22)

> or we could do what we do for a bunch of other atk methods reutrning const
> gchar* nd use nsAccessibleWrap::ReturnString() which keeps a static
> nsCString and returns a pointer into its buffer, and so requires caller of
> atk method to copy returned string before calling another atk function,
> which I think its very likely the bridge will always do.

I think I would try to avoid assumptions like this. Ginn?

Revision history for this message
In , Deckerjeffreyr (deckerjeffreyr) wrote :

I would like to take on this bug if that's alright. Just reading through the comments though it looks like it's a little unclear as to how we want to refactor to fix the bug. Has there been any decision made? I think this would be an iterating bug to work on as I am still a relative newbie to making fixes to Firefox but have a solid programming background.

Thanks,
Jeffrey

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

(In reply to JeffreyDecker from comment #24)
> I would like to take on this bug if that's alright.

done, thank you btw.

> Just reading through the
> comments though it looks like it's a little unclear as to how we want to
> refactor to fix the bug.

I think go with solution from comment #21.

> Has there been any decision made?

Ginn, Trevor, does comment #21 approach sounds acceptable for you?

Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :

(In reply to alexander :surkov from comment #25)
> (In reply to JeffreyDecker from comment #24)
> > I would like to take on this bug if that's alright.
>
> done, thank you btw.
>
> > Just reading through the
> > comments though it looks like it's a little unclear as to how we want to
> > refactor to fix the bug.
>
> I think go with solution from comment #21.
>
> > Has there been any decision made?
>
> Ginn, Trevor, does comment #21 approach sounds acceptable for you?

seems fine.

Revision history for this message
In , Deckerjeffreyr (deckerjeffreyr) wrote :

Just as clarification I need to first write getName and setName and then replace the instances of atk_object_get_name and atk_object_set_name with the new function. Just want to make sure before I get started.

Thank you.

Revision history for this message
In , Ginn-chen-r (ginn-chen-r) wrote :

(In reply to JeffreyDecker from comment #27)
> Just as clarification I need to first write getName and setName and then
> replace the instances of atk_object_get_name and atk_object_set_name with
> the new function. Just want to make sure before I get started.
>
> Thank you.

No, I don't think you need to write getName and setName.
You can write setNameCB just like we have getNameCB.
And use obj->name directly in getNameCB and setNameCB.

Revision history for this message
Brett Alton (brett-alton-deactivatedaccount) wrote :

This has been occuring for me since I wiped 10.10 and installed the 12.04 release. Let me know what I need to add to be useful for this bug.

sheehan@ubuntu:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 12.04 LTS
Release: 12.04
Codename: precise
sheehan@ubuntu:~$ apt-cache policy thunderbird
thunderbird:
  Installed: 12.0.1+build1-0ubuntu0.12.04.1
  Candidate: 12.0.1+build1-0ubuntu0.12.04.1
  Version table:
 *** 12.0.1+build1-0ubuntu0.12.04.1 0
        500 http://us.archive.ubuntu.com/ubuntu/ precise-updates/main i386 Packages
        500 http://security.ubuntu.com/ubuntu/ precise-security/main i386 Packages
        100 /var/lib/dpkg/status
     11.0.1+build1-0ubuntu2 0
        500 http://us.archive.ubuntu.com/ubuntu/ precise/main i386 Packages
sheehan@ubuntu:~$ date
Tue May 8 19:54:35 EDT 2012

Revision history for this message
In , Vd-4 (vd-4) wrote :

Hello,

First of all, this bug does not exist currently because the following commit was reverted from ATK source: https://git.gnome.org/browse/atk/commit/?id=7ebaa51b17fbca385d9d1f3dd026bd4770852d9b

So in order to close this bug, either

1. Leave the code as is and put a comment in ATK source not to call atk_object_get_name() from atk_object_set_name() to avoid future reappearance of this bug, or

2. Change Mozilla's accessible/src/atk/AccessibleWrap.cpp to avoid the problem. I am going to attach a patch for that here shortly. After that the above commit to ATK source may be replayed.

Revision history for this message
In , Vd-4 (vd-4) wrote :

Created attachment 725350
Implement setNameCB() in AccessibleWrap.cpp and use it in getNameCB() instead of atk_object_set_name()

Beware - I am not very familiar with this code, I may have screwed it up!

Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :

Comment on attachment 725350
Implement setNameCB() in AccessibleWrap.cpp and use it in getNameCB() instead of atk_object_set_name()

>@@ -644,11 +644,40 @@ getNameCB(AtkObject* aAtkObj)
>
> NS_ConvertUTF8toUTF16 objName(aAtkObj->name);
> if (!uniName.Equals(objName))
>- atk_object_set_name(aAtkObj, NS_ConvertUTF16toUTF8(uniName).get());
>+ setNameCB(aAtkObj, NS_ConvertUTF16toUTF8(uniName).get());

you don't need to implement SetNameCB() or deal with atkobj->name at all you should be able to just do g_object_notify(blah);

>@@ -1011,6 +1040,7 @@ AccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
> accessible->Name(newName);
> NS_ConvertUTF16toUTF8 utf8Name(newName);
> if (!atkObj->name || !utf8Name.Equals(atkObj->name))
>+ /* XXX also use setNameCB() here? */
> atk_object_set_name(atkObj, utf8Name.get());

just change here too. Note we should do the same thing for atk_object_set_parent() and atk_object_set_description()

btw I don't really care but most people around here like 8 lines of context in diffs.

Changed in firefox:
status: Confirmed → In Progress
Revision history for this message
In , Vd-4 (vd-4) wrote :

Created attachment 726580
Implement a replacement of atk_object_set_name() which mimics the behavior without calling atk_object_get_name()

Do not call our replacement setNameCB() and do not register it as a callback by assigning it to AtkObjectClass::set_name. Also use it in the other place where we use atk_object_set_name(), as suggested by Trevor Saunders (:tbsaunde).

Our function AtkObjectSetName() does the same as what atk_object_set_name() does, except that it does not call atk_object_get_name() but accesses aAtkObj->name directly.

For reference, atk_object_set_name() is implemented here:
https://git.gnome.org/browse/atk/tree/atk/atkobject.c#n999
If the set_name() member has not been overriden, then it will point to atk_object_real_set_name(), which is implemented here:
https://git.gnome.org/browse/atk/tree/atk/atkobject.c#n1420

Practically this patch is a non-functional change since the _current_ version of atk_object_set_name() does not call atk_object_get_name() either but accesses the name directly. The point is that after this patch hits the tree, then this ATK commit could be replayed: https://git.gnome.org/browse/atk/commit/?id=7ebaa51b17fbca385d9d1f3dd026bd4770852d9b

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

Comment on attachment 726580
Implement a replacement of atk_object_set_name() which mimics the behavior without calling atk_object_get_name()

Review of attachment 726580:
-----------------------------------------------------------------

::: i/accessible/src/atk/AccessibleWrap.cpp
@@ +147,5 @@
> #endif
>
> G_BEGIN_DECLS
> +
> +static void AtkObjectSetName(AtkObject *aAtkObj, const gchar *name);

nit: type* name (here and below)

@@ +647,4 @@
>
> NS_ConvertUTF8toUTF16 objName(aAtkObj->name);
> if (!uniName.Equals(objName))
> + AtkObjectSetName(aAtkObj, NS_ConvertUTF16toUTF8(uniName).get());

nit: you can change the code to use one conversion

@@ +654,5 @@
>
> +static void
> +AtkObjectSetName(AtkObject *aAtkObj, const gchar *name)
> +{
> + /* This function duplicates the functionality of atk_object_set_name(),

nit: We use '//' comment style in function body

Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :

Comment on attachment 726580
Implement a replacement of atk_object_set_name() which mimics the behavior without calling atk_object_get_name()

>+static void
>+AtkObjectSetName(AtkObject *aAtkObj, const gchar *name)

so, both of the times this is called we have to check if we actually want to fire an event first. So why don't we refactor this stuff like this

make this function
static void
MaybeFireNameChange(AtkObject* aObj, nsString& aNewName)

then it can incapsilate the stuff about comparing against the old name.

>+ size_t name_len = strlen(name);
>+
>+ if (strlen(aAtkObj->name) >= name_len) {
>+ /* If the new name is shorter, then just use the old memory chunk
>+ * to minimize memory fragmentation. */
>+ memcpy(aAtkObj->name, name, name_len + 1);
>+ } else {
>+ g_free(aAtkObj->name);
>+ aAtkObj->name = g_strdup(name);

I'd be suprised if this isn't a win and possibly a loss. Especially since the best you can do is strlen while the allocator actually knows how big the block is.

otherwise this seems like the correct approach so f=me but I'd like to see another version before r+ :)

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

(In reply to Trevor Saunders (:tbsaunde) from comment #34)
> Comment on attachment 726580
> Implement a replacement of atk_object_set_name() which mimics the behavior
> without calling atk_object_get_name()
>
> >+static void
> >+AtkObjectSetName(AtkObject *aAtkObj, const gchar *name)
>
> so, both of the times this is called we have to check if we actually want to
> fire an event first.

we don't want an event in the former case

Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :

(In reply to alexander :surkov from comment #35)
> (In reply to Trevor Saunders (:tbsaunde) from comment #34)
> > Comment on attachment 726580
> > Implement a replacement of atk_object_set_name() which mimics the behavior
> > without calling atk_object_get_name()
> >
> > >+static void
> > >+AtkObjectSetName(AtkObject *aAtkObj, const gchar *name)
> >
> > so, both of the times this is called we have to check if we actually want to
> > fire an event first.
>
> we don't want an event in the former case

not sure what you mean. both places we call atk_object_set_name() we guard it with something that is more or less oldName != newName

now, the first of those shouldn't be needed in an ideal world because we'd always fire name change event, but we don't do that because its between hard and impossible to do that because name algorithm is complicated and depends on all sorts of stuff.

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

atk_object_set_name() called inside get_name is a wrong thing we try to remove here. It made us fire name change events which is ridiculous I think. If I get right then ATK implementation internals don't need that event as long as we override get_name. On the another hand I don't understand why the consumer might need name change event when it asks for the name.

Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :

(In reply to alexander :surkov from comment #37)
> atk_object_set_name() called inside get_name is a wrong thing we try to

I think the only thing we try to fix here is the infinite recurssion.

> remove here. It made us fire name change events which is ridiculous I think.
> If I get right then ATK implementation internals don't need that event as
> long as we override get_name. On the another hand I don't understand why the
> consumer might need name change event when it asks for the name.

I absolutely agree what we do is crazy, but I know there is caching involved and I'm atleast somewhat concerned not fireing an event in getName() could break that even more than it is now. If your offering to fix name change events so they're fired whenever a name changes and never when it doesn't then of course I'm happy to remove this madness.

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

(In reply to Trevor Saunders (:tbsaunde) from comment #38)
> (In reply to alexander :surkov from comment #37)
> > atk_object_set_name() called inside get_name is a wrong thing we try to
>
> I think the only thing we try to fix here is the infinite recurssion.

and code madnness :)

> > remove here. It made us fire name change events which is ridiculous I think.
> > If I get right then ATK implementation internals don't need that event as
> > long as we override get_name. On the another hand I don't understand why the
> > consumer might need name change event when it asks for the name.
>
> I absolutely agree what we do is crazy, but I know there is caching involved
> and I'm atleast somewhat concerned not fireing an event in getName() could
> break that even more than it is now.

what kind of caching? And how does this caching is supposed to work if somebody asks us to calculate the name (bypassing that cache)? Or alternatively who uses that cache and why all consumers don't want to use it?

> If your offering to fix name change
> events so they're fired whenever a name changes and never when it doesn't
> then of course I'm happy to remove this madness.

iirc AT needs this event every time when name is changed. In this sense our name change event might never work for this purpose.

Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :

(In reply to alexander :surkov from comment #39)
> (In reply to Trevor Saunders (:tbsaunde) from comment #38)
> > (In reply to alexander :surkov from comment #37)
> > > atk_object_set_name() called inside get_name is a wrong thing we try to
> >
> > I think the only thing we try to fix here is the infinite recurssion.
>
> and code madnness :)

why? the reason for the bug was crashes with a change to atk, so just fixing the way we interact with atk should be fine.

> > > remove here. It made us fire name change events which is ridiculous I think.
> > > If I get right then ATK implementation internals don't need that event as
> > > long as we override get_name. On the another hand I don't understand why the

I believe it needs event to keep cache in sync with reality.

> > > consumer might need name change event when it asks for the name.

what if there is more than one consumer, then it may be arguably less bad for other consumers to get the event late rather than never.

> > I absolutely agree what we do is crazy, but I know there is caching involved
> > and I'm atleast somewhat concerned not fireing an event in getName() could
> > break that even more than it is now.
>
> what kind of caching? And how does this caching is supposed to work if
> somebody asks us to calculate the name (bypassing that cache)? Or
> alternatively who uses that cache and why all consumers don't want to use it?

I think the way it works is that consumer processes have a local repreentation of atkobject in their process which keeps the name and atk updates the name based on name change event. So each consumer can choose for itself to use or not use cache as it likes, and might well want to not use the cache because it can easily become out of date due to us not always firing name change events.

> > If your offering to fix name change
> > events so they're fired whenever a name changes and never when it doesn't
> > then of course I'm happy to remove this madness.
>
> iirc AT needs this event every time when name is changed. In this sense our
> name change event might never work for this purpose.

its possible

in any case I'm not really willing to remove the madness we have now atleast until we talk to atk people about it, and I don't see a reason to make vd block on that.

Revision history for this message
In , Alexander Surkov (surkov-alexander) wrote :

(In reply to Trevor Saunders (:tbsaunde) from comment #40)

> > > I think the only thing we try to fix here is the infinite recurssion.
> >
> > and code madnness :)
>
> why? the reason for the bug was crashes with a change to atk, so just fixing
> the way we interact with atk should be fine.

the crash was fixed on atk side, we need to make our side robust.

> > > > consumer might need name change event when it asks for the name.
>
> what if there is more than one consumer, then it may be arguably less bad
> for other consumers to get the event late rather than never.

it's intermittent failures, it's not the way the software is supposed to work

> I think the way it works is that consumer processes have a local
> repreentation of atkobject in their process which keeps the name and atk
> updates the name based on name change event. So each consumer can choose
> for itself to use or not use cache as it likes, and might well want to not
> use the cache because it can easily become out of date due to us not always
> firing name change events.

> in any case I'm not really willing to remove the madness we have now atleast
> until we talk to atk people about it, and I don't see a reason to make vd
> block on that.

see comment #7:

"after irc chat with Alejandro it seems we don't need to call atk_object_set_name at all. We override atkobject->get_name so we are guaranteed that we always deliver correct accessible name, in other words it doesn't make sense to call atk_object_set_name to change atkobject->accessible->name."

If you are really sure than some cache exists that we must update then could you please run a testcase with orca or check it with Alejandro?

Revision history for this message
In , Vd-4 (vd-4) wrote :

Created attachment 728261
Implement a replacement of atk_object_set_name() which mimics the behavior without calling atk_object_get_name()

Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :

Comment on attachment 728261
Implement a replacement of atk_object_set_name() which mimics the behavior without calling atk_object_get_name()

>diff --git i/accessible/src/atk/AccessibleWrap.cpp w/accessible/src/atk/AccessibleWrap.cpp
>index e35da5d..208e955 100644
>--- i/accessible/src/atk/AccessibleWrap.cpp
>+++ w/accessible/src/atk/AccessibleWrap.cpp
>@@ -142,16 +142,20 @@ struct MaiAtkObjectClass
> static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, };
>
> #ifdef MAI_LOGGING
> int32_t sMaiAtkObjCreated = 0;
> int32_t sMaiAtkObjDeleted = 0;
> #endif
>
> G_BEGIN_DECLS
>+
>+static void
>+MaybeFireNameChange(AtkObject *aAtkObj, const nsAutoString& aNewNameUTF16);

there's no reason this needs to be extern "C" which is all the G_DECL thing is hiding is there?

btw type* name

> nsAutoString uniName;
> accWrap->Name(uniName);
>
>- NS_ConvertUTF8toUTF16 objName(aAtkObj->name);
>- if (!uniName.Equals(objName))
>- atk_object_set_name(aAtkObj, NS_ConvertUTF16toUTF8(uniName).get());
>+ // XXX Firing an event from here does not seem right
>+ MaybeFireNameChange(aAtkObj, uniName);

nit, might be nice if you renamed the var to just name since we don't convert it here

>+MaybeFireNameChange(AtkObject* aAtkObj, const nsAutoString& aNewNameUTF16)

nit, utf16 is implied by the type being nsFooString not nsFooCString so kind of redundant

>+{
>+ NS_ConvertUTF8toUTF16 curNameUTF16(aAtkObj->name);

wouldn't it be more efficient to just convert the new name to utf8?

>+
>+ if (aNewNameUTF16.Equals(curNameUTF16)) {
>+ return;
>+ }

nit, no braces

>+ const gchar* name = NS_ConvertUTF16toUTF8(aNewNameUTF16).get();

so, that creates an object that only lives for the statement which is going to mean accessing atkObj->name after this statement is a use after free.

if you convert newName to utf8 at the start you can just do free(atkOjb->name); atkObj->name = strdup(newNameUTF8.get());

>+
>+ // Below we duplicate the functionality of atk_object_set_name(),
>+ // but without calling atk_object_get_name(). Instead of
>+ // atk_object_get_name() we directly access aAtkObj->name. This is because
>+ // atk_object_get_name() would call getNameCB() which would call
>+ // MaybeFireNameChange() (or atk_object_set_name() before this problem was
>+ // fixed) and we would get an infinite recursion.
>+ // See http://bugzilla.mozilla.org/733712
>+
>+ AtkObjectClass *klass;
>+ gboolean notify = FALSE;
>+
>+ g_return_if_fail(ATK_IS_OBJECT(aAtkObj));
>+ g_return_if_fail(name != NULL);
>+
>+ klass = ATK_OBJECT_GET_CLASS(aAtkObj);
>+ if (klass->set_name) {
>+ // Do not notify for initial name setting.
>+ // See bug http://bugzilla.gnome.org/665870
>+ notify = (aAtkObj->name != NULL);
>+
>+ (klass->set_name)(aAtkObj, name);
>+ if (notify) {
>+ g_object_notify(G_OBJECT(aAtkObj), atk_object_name_property_name);
>+ }
>+ }

the only part of this you need is the if notify g_object_notify() bit unless I'm missing something

thanks for helping to clean this up it looks good other than that.

Revision history for this message
In , Vd-4 (vd-4) wrote :
Download full text (3.7 KiB)

(In reply to Trevor Saunders (:tbsaunde) from comment #43)
> Comment on attachment 728261
> Implement a replacement of atk_object_set_name() which mimics the behavior
> without calling atk_object_get_name()
>
> >diff --git i/accessible/src/atk/AccessibleWrap.cpp w/accessible/src/atk/AccessibleWrap.cpp
> >index e35da5d..208e955 100644
> >--- i/accessible/src/atk/AccessibleWrap.cpp
> >+++ w/accessible/src/atk/AccessibleWrap.cpp
> >@@ -142,16 +142,20 @@ struct MaiAtkObjectClass
> > static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, };
> >
> > #ifdef MAI_LOGGING
> > int32_t sMaiAtkObjCreated = 0;
> > int32_t sMaiAtkObjDeleted = 0;
> > #endif
> >
> > G_BEGIN_DECLS
> >+
> >+static void
> >+MaybeFireNameChange(AtkObject *aAtkObj, const nsAutoString& aNewNameUTF16);
>
> there's no reason this needs to be extern "C" which is all the G_DECL thing
> is hiding is there?

Yes, G_BEGIN_DECLS does ``extern "C" {''. There's no special reason why
I put the function prototype inside G_BEGIN_DECLS. I have now moved it
outside.

> btw type* name

Fixed.

> > nsAutoString uniName;
> > accWrap->Name(uniName);
> >
> >- NS_ConvertUTF8toUTF16 objName(aAtkObj->name);
> >- if (!uniName.Equals(objName))
> >- atk_object_set_name(aAtkObj, NS_ConvertUTF16toUTF8(uniName).get());
> >+ // XXX Firing an event from here does not seem right
> >+ MaybeFireNameChange(aAtkObj, uniName);
>
> nit, might be nice if you renamed the var to just name since we don't
> convert it here

Done.

> >+MaybeFireNameChange(AtkObject* aAtkObj, const nsAutoString& aNewNameUTF16)
>
> nit, utf16 is implied by the type being nsFooString not nsFooCString so kind
> of redundant

Ok, renamed it to aNewName.

> >+{
> >+ NS_ConvertUTF8toUTF16 curNameUTF16(aAtkObj->name);
>
> wouldn't it be more efficient to just convert the new name to utf8?

Right, done that way in the simplified version (my original intention was
to preserve the way the body of atk_object_set_name() looks).

> >+ if (aNewNameUTF16.Equals(curNameUTF16)) {
> >+ return;
> >+ }
>
> nit, no braces

Done.

> >+ const gchar* name = NS_ConvertUTF16toUTF8(aNewNameUTF16).get();
>
> so, that creates an object that only lives for the statement which is going
> to mean accessing atkObj->name after this statement is a use after free.

Fixed.

> if you convert newName to utf8 at the start you can just do
> free(atkOjb->name); atkObj->name = strdup(newNameUTF8.get());

Done.

> >+ // Below we duplicate the functionality of atk_object_set_name(),
> >+ // but without calling atk_object_get_name(). Instead of
> >+ // atk_object_get_name() we directly access aAtkObj->name. This is because
> >+ // atk_object_get_name() would call getNameCB() which would call
> >+ // MaybeFireNameChange() (or atk_object_set_name() before this problem was
> >+ // fixed) and we would get an infinite recursion.
> >+ // See http://bugzilla.mozilla.org/733712
> >+
> >+ AtkObjectClass *klass;
> >+ gboolean notify = FALSE;
> >+
> >+ g_return_if_fail(ATK_IS_OBJECT(aAtkObj));
> >+ g_return_if_fail(name != NULL);
> >+
> >+ klass = ATK_OBJECT_GET_CLASS(aAtkObj);
> >+ if (klass->set_name) {
> >+ // Do not notify for initial name setting.
...

Read more...

Revision history for this message
In , Vd-4 (vd-4) wrote :

Created attachment 729066
Implement a replacement of atk_object_set_name() which mimics the behavior without calling atk_object_get_name()

Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :
Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :

Comment on attachment 729066
Implement a replacement of atk_object_set_name() which mimics the behavior without calling atk_object_get_name()

sorry it took me so long, but I finally got to test your patch today. It seems good so I checked it in for you ask you just saw :-)

Revision history for this message
In , Philringnalda (philringnalda) wrote :
Revision history for this message
In , Vd-4 (vd-4) wrote :

Created attachment 738132
Implement a replacement of atk_object_set_name() which mimics the behavior without calling atk_object_get_name()

This is an updated patch that should fix the assertion failure. The only change compared to the pushed patch [1] is this:

-+ if (newNameUTF8.Equals(aAtkObj->name))
++ if (aAtkObj->name && newNameUTF8.Equals(aAtkObj->name))

For some reason I was not able to reproduce the assertion failure myself with the "broken" patch, so I cannot verify that this one fixes the problem, but it *should* fix it.

I will followup here if I manage to reproduce the failure and then confirm that the above change fixes is.

[1] https://hg.mozilla.org/integration/mozilla-inbound/rev/ecd327272240

Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :
Revision history for this message
In , Trevor Saunders (trev-saunders) wrote :

Comment on attachment 738132
Implement a replacement of atk_object_set_name() which mimics the behavior without calling atk_object_get_name()

landed again, but forgot to qref -u sorry :(

Revision history for this message
In , Vd-4 (vd-4) wrote :

No problem, thank you!

Revision history for this message
In , Ryanvm (ryanvm) wrote :
Changed in firefox:
status: In Progress → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.