Merge lp://qastaging/~smspillaz/compiz-core/compiz-core.fix_931927 into lp://qastaging/compiz-core

Proposed by Sam Spilsbury
Status: Merged
Merged at revision: 3010
Proposed branch: lp://qastaging/~smspillaz/compiz-core/compiz-core.fix_931927
Merge into: lp://qastaging/compiz-core
Diff against target: 420 lines (+87/-89)
9 files modified
include/core/abiversion.h (+1/-1)
include/core/option.h (+3/-3)
include/core/plugin.h (+2/-2)
plugins/move/src/move.cpp (+7/-7)
plugins/resize/src/resize.cpp (+7/-7)
src/event.cpp (+1/-1)
src/option.cpp (+62/-64)
src/plugin.cpp (+1/-1)
src/session.cpp (+3/-3)
To merge this branch: bzr merge lp://qastaging/~smspillaz/compiz-core/compiz-core.fix_931927
Reviewer Review Type Date Requested Status
Alan Griffiths Approve
Daniel van Vugt Approve
Tim Penhey Pending
Review via email: mp+93779@code.qastaging.launchpad.net

This proposal supersedes a proposal from 2012-02-16.

Description of the change

Only call removeAction on the CompOption destructor and not the CompOption::Value
destructor, since plugins that make copies of CompOption::Value can cause actions to
be added through setOptionForPlugin and then those actions will be removed when the
value temporary goes away.

The action adding and removing only happens within the bounds of CompOption anyways, so
its its more appropriate to have it in its destructor.

Of course, this brings up another issue, which is that CompOption should be noncopyable
but this opens up a whole another can of worms.

How this even worked before is beyond me...

bug 931927

(See also lp:~smspillaz/compiz-expo-plugin/compiz-expo-plugin.api_change_931927)

To post a comment you must log in.
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

The noOptions API change makes me nervous. Especially the part about returning a reference to a static local:

203 +CompOption::Vector &
204 +noOptions ()
205 +{
206 + static CompOption::Vector v (0);
207 + return v;
208 +}

Why not just change the global:
    CompOption::Vector noOptions (0);
to:
    const CompOption::Vector noOptions (0);
??

review: Needs Information
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

And change:
    extern CompOption::Vector noOptions;
to:
    extern const CompOption::Vector noOptions;

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

And the same for all of:
164 -CompOption::Vector noOptions (0);
165 -CompOption::Value::Vector emptyList;
166 -CompString emptyString;
167 -CompMatch emptyMatch;
168 -CompAction emptyAction;
169 -unsigned short emptyColor[4];

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

All the globals should remain globals instead of functions. Perhaps convert them to const for safety.

review: Needs Fixing
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Static initialization and destruction, basically.

There's a case where the destructor would be called on the global when a plugin was loaded (compiler, linker bug?) before it was actually fully constructed.

I would have made them const, but a lot of the Option* code requires a non const reference. It worked fine even when the globals weren't const, so I don't think this is an issue.

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

OK, that's not a compiler/linker/loader bug at all. That is correct behaviour. I have seen many such static ctor/dtor DSO bugs on various Unixes before, but not Linux, at least not for ~10 years.

The real problem must be globals using other globals during their construction/destruction (again). That's what really needs fixing I think.

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Its not worth fixing in this branch :)

The best way to get around this fiasco, is like the article says, to use the construct-upon-access idiom which is what I have done here.

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

> OK, that's not a compiler/linker/loader bug at all. That is correct behaviour.
> I have seen many such static ctor/dtor DSO bugs on various Unixes before, but
> not Linux, at least not for ~10 years.

To clarify, I guess the reason why I said linker bug was because of this

#0 CompAction::active
#1 CompOption::~CompOption // wtf ?
#2 __static_initialization_and_destruction

The use of uninitialized globals within the constructors of other globals is fine, but calling the destructor to a static object before we hit main () is very strange indeed.

(And yes, I've hit compiler bugs before where destructors were incorrectly called :P)

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

OK, I agree it's a quick fix that should work, even though it impacts the public API in a less than ideal way.

Alan already started logging bugs describing the removal of globals such as screen (in the distant future)...

review: Abstain
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

And I do believe you now :)

But you will probably find some obscure DSO-related reason for the apparently premature destruction.

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

> OK, I agree it's a quick fix that should work, even though it impacts the
> public API in a less than ideal way.
>
> Alan already started logging bugs describing the removal of globals such as
> screen (in the distant future)...

The good news is that only one plugin was impacted by this.

It would be so awesome if const references could be NULL. I guess that's what exceptions are for.

Revision history for this message
Tim Penhey (thumper) wrote : Posted in a previous version of this proposal

I have to agree with Daniel on a number of points. This is kinda ick, but
better than nothing as far as I can tell.

Might as well remove the boost/noncopyable header since you are not using it.

You do hit a couple of differences here.

Static initialisation initially zeros things out. So...

unsigned short emptyColor[4];
would be zero initialised.

When you have a static variable in a function, I don't think it is zero
initialised. Worth checking with Alan about that. So, inside the emptyColor
function use:
  static unsigned short v[4] = {0,0,0,0};

We need to file bugs about the catch (...) bits, that's just ick.

I can't comment on whether this fix actually works. Ideally we'd have test
coverage :-(

review: Needs Fixing
Revision history for this message
Tim Penhey (thumper) wrote : Posted in a previous version of this proposal

> And I do believe you now :)
>
> But you will probably find some obscure DSO-related reason for the apparently
> premature destruction.

What do you mean by DSO-related?

And I have to say that everytime I've come across a weird destruction bug, whether mis-timed or double delete, it has been a coding error, not the compiler.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

