2013-07-17 4 views
1

Je reçois un échec de distribution dynamique sur un compilateur g ++ (Redhat 5.5 gcc version 3.4.6) qui fonctionne correctement sur un compilateur Windows Visual Studio 2003, 2005 et 2010. Pour comprendre ce que je vois, je vais essayer de briser rapidement le problème. Nous avons un processus qui charge dans de nombreux "plugins" d'un répertoire et charge dynamiquement ces plugins (qui sont des bibliothèques liées dynamiquement). Le processus est supposé comparer différentes règles et types de données pour renvoyer une réponse. Pour rendre le processus modulable, nous avons fait en sorte que le processus comprenne un "BaseDataType" mais pas les types spécifiques réels (donc nous pourrions garder le processus générique). Le déroulement du programme va quelque chose comme ceci:Échec de la fusion dynamique C++

Tous nos « SpecifcObject » types hériteront de « BaseDataType » comme celui-ci

class SpecificObject : public virtual BaseDataType { 

    ... Class Items ... 
} 

Voici le code du processus ressemble à:

// Receive raw data 
void receive_data(void *buff, int size,DataTypeEnum type) 
{ 
    // Get the plugin associated with this data 
    ProcessPlugin *plugin = m_plugins[type]; 

    // Since we need to cast the data properly into its actual type and not its 
    // base data type we need the plugin to cast it for us (so we can keep the 
    // process generic) 
    BaseDataType *data = plugin->getDataObject(buff); 
    if(data) 
    { 
    // Cast worked just fine 
    .... Other things happen (but object isn't modified) .... 
    // Now compare our rule 
    RuleObject obj = getRule(); 
    ResultObject *result = plugin->CompareData(obj,data); 
    if(result) 
     ... Success Case ... 
    else 
     ... Error Case ... 
    } 
} 

maintenant, c'est (génériquement) ce plugin ressemblerait

BaseDataType* ProcessPluginOne::getDataObject(unsigned char *buff) 
{ 
    // SpecificObject inherits from BaseDataType using a "virtual" inheritance 
    SpecificObject *obj = reinterpret_cast<SpecificObject*>(buff); 
    if(obj) 
     return (BaseDataType*)obj; 
    else 
     return NULL; 
} 

ResultObject* ProcessPluginOne::CompareData(RuleObject rule, BaseDataType *data) 
{ 
    ResultObject *obj = NULL; 
    // This method checks out fine 
    if(data->GetSomeBaseMethod()) 
    { 
     // This cast below FAILS every time in gcc but passes in Visual Studio 
     SpecificObject *obj = dynamic_cast<SpecificObject*>(data); 
     if(obj) 
     { 
      ... Do Something ... 
     } 
    } 

    return result; 
} 

Encore une fois tout cela fonctionne sous Visual Studio mais pas sous GCC. Pour déboguer le programme j'ai commencé à ajouter du code à différentes sections. J'ai finalement eu à travailler une fois que je l'ai fait ce qui suit dans le processus principal (voir code ajouté ci-dessous):

// In process with Modification 
void receive_data(void *buff, int size,DataTypeEnum type) 
{ 
    // Get the plugin associated with this data 
    ProcessPlugin *plugin = m_plugins[type]; 

    // Since we need to cast the data properly into its actual type and not its 
    // base data type we need the plugin to cast it for us (so we can keep the 
    // process generic) 
    BaseDataType *data = plugin->getDataObject(buff); 
    if(data) 
    { 
    // Cast worked just fine 
    .... Other things happen (but object isn't modified) .... 
    // Now compare our rule 
    RuleObject obj = getRule(); 

    /** I included the specific data types in as headers for debugging and linked in 
     * all the specific classes and added the following code 
     */ 
    SpecificObject *test_obj = dynamic_cast<SpecificObject*>(data); 
    if(test_obj) 
     cout << "Our was Data was casted correctly!" << endl; 
    /// THE CODE ABOVE FIXES THE BAD CAST IN MY PLUGIN EVEN THOUGH 
    /// THE CODE ABOVE IS ALL I DO 


    ResultObject *result = plugin->CompareData(obj,data); 
    if(result) 
     ... Success Case ... 
    else 
     ... Error Case ... 
    } 
} 

Processus importants Options de compilation:

Compile: -m64 -fPIC -wno-non-template-friend -DNDEGBUG -I <Includes> 
Link: -Wl -z muldefs -m64 

important Plugin Options de compilation

Compile: -Wall -wno-non-template-friend -O -O2 
Link: -Wl -Bstatic -Bdynamic -z muldefs -shared -m64 

Comme je ne modifie pas l'objet "données", je n'ai aucune idée de la raison pour laquelle le reste du programme va soudainement commencer à fonctionner. La seule chose que je peux penser est que la table virtuelle est enlevée quelque part dans le processus et la distribution dynamique "supplémentaire" force le processus principal à garder la table (ce qui n'a toujours pas beaucoup de sens).

J'ai essayé de supprimer tous les paramètres d'optimisation dans gcc et c'est toujours pareil. Des pensées sur ce qui se passe ici?

Merci.

+0

Quel est le code * réel * et le code d'appel de 'getDataObject'? Comme vous l'avez posté, le code ne peut pas être compilé (' void * 'n'est pas automatiquement converti en' unsigned char * ') –

+0

Désolé ... C'est en fait juste non signé char * pas vide * C'était une faute de frappe. J'ai confirmé qu'à l'intérieur de getDataObject, la conversion de réinterprétation fonctionne correctement et semble être un SpecificObject valide. Le code _actual_ à l'intérieur de getDataObject ressemble exactement à ce qui a été posté (moins la faute de frappe *). – Nashirak

+0

GCC 3.4.6 est une version très ancienne de GCC (2004). La version actuelle est 4.8.1, elle fonctionne mieux (meilleurs diagnostics, meilleure optimisation, meilleure conformité standard). ** s'il vous plaît mettre à jour votre compilateur GCC ** –

Répondre

1

Les deux scénarios les plus probables sont que BaseDataType est pas un type polymorphes, ou que le compilateur ne voit pas la relation entre BaseDataType et SpecificObject à un moment donné dans le code (par exemple, en getDataObject le compilateur peut générer un code différent en fonction de la connaissance de la relation parent-enfant, puisque vous utilisez C-cast de l'enfant à parent.C'est très facile à vérifier: Changer la distribution en C à static_cast.Si il ne parvient pas à compiler, il vous manque un élément critique.

+0

Depuis que nous utilisons BaseDataType dans d'autres domaines et n'avons pas eu de problèmes (juste pas ce flux exact). Je peux dire que BaseDataType est polymorphe. J'ai essayé le static_cast et il a bien compilé. Je suis convaincu que je compile quelque chose de mal (manquant une option ou mauvais mélange d'options) ou (peu probable mais possible) il y a un bogue de compilateur dans cette version de gcc. – Nashirak