6
votes

Prise en charge personnalisée pour __attribute __ ((format))

GCC et SLIG ont un support pour effectuer des vérifications de temps de compilation sur des fonctions d'argument variable telles que printf . Ces compilateurs acceptent la syntaxe comme: xxx

sur OSX, le framework de cacao utilise également une extension de ceci pour nstring : xxx

Dans notre entreprise, nous avons un cadre personnalisé C ++ avec une bande de classes comme bastion tout dérivant de baseobject . Dans BASESTRING Il existe quelques méthodes d'argument variable similaires à Sprintf , mais avec des extensions. Par exemple, "% s" attend un argument de type bastion * et "% @" attend un baseObject * Argument.

J'aimerais effectuer une vérification du temps de compilation des arguments dans nos projets, mais en raison des extensions, __ attribut __ ((format (printf))) donner beaucoup d'avertissements faux positifs.

existe-t-il un moyen de personnaliser le support de __ attribut __ ((format)) pour l'un des deux compilateurs? Si cela nécessite un correctif à la source du compilateur, est-il faisable dans une quantité de temps raisonnable? Alternativement, y a-t-il d'autres outils Lint comme des outils pouvant effectuer le chèque?


0 commentaires

4 Réponses :


2
votes

C'est faisable, mais ce n'est certainement pas facile; Une partie du problème est que bassetruction et baseObject sont des types définis par l'utilisateur. Vous devez donc définir les spécificateurs de format de manière dynamique. Heureusement, GCC a au moins un support pour cela, mais il faudrait toujours corriger le compilateur.

La magie est dans la fonction manipul_format_attribute dans GCC / C-FAMERY / C-FORMAT.C < / Code>, qui appelle les fonctions d'initialisation pour les spécificateurs de format qui font référence aux types définis par l'utilisateur. Un bon exemple pour baser votre support serait le type de format gcc_gfc , car il définit un spécificateur de format % l pour locus * : xxx

évidemment bien que vous souhaitiez baser votre format_char_info tableau sur print_char_table , comme cela définit la norme printf spécificateurs; gcc_gfc est sensiblement réduit en comparaison.

Le correctif ajouté gcc_gfc est http://gcc.gnu.org/ml/fortran/2005-07/msg00018.html ; Il devrait être assez évident de ce correctif comment et où vous auriez besoin de faire vos ajouts.


0 commentaires

5
votes