I mean that if this destruction issue /is/ a bug then it is most likely triggered by using dynamic shared objects. I've seen many such loader/construction/destruction bugs before. But none in Linux since at least before Ubuntu existed.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Re: "Static initialisation initially zeros things out"

Is that in the C++ spec? As far as I know, basic types like;
    unsigned short emptyColor[4];
will not be initialized at all, because they don't have a constructor.

Revision history for this message
Tim Penhey (thumper) wrote : Posted in a previous version of this proposal

> Re: "Static initialisation initially zeros things out"
>
> Is that in the C++ spec? As far as I know, basic types like;
> unsigned short emptyColor[4];
> will not be initialized at all, because they don't have a constructor.

Normally no, but for statics / globals, yes.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

If that's true I would still recommend explicit initialization for the sake of readability :)

Revision history for this message
Tim Penhey (thumper) : Posted in a previous version of this proposal
review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> Re: "Static initialisation initially zeros things out"
>
> Is that in the C++ spec? As far as I know, basic types like;
> unsigned short emptyColor[4];
> will not be initialized at all, because they don't have a constructor.

Local statics have a special case (don't you just love C++) - they are zero initialized (the same as namespace scope variables - which is what they are to the link loader).

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

Oh, and you don't need

"static unsigned short v[4] = {0,0,0,0};"

either:

"static unsigned short v[] = {0,0,0,0};"

or

"static unsigned short v[4] = {0};"

is fine

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

*** Found the problem ***

CompOption::Vector noOptions (0);
causes a reserve of at least one CompOption to be constructed (and then quickly destructed)

The fix is to change:
    CompOption::Vector noOptions (0);
to:
    CompOption::Vector noOptions;

review: Needs Fixing
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

> *** Found the problem ***
>
> CompOption::Vector noOptions (0);
> causes a reserve of at least one CompOption to be constructed (and then
> quickly destructed)
>
> The fix is to change:
> CompOption::Vector noOptions (0);
> to:
> CompOption::Vector noOptions;

It is still better to use the on-demand construction, for reasons specified above. I'll fix this though.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

This means we don't need to change the public API of "noOptions" or need to change any plugins. You're now doing it for stylistic reasons only. :)

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

There is still a risk involved. I'd much prefer to have less risky code then to be tripped up later.

This isn't "purely stylistic"

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

(Also as evidenced by the fact that PrivateAction was not even created during static initialization and destruction makes me more inclined to make it like this)

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

170 + CompString & emptyString ()

Rather invites:

emptyString () = CompString("Murphy rules!");

(The same applies to a lot of the functions, and the original [non-]constants.)

So, we should add const to the "constants" while addressing this problem.

On the comment discussion: Global data, monostate & singleton are all likely causes for issues. So this code could do with some cleanup regardless of "on demand" or "global data".

As Sam says, it is slightly safer to use "on demand" than global variables - as it ensures they have actually been initialized before use. OTOH, if we "know" there is no init-sequence issue that only makes the design marginally better.

So, I wouldn't have done the "wrapping" if the problem can be fixed more simply. But, if we had the code ready to go I'd take it, it make the codebase a safer place to live.

review: Needs Fixing
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

I can remove all the global data, but I can tell you know that the diff is going to get a *lot* bigger (ditto for adding constness)

Revision history for this message
Tim Penhey (thumper) wrote : Posted in a previous version of this proposal

Sam, if the change to the vector constructor is enough to fix this bug, we should go with the simplest possible branch.

Revision history for this message
Tim Penhey (thumper) wrote : Posted in a previous version of this proposal

I have to admit to preferring to use the default constructor for vectors rather than trying to be clever with the size. It also means that people don't have to go and look for what the integer parameter constructor does.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

"Don't initialize to list size zero since that creates a temporary and destroys it
(for gosh knows what reasons)"

That's because it calls a constructor with a default parameter. Vis:

CompOption::Vector(o, CompOption());

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

I'd really like to know what all the push back on delaying initialization till use is, its a far safer way of doing things and doesn't have any obvious drawbacks.

Revision history for this message
Tim Penhey (thumper) wrote : Posted in a previous version of this proposal

Please also change the constructor in noOptions too:

  static CompOption::Vector v (0);

should be:

  static CompOption::Vector v;

Given that there were also issues around the ordering of the static object initialisation that Sam said he saw, I'm in favour of landing this branch. However, we should look to clean the whole mess up soonish.

I want to know though what the impact is of making these constants.

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Yes indeed on demand construction is more than stylistic. I think my clumsy words missed the point there. My point should have been that on demand construction (while being good for preventative maintenance), is causing a lot more code to change just before a release. And that's a risk.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Conditionally approved, pending the 1-line fix Tim mentioned:
210 + static CompOption::Vector v (0);
becomes:
210 + static CompOption::Vector v;

I've also tested for further API breakage in libcompizconfig, compiz-plugins-main and compiz-plugins-extra. Only main (expo) failed, which Sam has already proposed a fix for.

review: Approve
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Impact of removing the const is that we need to remove these

CompAction &
CompOption::Value::action ()
{
    try
    {
 return boost::get<CompAction>(mValue);
    }
    catch (...)
    {
 return emptyAction ();
    }
}

CompMatch &
CompOption::Value::match ()
{
    try
    {
 return boost::get<CompMatch>(mValue);
    }
    catch (...)
    {
 return emptyMatch ();
    }
}

CompString &
CompOption::Value::s ()
{
    try
    {
 return boost::get < CompString > (mValue);
    }
    catch (...)
    {
 return emptyString ();
    }
}

which I am +1 for but I'm not sure how much client code uses these

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Satisfies my previous comment.

review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Reads OK.

Still concerned about the lack of const-safety, But willing to leave that for posterity.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
The diff is not available at this time. You can reload the page or download it.

Subscribers

People subscribed via source and target branches