Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ofParameterGroup with sub-groups causes crashes #2674

Closed
jvcleave opened this issue Nov 8, 2013 · 6 comments
Closed

ofParameterGroup with sub-groups causes crashes #2674

jvcleave opened this issue Nov 8, 2013 · 6 comments

Comments

@jvcleave
Copy link
Member

jvcleave commented Nov 8, 2013

Adding a nested ofParameterGroup will cause strangeness(duplicate groups) and crashes with used with an ofBaseSerializer or ofParameterGroup::toString

It is hard to explain without running the code but using traditional pointers yields the expected results. To me this lends itself to something falling out of scope/reference counting with ofPtr

I've narrowed it down to these two examples (also here https://gist.github.com/jvcleave/7366381)

#include "ofMain.h"

#define STRINGIFY(x) #x

class ofApp : public ofBaseApp
{
public:

    ofParameter<bool> createBoolean(ofXml& xmlParser)
    {
        string childName = xmlParser.getName();
        ofParameter<bool> item;
        item.set(childName, xmlParser.getBoolValue());
        return item;
    }

    ofParameterGroup createParameterGroup(ofXml& xmlParser)
    {
        ofParameterGroup parameterGroup;
        string elementName = xmlParser.getName();
        parameterGroup.setName(elementName);
        int numElementChildren = xmlParser.getNumChildren();
        for(int j=0; j<numElementChildren; j++)
        {
            xmlParser.setToChild(j);
                ofParameter<bool> item = createBoolean(xmlParser);
                parameterGroup.add(item);
            xmlParser.setToParent();
        }
        return parameterGroup;
    }
    void setup()
    {
        ofSetLogLevel(OF_LOG_VERBOSE);


        inputXML = STRINGIFY(
                            <root>
                                <single>0</single>
                                <double>0</double>
                                <triple>0</triple>
                                <quad>0</quad>
                                <clauses>
                                    <who>0</who>
                                    <what>0</what>
                                    <where>0</where>
                                    <how>0</how>
                                </clauses>
                                <locations>
                                    <here>0</here>
                                    <there>0</there>
                                </locations>
                            </root>
                             );

        ofLogVerbose() << "inputXML: " << inputXML;
        xmlParser.loadFromBuffer(inputXML);

        xmlParser.setTo("root");
        mainGroup.setName("main");

        int numRootChildren =  xmlParser.getNumChildren();
        ofLogVerbose() << "numRootChildren: " << numRootChildren;
        for(int i=0; i<numRootChildren; i++)
        {
            xmlParser.setToChild(i);
            int numElementChildren = xmlParser.getNumChildren();
            ofLogVerbose() << "xmlParser.getName(): " << xmlParser.getName();
            if (numElementChildren>0)
            {
                ofParameterGroup parameterGroup = createParameterGroup(xmlParser);
                mainGroup.add(parameterGroup);
                ofLogVerbose() << mainGroup.getName() << "\n" << mainGroup.toString();
            }else
            {
                ofParameter<bool> singleItem = createBoolean(xmlParser);
                mainGroup.add(singleItem);
                ofLogVerbose() << mainGroup.getName() << ":" << mainGroup.toString();
            }
            xmlParser.setToParent();
        }

        //next line will crash
        ofLogVerbose() << mainGroup.getName() << ":" << mainGroup.toString();
        //;
    }
    string inputXML;
    ofXml xmlParser;
    ofParameterGroup mainGroup;

};
//========================================================================
int main( ){

    ofSetupOpenGL(1024,768, OF_WINDOW);         // <-------- setup the GL context

    // this kicks off the running of my app
    // can be OF_WINDOW or OF_FULLSCREEN
    // pass in width and height too:
    ofRunApp( new ofApp());

}

Inside the loop it mainGroup.toString() print out

verbose] main
single:0
double:0
triple:0
quad:0
locations:
here:0
there:0
locations:
here:0
there:0

Outside the loop mainGroup.toString() will crash with the backtrace