avec une version récente de GCC (je recommande 4.7 ou plus récent, mais vous pouvez essayer avec un GCC 4.6 ) Vous pouvez ajouter vos propres variables et fonctions attributes à travers un plug-in GCC (avec le plugin_attributes crochet) ou un fondre extension. Melt est une langue spécifique de domaine pour étendre la GCC (mise en œuvre comme un plug-in [méta-].

Si vous utilisez un plugin (E.G. Melt), vous n'aurez pas besoin de recompiler le code source de GCC. Mais vous avez besoin d'un GCC compatible avec plug-in (Vérifier avec GCC -V ).

En 2020, la FLASE n'est plus mise à jour (en raison du manque de financement); Cependant, vous pouvez écrire votre propre Plugin GCC pour GCC 10 en C ++, faisant de telles vérifications.

Certaines distributions Linux ne permettent pas aux plugins dans leur GCC - Veuillez vous plaindre à votre fournisseur de distribution; D'autres fournissent un package pour le développement du plug-in GCC, par ex. GCC-4.7-Plugin-dev Pour Debian ou Ubuntu.


0 commentaires

2
votes

Un an et demi après avoir posé cette question, je suis sorti avec une approche totalement différente pour résoudre le problème réel: existe-t-il un moyen de vérifier statiquement les types d'instructions de formatage de variadiques personnalisées? em>

Pour l'exhaustivité et parce que cela peut aider d'autres personnes, voici la solution que j'ai enfin mise en œuvre. Il a deux avantages sur la question initiale: p>

  • relativement simple: mis en œuvre en moins d'une journée; Li>
  • compilateur indépendant: peut vérifier le code C ++ sur n'importe quelle plate-forme (Windows, Android, OSX, ...). LI> ul>

    Un script Perl analyse le code source, trouve les chaînes de formatage et décode les modificateurs en pourcentage en eux. Il enveloppe ensuite tous les arguments avec un appel à une fonction d'identité de modèle checkformat code>. Exemple: P>

    enum class CFL
    {
        c, d, i=d, star=i, u, o=u, x=u, X=u, f, F=f, e=f, E=f, g=f, G=f, p, s, S, P=S, at
    };
    enum class CFM
    {
        hh, h, l, z, ll, L=ll, _
    };
    template<CFL letter, CFM modifier, typename T> inline T CheckFormat(T value) { CFL test= value; (void)test; return value; }
    template<> inline const BaseString* CheckFormat<CFL::S, CFM::_, const BaseString*>(const BaseString* value) { return value; }
    template<> inline const BaseObject* CheckFormat<CFL::at, CFM::_, const BaseObject*>(const BaseObject* value) { return value; }
    template<> inline const char* CheckFormat<CFL::s, CFM::_, const char*>(const char* value) { return value; }
    template<> inline const void* CheckFormat<CFL::p, CFM::_, const void*>(const void* value) { return value; }
    template<> inline char CheckFormat<CFL::c, CFM::_, char>(char value) { return value; }
    template<> inline double CheckFormat<CFL::f, CFM::_, double>(double value) { return value; }
    template<> inline float CheckFormat<CFL::f, CFM::_, float>(float value) { return value; }
    template<> inline int CheckFormat<CFL::d, CFM::_, int>(int value) { return value; }
    
    ...
    


2 commentaires

Votre script Perl est-il capable d'analyser le code juridique C ++? D'après mon compréhension, écrivez un outil qui analyse correctement tout le code juridique C ++ est presque aussi difficile que l'écriture d'un compilateur.


@dshin certainement pas, surtout lorsque vous utilisez des macros difficiles. Mais cela fonctionne sans erreur dans notre base de code d'entreprise au moins.



2
votes

avec C ++ 11, il est possible de résoudre ce problème en remplaçant __ attribut__ ((Format)) CODE> avec une combinaison intelligente de consexpr code>, déclencheur et paquets de paramètres variadic. Passez la chaîne de format dans une fonction consexpr code> qui extrait tous les spécificateurs % code> à la compilation et validez que le N'th Specififier correspond au déclinger code > de l'argument ST (N + 1) 'ST.

Voici un croquis de la solution ... p>

Si vous avez: p> xxx pré>

Vous aurez besoin d'une wrapper macro pour my_printf code>, à l'aide du truc décrite ici , pour obtenir quelque chose comme ceci: p> xxx pré>

Vous devez écrire fmtvalidator code> et maqueypeholder () code>. p>

Maketypeholder code> va ressembler à ceci: p>

    template<>
    struct specmatch<int>
    {
        static constexpr bool match(const char* c, const char* cend)
        {
            return strmatches(c, cend, "d") ||
                    strmatches(c, cend, "i");
        }
    };

    // add other specmatch specializations for float, const char*, etc.


4 commentaires

Ce commentaire se lit comme le dernier théorème de Fermat. "Il est possible de résoudre ce problème, mais la solution ne convient pas à ce petit espace de commentaire". Pouvez-vous s'il vous plaît élaborer sur votre solution intelligente?


@ Masonfreed Ajouté plus de détails


Agréable! Merci pour la réponse rapide et une réponse détaillée. Particulièrement utile est le Lien à l'autre poste à ce sujet. Malheureusement, je ne pense pas que cette technique fonctionnera pour moi, car je ne peux pas remplacer ma méthode de classe statique existante avec une macro.


Le truc de macro est pratique mais pas nécessaire. Vous pouvez simplement invoquer directement une fonction de validation qui effectue l'affirmation statique.