(lldb)  bt
* thread #1: tid = 0x8f4c9f, 0x002f0aba ofParameterSerializeDebug`ofParameterGroup::getType(this=0xbfffeee8, position=0) const + 44 at ofParameterGroup.cpp:151, queue = 'com.apple.main-thread, stop reason = EXC_BAD_ACCESS (code=1, address=0x30000000)
    frame #0: 0x002f0aba ofParameterSerializeDebug`ofParameterGroup::getType(this=0xbfffeee8, position=0) const + 44 at ofParameterGroup.cpp:151
    frame #1: 0x002f0df5 ofParameterSerializeDebug`operator<<(os=0x00e33140, group=0xbfffeee8) + 263 at ofParameterGroup.cpp:206
    frame #2: 0x002f0ef9 ofParameterSerializeDebug`operator<<(os=0x0000d303, group=0x0000d200) + 523 at ofParameterGroup.cpp:209
    frame #3: 0x002f0ca8 ofParameterSerializeDebug`ofParameterGroup::toString(this=0x00e21540) const + 54 at ofParameterGroup.cpp:179
    frame #4: 0x00004516 ofParameterSerializeDebug`ofApp::setup(this=0x00e21520) + 3638 at main.cpp:84
    frame #5: 0x0000485d ofParameterSerializeDebug`ofBaseApp::setup(this=0x00e21520, args=0x005faca5) + 29 at ofBaseApp.h:41
    frame #6: 0x002b11d8 ofParameterSerializeDebug`Poco::PriorityDelegate<ofBaseApp, ofEventArgs, false>::notify(this=<unavailable>, sender=0x00000000, arguments=<unavailable>) + 70 at PriorityDelegate.h:168
    frame #7: 0x002b6470 ofParameterSerializeDebug`Poco::AbstractEvent<ofEventArgs, Poco::PriorityStrategy<ofEventArgs, Poco::AbstractPriorityDelegate<ofEventArgs> >, Poco::AbstractPriorityDelegate<ofEventArgs>, Poco::FastMutex>::notify(void const*, ofEventArgs&) [inlined] Poco::PriorityStrategy<ofEventArgs, Poco::AbstractPriorityDelegate<ofEventArgs> >::notify(this=0x005e4688, this=0x005e4688, arguments=0x005faca5, sender=0x00000000) + 40 at PriorityStrategy.h:81
    frame #8: 0x002b6448 ofParameterSerializeDebug`Poco::AbstractEvent<ofEventArgs, Poco::PriorityStrategy<ofEventArgs, Poco::AbstractPriorityDelegate<ofEventArgs> >, Poco::AbstractPriorityDelegate<ofEventArgs>, Poco::FastMutex>::notify(this=<unavailable>, pSender=0x00000000, args=0x005faca5) + 90 at AbstractEvent.h:241
    frame #9: 0x002b3896 ofParameterSerializeDebug`void ofNotifyEvent<ofEvent<ofEventArgs>, ofEventArgs>(event=0x02953c00, args=0x005faca5) + 32 at ofEventUtils.h:172
    frame #10: 0x002b3002 ofParameterSerializeDebug`ofNotifySetup() + 36 at ofEvents.cpp:120
    frame #11: 0x002f3ca1 ofParameterSerializeDebug`ofAppGLFWWindow::runAppViaInfiniteLoop(this=0x002ada6d, appPtr=0x00e21520) + 39 at ofAppGLFWWindow.cpp:283
    frame #12: 0x002adebd ofParameterSerializeDebug`ofRunApp(OFSA=0x00e21520) + 1120 at ofAppRunner.cpp:137
    frame #13: 0x00002c71 ofParameterSerializeDebug`main + 305 at main.cpp:102

Using a traditional pointer allows it to work as expected

#include "ofMain.h"

#define STRINGIFY(x) #x

class ofApp : public ofBaseApp
{
public:

    ofParameter<bool> createBoolean(ofXml& xmlParser)
    {
        string childName = xmlParser.getName();
        ofParameter<bool> item;
        item.set(childName, xmlParser.getBoolValue());
        return item;
    }

    ofParameterGroup* createParameterGroup(ofXml& xmlParser)
    {
        ofParameterGroup* parameterGroup = new ofParameterGroup();
        string elementName = xmlParser.getName();
        parameterGroup->setName(elementName);
        int numElementChildren = xmlParser.getNumChildren();
        for(int j=0; j<numElementChildren; j++)
        {
            xmlParser.setToChild(j);
                ofParameter<bool> item = createBoolean(xmlParser);
                parameterGroup->add(item);
            xmlParser.setToParent();
        }
        return parameterGroup;
    }
    void setup()
    {
        ofSetLogLevel(OF_LOG_VERBOSE);


        inputXML = STRINGIFY(
                            <root>
                                <single>0</single>
                                <double>0</double>
                                <triple>0</triple>
                                <quad>0</quad>
                                <clauses>
                                    <who>0</who>
                                    <what>0</what>
                                    <where>0</where>
                                    <how>0</how>
                                </clauses>
                                <locations>
                                    <here>0</here>
                                    <there>0</there>
                                </locations>
                            </root>
                             );

        ofLogVerbose() << "inputXML: " << inputXML;
        xmlParser.loadFromBuffer(inputXML);

        xmlParser.setTo("root");
        mainGroup.setName("main");

        int numRootChildren =  xmlParser.getNumChildren();
        ofLogVerbose() << "numRootChildren: " << numRootChildren;
        for(int i=0; i<numRootChildren; i++)
        {
            xmlParser.setToChild(i);
            int numElementChildren = xmlParser.getNumChildren();
            ofLogVerbose() << "xmlParser.getName(): " << xmlParser.getName();
            if (numElementChildren>0)
            {
                ofParameterGroup* parameterGroup = createParameterGroup(xmlParser);
                mainGroup.add(*parameterGroup);
                ofLogVerbose() << mainGroup.getName() << "\n" << mainGroup.toString();
            }else
            {
                ofParameter<bool> singleItem = createBoolean(xmlParser);
                mainGroup.add(singleItem);
                ofLogVerbose() << mainGroup.getName() << ":" << mainGroup.toString();
            }
            xmlParser.setToParent();
        }

        ofLogVerbose() << mainGroup.getName() << ":" << mainGroup.toString();
        //
    }
    string inputXML;
    ofXml xmlParser;
    ofParameterGroup mainGroup;

};
//========================================================================
int main( ){

    ofSetupOpenGL(1024,768, OF_WINDOW);         // <-------- setup the GL context

    // this kicks off the running of my app
    // can be OF_WINDOW or OF_FULLSCREEN
    // pass in width and height too:
    ofRunApp( new ofApp());

}

This prints

[verbose] main:single:0
double:0
triple:0
quad:0
clauses:
who:0
what:0
where:0
how:0
locations:
here:0
there:0
@arturoc
Copy link
Member

arturoc commented Nov 8, 2013

the parameter group doesn't behave as ofParameter which always does a shallow copy so you can't create an instance in the stack and pass it to for example another group or a gui, you need to create it in the .h

this is probably inconsistent and should behave the same as ofParameter

@jvcleave
Copy link
Member Author

jvcleave commented Nov 8, 2013

Got it. The ability to create them dynamically would be nice as I am trying to create a system where one app is using ofParameter to save it's current state, publishing to an XML file and serving it via an ofxAddon.

A second app can connect to it, read the xml file, convert it to ofParameters, build a GUI and use ofParameter OSC sync to control the first app.

@arturoc
Copy link
Member

arturoc commented May 5, 2014

i'm testing this and it's working for me without problem, my first comment was wrong, actually ofParameterGroup does shallow copy the same as ofParameter, i'm checking the history and there's no changes to the file since 8 months ago so not sure what's the problem, can you check again to see if it's still nor working for you?

arturoc added a commit to arturoc/openFrameworks that referenced this issue Jun 9, 2014
@arturoc arturoc closed this as completed Jun 9, 2014
@danoli3
Copy link
Member

danoli3 commented Jun 10, 2014

@arturoc this is breaking ofxGui

Problem:
https://github.com/openframeworks/openFrameworks/blob/master/addons/ofxGui/src/ofxGuiGroup.cpp#L114

Which is using ofAbstractParameter (which is now no longer in the add(..) for ofParameterGroup)

@yty
Copy link

yty commented Jun 10, 2014

@danoli3 @arturoc

breaking +1..

I tried this modification, but does not work. (guiFromParametersExample)

parameters.add((ofParameterGroup &)(element->getParameter()));

@arturoc
Copy link
Member

arturoc commented Jun 10, 2014

thanks, it's fixed now, let me know if it's still a problem somewhere else

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants