Partage
  • Partager sur Facebook
  • Partager sur Twitter

bug clang ?

Sujet résolu
    11 juin 2021 à 11:18:07

    Voila le problème, dans "observable behavior" ils omettent "non terminating loop", volontairement ou pas. Qui conduit à un comportement "bottom"  (le que JR n'arrive pas à taper en HTML :-)). Pour la norme, une boucle infinie  while(1);, c'est pas observable.

    Leur définition d'observable behavior est donc différente de la notion intuitive de "comportement observable"

    C'est fâcheux que ça soit différent, mais bon, quand on cause correction des compilateurs, c'est la définition posée dans la norme qui fait foi.

    ---

    <autopromotion> Ca me rappelle que quand j'étais encore plus jeune que maintenant, j'avais étudié ça pour les expressions qui sont censées représenter des "expressions logiques" retournant vrai ou faux, mais qui en réalité peuvent aussi boucler indéfiniment ou planter.  https://www.semanticscholar.org/paper/Fatal-Errors-in-Conditional-Expressions-(Extended-Billaud/b443f5ba15ba935b02c0b26c4d63562cf250fb99 </autopromotion>

    -
    Edité par michelbillaud 11 juin 2021 à 11:30:53

    • Partager sur Facebook
    • Partager sur Twitter
      11 juin 2021 à 13:24:06

      deux comportements observables différents pour le même code source ⇒ un des deux est fautif. Celui qui donne la mauvaise sortie sans doute. Conclusion : clang (LLVM en fait) a un optimiseur trop agressif qui provoque un bug. Que tu le veuilles ou non au final, c'est également ce que l'équipe LLVM a déduit dans le BR965.
      • Partager sur Facebook
      • Partager sur Twitter
        11 juin 2021 à 16:19:09

        Il y a suffisamment de comportements indéfinis en C pour que le même code source puisse produire des comportements différents.

        Exemple

        include <stdio.h>
        
        int x = 1;
        
        int f(int n) {
        	x = x + n;
        	return x;
        }
        
        int main() {
        	printf("%d\n", f(2) + f(3));
        }
        

        peut afficher 9, ou 10.  Quel comportement est fautif ?


        et pour en revenir au sujet, à ce que nous pouvons tous lire dans la norme qui prend bien soin de définir le terme, la non-terminaison ne fait pas partie (qu'on s'en réjouisse ou qu'on le déplore) des comportements officiellement observables.  Et qu'un compilateur peut zapper ce qui n'a pas de comportement observable. On est bien obligés de faire avec cette réalité.

        Et si l'équipe LLVM a déduit qu'un truc était une erreur, pourquoi ne l'a-t-elle pas corrigé ?

        Si je comprend bien : dans le langage intermédiaire utilisé par LLVM, ils ont introduit des attributs supplémentaires comme mustprogress :

        This attribute indicates that the function is required to return, unwind, or interact with the environment in an observable way e.g. via a volatile memory access, I/O, or other synchronization. The mustprogress attribute is intended to model the requirements of the first section of [intro.progress] of the C++ Standard. As a consequence, a loop in a function with the mustprogress attribute can be assumed to terminate if it does not interact with the environment in an observable way, and terminating loops without side-effects can be removed. If a mustprogress function does not satisfy this contract, the behavior is undefined. This attribute does not apply transitively to callees, but does apply to call sites within the function. Note that willreturn implies mustprogress.

        qui indique qu'on peut supposer que des boucles se terminent, et qu'on peut les virer si elles ne font rien. Ca, c'est au niveau LLVM.

        Maintenant, il faut que les compilateurs  (CLANG) qui reposent sur LLVM génèrent cet attribut, quand c'est pertinent. C'est une autre histoire.

        -
        Edité par michelbillaud 11 juin 2021 à 16:42:36

        • Partager sur Facebook
        • Partager sur Twitter
          11 juin 2021 à 21:50:34

          michelbillaud a écrit:

          Il y a suffisamment de comportements indéfinis en C pour que le même code source puisse produire des comportements différents.

          Exemple

          include <stdio.h>
          
          int x = 1;
          
          int f(int n) {
          	x = x + n;
          	return x;
          }
          
          int main() {
          	printf("%d\n", f(2) + f(3));
          }
          

          peut afficher 9, ou 10.  Quel comportement est fautif ?

          Bel HS. Rien à voir avec le sujet,, essayons de ne pas nous étaler inutilement en essayant de faire passer des vessies pour des lanternes.

          Mais comme tu dis le dis si bien : pour en revenir au sujet

          michelbillaud a écrit:

          Et si l'équipe LLVM a déduit qu'un truc était une erreur, pourquoi ne l'a-t-elle pas corrigé ?

          Si je comprend bien : dans le langage intermédiaire utilisé par LLVM, ils ont introduit des attributs supplémentaires comme mustprogress :

          This attribute indicates that the function is required to return, unwind, or interact with the environment in an observable way e.g. via a volatile memory access, I/O, or other synchronization. The mustprogress attribute is intended to model the requirements of the first section of [intro.progress] of the C++ Standard. As a consequence, a loop in a function with the mustprogress attribute can be assumed to terminate if it does not interact with the environment in an observable way, and terminating loops without side-effects can be removed. If a mustprogress function does not satisfy this contract, the behavior is undefined. This attribute does not apply transitively to callees, but does apply to call sites within the function. Note that willreturn implies mustprogress.

          qui indique qu'on peut supposer que des boucles se terminent, et qu'on peut les virer si elles ne font rien. Ca, c'est au niveau LLVM.

          Maintenant, il faut que les compilateurs  (CLANG) qui reposent sur LLVM génèrent cet attribut, quand c'est pertinent. C'est une autre histoire.

          -
          Edité par michelbillaud il y a environ 4 heures

          Bon apparemment tu as le BR965 mais en diagonal, trop rapidement sans doute … ce ne serait pas la première fois non ? mais tu n'as peut-être pas l'habitude de lire les bug reports. Quoi qu'il en soit «pour en revenir au sujet» :

          Après avoir vérifié que le bug n'a pas déjà été signalé, on remplit un bug report, avec un exemple minimal de code qui produit le bug, une description de tout l'environnement, etc … il te suffit de regarder en détail le BR965. Tu remarqueras qu'il y a 10 duplicates, 10 autres bug reports qui ont été considéré comme décrivant le même problème ou ayant la même cause. Donc 11 report au total …

          Après, puisque tu interviens ici en en parlant, tu peux même essayer les codes demos … et tu verras que ces bugs ont été corrigés mais …  comme tu le fais remarquer à juste titre :

          michelbillaud a écrit:

          [...]
          L'explication du "bug toujours non résolu" est peut être dans la phrase

          > There might still be some incorrect assumptions left over here and there,
          [...]
          -

          Edité par michelbillaud il y a environ 11 heures

          Après que tu le veuilles ou non … c'est un bug qui a mis 15 à être résolu … pourquoi tant de temps ? va savoir hein …



          • Partager sur Facebook
          • Partager sur Twitter
            12 juin 2021 à 12:21:30

            Le fait est que le programme cité au début, avec CLANG 12.0.0, fournit du code beaucoup plus joli, mais qui ne boucle toujours pas

            test():                               # @test()
                    mov     eax, 1
                    ret
            main:                                   # @main
                    push    rax
                    mov     edi, offset .L.str
                    xor     eax, eax
                    call    printf
                    mov     edi, offset .Lstr
                    call    puts@PLT
                    xor     eax, eax
                    pop     rcx
                    ret
            .L.str:
                    .asciz  "On test : "
            
            .Lstr:
                    .asciz  "VRAI"

            https://godbolt.org/z/47vzbo776

            Si le bug LLVM est résolu, peut être que le bug qui a été résolu, ce n'est pas vraiment de ça que ça causait. Voir plus bas.

            --

            Bref, pour résumer.

            1. On a un source C, qui, compilé d'une façon boucle, et d'une autre façon (avec optimisation sur certains compilateurs), se termine.

            2. en lisant innocemment le source et en suivant les instructions une à une, ça DEVRAIT boucler.

            3. Et que _nous_ estimons que le compilateur (quoique il semble y en avoir plusieurs en fait) qui produit "l'optimisation" est buggé parce que nous observons un comportement différent.

            4. ça c'est une déduction incorrecte. Deux compilateurs C corrects peuvent produire des comportements différents sur le même code, parce chacun sait que le langage C est truffé d'ordres d'évaluation non spécifiés. Cf https://en.cppreference.com/w/c/language/eval_order

            Order of evaluation of the operands of any C operator, including the order of evaluation of function arguments in a function-call expression, and the order of evaluation of the subexpressions within any expression is unspecified (except where noted below). The compiler will evaluate them in any order, and may choose another order when the same expression is evaluated again

            5. Un second point, c'est que nous observons des choses, mais la norme C a sa propre définition de comportement observable. Pour nous, la non-terminaison d'un programme est observable (quoi ça prenne un certain temps pour en être sûr :-)). Pour la norme, c'est autre chose.

            6. Si on revient à "eval order" ci dessus, on trouve aussi

            If no side effects are produced by an expression and the compiler can determine that the value is not used, the expression may not be evaluated.

            et comme la non-terminaison n'est pas considérée comme un side-effect, voili voila, un truc qui boucle peut être zappé à la compilation.

            7. L'extrait ci-dessus concerne les expressions, mais dans le standard, il y a le même genre de choses (la fameuse note de bas de page)  : les compilateurs sont - sous certaines conditions - explicitement autorisés à virer du code sans effet de bord dont la terminaison n'est même pas certaine. Optimisation agressive, certes.

            8. Mais qu'il PUISSE être zappé, ça ne veut pas dire qu'il DOIT être zappé. C'est pas spécifié. Donc encore un cas de truc non spécifié qui peut conduire de fait à des exécutions différentes.

            Conclusion : we're deep in the sh*t.

            Au début, j'étais à peu près convaincu comme tout le monde que c'était effectivement un bug du compilateur, mais bon, à mon grand âge on se méfie autant de ce qui a pu passer par la tête des gens qui écrivent les standards que de ceux qui font les compilateurs. Et de nos propres opinions sur ce que le bon sens, dont nous sommes évidemment les représentants exclusifs, exige de toute évidence. Ce qu'on appelle prendre sa vessie pour une lanterne.


            Maintenant, après toutes ces bonnes lectures, je serais plutôt enclin à penser que le code produit avec clang -03 est lui aussi conforme à ce qu'indique le standard,  qui a la mauvaise idée de permettre ce genre de chose. Ca reste dans les limites du standard. Le standard est foireux, mais c'est le standard. Si on ne veut pas d'un langage avec des bizarreries, des unspecified behaviors (en plus des undefined) et des ambiguités, faut pas programmer en C.

            ----

            Si on revient au fameux bug report 965, on va supposer que c'est celui là https://bugs.llvm.org/show_bug.cgi?id=965

            le problème exposé se rapporte au code :

            void f(void) __attribute__((noreturn));
            
            int call_f() { f(); }
            
            void f()     { while(1); }
            

            le monsieur se plaint que

            With "opt -globalsmodref-aa -adce" this gets compiled to:
            
            int %call_f() {
            entry:
                %retval = alloca int, align 4           ; <int*> [#uses=1]
                unreachable ; **** WRONG!!
                
            return:         ; No predecessors!
                %retval = load int* %retval             ; <int> [#uses=1]
                ret int %retval
                
            void %f() {
            entry:
                br label %bb
                
            bb:             ; preds = %bb, %entry
                br label %bb
                
            return:         ; No predecessors!
                ret void    
            


            son souci, ça a l'air d'être le unreachable qui est généré.

            Les ignorants dans mon genre vont chercher dans la doc ce que ça veut dire :

            https://llvm.org/docs/LangRef.html#i-unreachable

            The ‘unreachable’ instruction has no defined semantics. This instruction is used to inform the optimizer that a particular portion of the code is not reachable. This can be used to indicate that the code after a no-return function cannot be reached, and other facts.

            Si je comprend bien on rentre dans call_f, et puis là, trou noir, on tombe sur unreachable Avec ça, on va avoir un peu de mal à générer du code (ni boucle ni return ?), mais ça n'a pas de rapport avec notre problème.

            Comme quoi on devrait toujours lire attentivement les bugs reports, et les normes.

            -
            Edité par michelbillaud 12 juin 2021 à 13:15:00

            • Partager sur Facebook
            • Partager sur Twitter
              12 juin 2021 à 13:36:47

              michelbillaud a écrit:

              Bref, pour résumer.

              1. On a un source C, qui, compilé d'une façon boucle, et d'une autre façon (avec optimisation sur certains compilateurs), se termine.

              2. en lisant innocemment le source et en suivant les instructions une à une, ça DEVRAIT boucler.

              3. Et que _nous_ estimons que le compilateur (quoique il semble y en avoir plusieurs en fait) qui produit "l'optimisation" est buggé parce que nous observons un comportement différent.

              4. ça c'est une déduction incorrecte.[...]

              -

              Edité par michelbillaud il y a moins de 30s


              Voilà LE point qui nous rend nos conceptions des choses irréconciliables :

              Tu dis «en lisant innocemment le source et en suivant les instructions une à une, ça DEVRAIT boucler.» je dis : ⋄«en lisant le source et en suivant les instructions une à une ça DOIT boucler à l'infini». 

              Tu trouves des excuses aux compilos qui produisent un code qui ne boucle pas en disant (et excuse moi car ce que tu dis est gros comme le Burj Khalifa) «on dit que l'optimisation est buggé parce qu'on ne constate un comportement différent d'une exécution pas à pas du source, mais qu'on se trompe car c'est une déduction incorrecte.»

              Et là ce n'est même pas du pinaillage de «et c'est quoi la définition de comportement observable» ? là c'est clairement un exécutable qui ne correspond pas au code source qu'on lui donne à traduire.

              Ho ! Le seul but de l'existence d'un compilateur est de produire un exécutable qui fait ce que le source demande ; aussi idiot ou élégant, aussi incompréhensible ou lisible, qu'il résolve ou non le problème pour lequel il a été créé !

              S'il ne le fait c'est qu'il y a un souci ! 

              Alors que tu trouves des excuses, je trouve une explication. Si la tâche est trop hardue pour le compilo de pouvoir prouver qu'une boucle termine alors il ne doit pas l'optimiser. Parce que là c'est la fenêtre ouverte à toutes les gouttes d'eau qui mettent le feu aux poudres !

              Ton programme ne fonctionne pas correctement ? mais c'est pas grave, Michel t'expliquera pourquoi c'est de ta faute alors que le compilo est blanc comme neige parce qu'au final c'est juste pour t'aider à aller plus vite et puis pourquoi vouloir optimiser de toute façon puisque ton code est incorrect …

              Avec des bugs de cet acabit, c'est clair que ma confiance en clang baisse …

              Parce que des compilos qui ne font pas l'erreur … il y en a.

              Edit:

              Je remarque, en lisant les interventions ici et sur devloppez.net, que nombreux sont ceux qui, comme toi, ont une tendance naturelle à défendre le compilo.
              Je le comprends, j'ai le même a priori : «c'est quoi ce jeune qui veut faire passer son ignorance comme un bug du compilo» le côté «un mauvais ouvrier blâme toujours ses outils» ou «encore un qui revient avec son mouvement perpétuel».
              Mais il faut tout de même  se rendre à l'évidence quand elle est flagrante. Faire comme l'équipe de dèv de LLVM qui dit «ok c'est un bug, on va essayer de faire de notre mieux pour sauver les murs parceque cette fonctionnalité est tout de même utile» tout en rajoutant «on a fait de notre mieux, mais il reste sans doute d'autres cas que l'on traitera indépendamment  au coup par coup si c'est possible».

              Un peu d'humilité que diable !

              -
              Edité par White Crow 12 juin 2021 à 14:01:33

              • Partager sur Facebook
              • Partager sur Twitter
                12 juin 2021 à 17:55:57

                Je ne sais pas pourquoi tu prends ça comme une critique personnelle, à moins de participer au comité qui rédige le standard C, tu n'y est pour rien.

                Tu as tout à faire raison de dire qu'il faut se rendre à l'évidence :

                1. depuis C11 (et on le retrouve dans C17), le standard permet de faire sauter des boucles infinies

                2. certains compilateurs le font

                3. mais ce n'est pas obligatoire en C,

                4. et c'est embêtant parce qu'on ne sait pas si il va le faire ou pas : ça introduit un comportement non spécifié. Un de plus. Et c'est pas cool.

                Maintenant, l'humilité, après nous avoir poussé à vraiment lire la norme au lieu de penser qu'elle devrait dire ce qui nous arrange, et que les gens qui écrivent les compilateurs en appliquant la norme sont incompétents (ils utilisent la norme comme excuse, imaginez-vous), peut aussi nous conduire à regarder la documentation.

                Mieux vaut allumer une chandelle que maudire l'obscurité, qu'il disait l'autre.


                Et à la lumière de cette chandelle https://clang.llvm.org/docs/ClangCommandLineReference.html, constater qu'il y a maintenant avec clang 12 une option qui lève cette indétermination.

                Si on compile avec -O3 -fno-finite-loops   https://godbolt.org/z/PoseEfTE7

                le code généré pour test contient toujours la double boucle

                test():                               # @test()
                .LBB0_1:                                # =>This Loop Header: Depth=1
                        mov     eax, 14
                .LBB0_2:                                #   Parent Loop BB0_1 Depth=1
                        lea     ecx, [rax - 4]
                        mov     edx, ecx
                        imul    edx, ecx
                
                ...
                        add     eax, 5
                        cmp     eax, 104
                        jne     .LBB0_2
                        jmp     .LBB0_1


                et boucle à l'exécution

                ASM generation compiler returned: 0
                Execution build compiler returned: 0
                Program returned: 143
                
                Killed - processing time exceeded

                Et sans l'option, la boucle est éliminée (la fonction test retourne 1, mais on s'en fout parce que le main ne l'appelle pas, elle appelle juste 2 fois printf). L'équipe CLANG a fait le job.

                https://reviews.llvm.org/D96419

                PS et inversement, si on compile avec gcc -O3 -ffinite-loops, la boucle saute. https://godbolt.org/z/r5EsqdEvs

                Toute cette agitation sur clang qui serait horriblement buggé alors que gcc ne le serait pas se ramène donc à une histoire d'options par défaut quand -O3 est présent, qui activent ou pas une élimination de code autorisée par le standard.

                Ca valait le coup de s'énerver et d'invoquer un complot des boomers contre les petits jeunes ignorants qui ne lisent pas les standards ou la doc, tiens.




                -- tu devrais relire le bug report : ça parle d'autre chose

                -
                Edité par michelbillaud 12 juin 2021 à 18:23:43

                • Partager sur Facebook
                • Partager sur Twitter
                  12 juin 2021 à 18:34:14

                  Et moi qui pensais que les standards étaient des edits de Dieu et que les compilateurs avaient été écrits par le Saint-Esprit ...
                  • Partager sur Facebook
                  • Partager sur Twitter

                  Le Tout est souvent plus grand que la somme de ses parties.

                    12 juin 2021 à 20:18:38

                    J'ai retrouvé la référence, ce qu'en dit le comité de normalisation pour justifier tout ça, c'est qu'un programme avec une boucle sans fin a officiellement un comportement indéfini, point barre.  A partir de là, si deux compilateurs ne font pas la même chose avec, faut pas venir se plaindre.

                    http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm


                    et ce que ce qui a été écrit dans le standard C11 est essentiellement une clarification de ce qui était dans le précédent, et qui a été implémenté dans beaucoup de compilateurs

                    The deciding factor in the WG21 discussions was the realization that the current wording is in fact much more of a clarification of the existing standard than a change from it. If the N1509 wording were adopted, many existing compilers would be rendered nonconforming. And a reasonable argument can be made that those compilers currently conform to existing C and C++ standards.

                    La proposition N1509 était de virer le petit laïus (déjà cité) et la note de bas de page sur les boucles dont on peut supposer la terminaison pour permettre de les éliminer.

                    Au passage

                    > John [Regehr] argues that these compilers are violating the current specification, but that was unclear in the WG21 discussions, and it is still unclear to me now.

                    Comme quoi c'est une vieille histoire, qui est décidée depuis longtemps.

                    -
                    Edité par michelbillaud 12 juin 2021 à 20:19:09

                    • Partager sur Facebook
                    • Partager sur Twitter
                      12 juin 2021 à 20:58:39

                      Et qui sait … ptêt qu'elle trouvera même une résolution dans le futur C23, étant donné que cela pose des problèmes :

                      n2280 - Proposal to limit optimization to C semantics

                      Rationale:

                      It is specified in the Standard that "optimization" in a conforming implementation must produce behavior that conforms to the semantics of the language. Advances in optimization technology in translators have lead to the development of multi-pass translators in which semantics of programs can be modified - possibly unintentionally - without some care to preserve semantics over optimization passes. This change calls for conforming implementations to take that care.

                      Proposed change

                      5.1.2.3 Program execution

                      1 The semantic descriptions in this International Standard describe the behavior of an abstract machine in which issues of optimization are irrelevant. A conforming implementation may not change semantics of a program as an "optimization” except as described in 5.1.2.3.4.

                      • Partager sur Facebook
                      • Partager sur Twitter
                        12 juin 2021 à 23:38:34

                        Pas de chance, 5.1.2.3.4  qui ne serait pas touché par cette proposition, c'est justement le passage qui dit qu'on peut se dispenser d'évaluer ce qui ne sert à rien.

                        Le comité de normalisation de C  a décidé depuis 2011 une approche conservatrice, on n'introduit pas de nouveautés (contrairement à c++),  on arrange ce qui est trop mal foutu si c'est possible a peu de frais (ex typeof) mais surtout  on évite de mettre en porte à faux les implémentations existantes. Y a des enjeux économiques derrière, tant pour les marchands de compilos que pour la  compatibilité et la pérennité du code existant.

                        -
                        Edité par michelbillaud 13 juin 2021 à 10:15:35

                        • Partager sur Facebook
                        • Partager sur Twitter
                          12 juin 2021 à 23:57:19

                          michelbillaud a écrit:

                          Pas de chance, 5.1.2.3.4  qui ne setait pas touché par cette proposition, c'est justement le passage qui dit qu'on peut se dispenser d'evaluer ce qui ne sert à rien.

                          Le comité de normalisation de C  a decidé depuis 2011 une approche conservatrice, on n'introduit pas de nouveautés (contrairement à c++),  on arrange ce qui est trop mal foutu si c'est possible a peu de frais (ex typeof) mais surtout  on évite de mettre en porte à faux les implémentations existantes. Y a des enjeux économiques derrière, tant pour les marchands de compilo que pour la  compatibilité de l'existant.

                          -
                          Edité par michelbillaud il y a 6 minutes


                          ah ben tient pourtant tu parlais d'une autre section …

                          michelbillaud a écrit:

                          [...]
                          Après, si on cherche un peu, on trouve dans le standard des choses qui peuvent faire douter.

                          https://stackoverflow.com/questions/59925618/how-do-i-make-an-infinite-empty-loop-that-wont-be-optimized-away

                          Par exemple, est-ce que supprimer une boucle infinie serait si incorrect que ça ?


                          (draft standard c11).

                          et la note d'après précise bien

                          157) This is intended to allow compiler transformations such as removal of empty loops even when termination cannot be proven.



                          ça ne s'appliquerait pas au  for(;;) de l'exemple, précisément ?

                          En d'autres termes :  maybe this is not a bug, that's a feature.


                          [...]

                          -
                          Edité par michelbillaud 10 juin 2021 à 17:56:13

                          Il faudrait te souvenir de ce que tu avances comme arguments … histoire d'être un poil cohérent et crédible.

                          Donc si on cherche un peu (pun intended) , la section 5.1.2.3.4 :

                          In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or through volatile access to an object).

                          Je pense que tu vas sans doute te fendre d'un oui mais … mais je comprends qu'il est facile de se tromper entre un 5.1.2.3.4 et un 6.8.5.6. Tous ces chiffres qui se mélangent … 



                          • Partager sur Facebook
                          • Partager sur Twitter
                            13 juin 2021 à 10:06:06

                            >Il faudrait te souvenir de ce que tu avances comme argument

                            Pas besoin de se souvenir, c'est marqué. C'est simple, au début je pensais (comme tout le monde à ce moment là apparemment) que l'élimination des boucles était un bug, et en me renseignant, j'ai trouvé que non, c'était parfaitement prévu par le standard.

                            Je ne suis pas ici pour étaler des opinions définitives (ça n'intéresserait personne, surtout pas moi qui les connais depuis longtemps), j'apprends et j'intègre des choses.

                            C'est au moment où je suis passé d'une impression basée sur rien à une opinion un peu plus éclairée par des faits, que j'ai écrit

                            > En d'autres termes :  maybe this is not a bug, that's a feature.

                            L'état actuel de la réflexion, c'est qu'il y a bien une sémantique de référence (la machine abstraite) mais qu'elle est pleine de comportements non-spécifiés qui laissent de la marge aux gens qui implémentent des compilateurs. Et les derniers élements trouvés montrent que

                            1. c'est précisément le cas pour les boucles infinies qui ne font rien

                            2. c'est parfaitement connu, volontaire et assumé par le comité de normalisation.

                            Là où on a avancé, c'est qu'on a des textes, issus du WG lui-même, qui en attestent.

                            Et toi, as-tu changé d'avis ? est-ce que pour toi l'élimination des boucles infinies est toujours un bug, une abomination absolument prohibée par le standard ? Tu crois toujours que gcc ne va pas éliminer les boucles, si on lui demande gentiment ? Tu as toujours les mêmes arguments sur la question ? Qu'as tu appris dans cette histoire ? :-)

                            -
                            Edité par michelbillaud 13 juin 2021 à 10:20:33

                            • Partager sur Facebook
                            • Partager sur Twitter
                              13 juin 2021 à 10:26:22

                              michelbillaud a écrit:

                              >Il faudrait te souvenir de ce que tu avances comme argument

                              Pas besoin de se souvenir, c'est marqué. C'est simple, au début je pensais (comme tout le monde à ce moment là apparemment) que l'élimination des boucles était un bug, et en me renseignant, j'ai trouvé que non, c'était parfaitement prévu par le standard.

                              Je ne suis pas ici pour étaler des opinions définitives, j'apprends et j'intègre des choses.

                              C'est au moment où je suis passé d'une impression basée sur rien à une opinion un peu plus éclairée par des faits, que j'ai écrit

                              > En d'autres termes :  maybe this is not a bug, that's a feature.

                              L'état actuel de la réflexion, c'est qu'il y a bien une sémantique de référence (la machine abstraite) mais qu'elle est pleine de comportements non-spécifiés qui laissent de la marge aux gens qui implémentent des compilateurs. [...]
                              -

                              Edité par michelbillaud il y a moins de 30s


                              Donc c'est à ce moment que je me permets de te rappeler :

                              «5.1.2.3 Program execution

                              1 The semantic descriptions in this International Standard describe the behavior of an abstract machine in which issues of optimization are irrelevant»

                              michelbillaud a écrit:

                              [..]
                              Et toi, as-tu changé d'avis ? est-ce que pour toi l'élimination des boucles infinies est toujours un bug, une abomination absolument prohibée par le standard ? Tu crois toujours que gcc ne va pas éliminer les boucles, si on lui demande gentiment ? Tu as toujours les mêmes arguments sur la question ? Qu'as tu appris dans cette histoire ? :-)

                              -
                              Edité par michelbillaud il y a moins de 30s


                              Tu sais que simplement vouloir qu'un compilateur produise un exécutable qui fait exactement ce que le code source demande n'est pas un avis ?

                              Je t'ai montré que gcc (par exemple) ne souffre pas de ce bug … même si on lui demande gentiment ou pas.

                              • Partager sur Facebook
                              • Partager sur Twitter
                                13 juin 2021 à 10:35:40

                                > un exécutable qui fait exactement ce que le code source demande

                                Tu n'as toujours pas compris qu'en raison des "undefined behaviours" de la machine abstraite, "ce que le code source demande" n'est pas forcément déterminé.

                                C'est pour ça que j'avais montré l'exemple  simple  f(2) + f(3)   qui retourne une valeur ou une autre selon l'ordre d'évaluation, qui est indéfini. Et dans ce cas on ne peut pas se réclamer de "ce que le code source demande".

                                Ca me parait pourtant simple à comprendre. Pour un code source, il y a des comportements possibles, en général.

                                Et justement, le comité qualifie volontairement cette histoire de boucle de comportement indéterminé, pour permettre l'élimination.

                                Yodaiken a expliqué sa position N2280 ici https://www.yodaiken.com/2018/06/17/three-modest-proposals-for-the-c-standard-wg14/  et prend bien le soin de préciser qu'il ne s'agit absolument pas de faire le "major rewrite" que John Regehr appelait de ses voeux.

                                 Limiting UB directed “optimizations” will incentivize implementations to optimize within the C semantics and make C more reliable without requiring the major rewrite of the Standard suggested in https://blog.regehr.org/archives/1180 (which motivated this proposal).

                                D'où la mention du "except 5.1.2.3.4".

                                ---

                                > Je t'ai montré que gcc (par exemple) ne souffre pas de ce bug … même si on lui demande gentiment ou pas.

                                Mon message était peut être trop long, et tu n'as pas vu

                                gcc -O3 -ffinite-loops

                                (et ce n'est pas un bug, donc gcc ne souffre pas trop).

                                --- Complément

                                Ce qui est bien avec les WG, c'est qu'on a une trace des meetings. A Pittsburgh ils ont examiné la proposition N2280

                                6.14.Proposal to limit optimization to C semantics [N 2280]

                                Martin: Adding this sentence has no impact on anything. It won’t prevent any of the cases you want prevented. This is already the case for well defined programs

                                Ca sent pas l'enthousiasme.

                                http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf

                                Du coup j'ai aussi cherché ce qu'ils avaient dit sur les histoires d'optimisation des boucles infinies. COmme le blog de Regehr (qui y participe) était de 2010, ça n'a pas été trop dur de trouver. Affaire traitée au meeting de Batavia, compte rendu ici http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1541.pdf

                                6.4 Optimizing away infinite loops(N1509) (Walls)N1509 proposes to eliminated 6.8.5p6 in the current WP as the author believes it to be incompatible with C99. See also N1528, Item 6.30,

                                Response to N1509. N1528 covers why the rules were added. N1509 was written to show a compiler can determine the opposite as well. N1528 breaks existing conforming programs.



                                (WP, c'est work proposal, pas wordpress :-))




                                Et voyons donc 1528 : http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm  qui justifie le choix fait dans N1509 de laisser plusieurs comportements possibles :


                                The current wording, in both C and C++ drafts, explicitly allows the behavior exhibited by many current implementations, while giving the programmer explicit tools for disabling that behavior when it is not desired. It was felt that this was a clear improvement over the status quo, which leaves it ambiguous whether current behavior is allowed, and leaves it unclear, especially with the addition of thread support, exactly what is required to obtain desired behavior.

                                -
                                Edité par michelbillaud 13 juin 2021 à 19:22:29

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  14 juin 2021 à 0:41:39

                                  michelbillaud a écrit:

                                  > un exécutable qui fait exactement ce que le code source demande

                                  Tu n'as toujours pas compris qu'en raison des "undefined behaviours" de la machine abstraite, "ce que le code source demande" n'est pas forcément déterminé.

                                  C'est pour ça que j'avais montré l'exemple  simple  f(2) + f(3)   qui retourne une valeur ou une autre selon l'ordre d'évaluation, qui est indéfini. Et dans ce cas on ne peut pas se réclamer de "ce que le code source demande".

                                  Ca me parait pourtant simple à comprendre. Pour un code source, il y a des comportements possibles, en général.

                                  Et justement, le comité qualifie volontairement cette histoire de boucle de comportement indéterminé, pour permettre l'élimination.[..]
                                  .-

                                  Edité par michelbillaud il y a environ 4 heures

                                  Bon on va faire hypersimple, montre moi dans le standard où il est stipulé qu'une boucle infinie est un UB. Le standard hein …

                                  Ensuite tu m'expliques comment un problème qui est indécidable peut servir pour définir un UB. Une boucle infinie est dans le cas général impossible à détecter (sauf quand c'est une expression constante qui contrôle la boucle, comme un while(1)).

                                  Donc tout programme contenant une boucle dont on ne peut déterminer l'arrêt contient potentiellement un UB et donc sur tout programme de ce type on va pouvoir faire n'importe quoi ?

                                  Sois sérieux.

                                  michelbillaud a écrit:

                                  > Je t'ai montré que gcc (par exemple) ne souffre pas de ce bug … même si on lui demande gentiment ou pas.

                                  Mon message était peut être trop long, et tu n'as pas vu

                                  gcc -O3 -ffinite-loops

                                  (et ce n'est pas un bug, donc gcc ne souffre pas trop).

                                  [...]
                                  -

                                  Edité par michelbillaud il y a environ 4 heures

                                  Ou ptêt que tu as la mauvaise habitude d'éditer tes messages pendant que je te réponds ? Ici, en l'occurrence, il aurait plus adéquat de ta part de t'excuser et de me dire que pendant l'édition de mon message tu as modifié celui auquel je répondais …

                                  Donc non Michel, gcc n'exhibe pas le même souci.

                                  michelbillaud a écrit:

                                  [...]
                                  --- Complément

                                  Ce qui est bien avec les WG, c'est qu'on a une trace des meetings. A Pittsburgh ils ont examiné la proposition N2280

                                  6.14.Proposal to limit optimization to C semantics [N 2280]

                                  Martin: Adding this sentence has no impact on anything. It won’t prevent any of the cases you want prevented. This is already the case for well defined programs

                                  Ca sent pas l'enthousiasme.

                                  http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf

                                  Du coup j'ai aussi cherché ce qu'ils avaient dit sur les histoires d'optimisation des boucles infinies. COmme le blog de Regehr (qui y participe) était de 2010, ça n'a pas été trop dur de trouver. Affaire traitée au meeting de Batavia, compte rendu ici http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1541.pdf

                                  6.4 Optimizing away infinite loops(N1509) (Walls)N1509 proposes to eliminated 6.8.5p6 in the current WP as the author believes it to be incompatible with C99. See also N1528, Item 6.30,

                                  Response to N1509. N1528 covers why the rules were added. N1509 was written to show a compiler can determine the opposite as well. N1528 breaks existing conforming programs.



                                  (WP, c'est work proposal, pas wordpress :-))




                                  Et voyons donc 1528 : http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm  qui justifie le choix fait dans N1509 de laisser plusieurs comportements possibles :


                                  The current wording, in both C and C++ drafts, explicitly allows the behavior exhibited by many current implementations, while giving the programmer explicit tools for disabling that behavior when it is not desired. It was felt that this was a clear improvement over the status quo, which leaves it ambiguous whether current behavior is allowed, and leaves it unclear, especially with the addition of thread support, exactly what is required to obtain desired behavior.

                                  -
                                  Edité par michelbillaud il y a environ 4 heures


                                  Pourquoi ne pas avoir mis le lien vers ce document mais tous les autres ?

                                  Extraire la première réaction est plus que … comment dire … malhonnête ? oui, malhonnête.

                                  C'est un peu comme si de ce document je ne tirais que la partie :

                                  Victor: The transformations I am talking about are not optimizations. They make the program incorrect.
                                  Aaron: Sympathetic to the issue. But compilers can’t tell the intent of the programmer.
                                  Rajan: Seeing the problem would be helpful. It sounds like some of this is compiler bugs.
                                  Dan: I am surprised. If a programmer writes something they intended it. It is blindingly obvious. 

                                  et que je finissais par un 

                                  «tu vois bien que c'est un bug …»

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    14 juin 2021 à 2:25:31

                                    Je met un peu d'huile sur votre feu:
                                    while(1) {
                                         fonction();
                                    {
                                    Est-ce un UB? Et ça devrait être éliminé?
                                    Et les boucles apparemment inutiles qui introduisent un delais trop court pour une pause() ou sleep()
                                    for(int i=0; i < 10000; i++) int j = i;
                                    • Partager sur Facebook
                                    • Partager sur Twitter

                                    Le Tout est souvent plus grand que la somme de ses parties.

                                      14 juin 2021 à 7:26:55

                                      @whitecrow,, continue à ramer, tu verras l'Amérique.

                                      Les transforrmations  dont parle Victor (Y) c'est à propos des débordements arithmétiques. C'est pourquoi il n'était pas pertinent de l'amener dans la conversation. Je t'ai d'ailleurs signalé qu'il n'avait pas de rapport avec la choucroute puisqu'il excluait le point 5,1,2,3,4.  Mais bon, puisque tu disais que c'etait proposé pour l'avenir, c'etait intéressant de voir ce qu'en a dit le comité.

                                      Bref, viens nous parler d'honnêteté et de bonne lecture des documents, les occasions de rigoler sont rares en ce moment

                                      ____

                                      Pierrot Ca PEUT être éliminé si l'analyse inter-procedure permet de conclure que ce qui se passe dans la fonction n'est pas intéressant. 

                                      Il y a d'autres cas encore plus bêtes à propos de l'optimisation , est-ce que dans

                                         Int n = 0 * f(1234);

                                      On peut éliminer l'appel de f ?

                                      -
                                      Edité par michelbillaud 14 juin 2021 à 7:31:21

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        14 juin 2021 à 7:50:40

                                        > Pierrot Ca PEUT être éliminé si l'analyse inter-procedure permet de conclure que ce qui se passe dans la fonction n'est pas intéressant.
                                        Pour déjouer ceci, est-ce que compiler la fonction séparément suffirait?
                                        > int n = 0 * f(1234);
                                        Dans ce cas, peu importe ce que la fonction retourne, ce sera le même résulttat.
                                        Mais si la fonction joue sur des variables globales ou crée un fichier, c'est plus embêtant.
                                        Je suppose que le compilateur ne "voit" pas le code de la fonction.

                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        Le Tout est souvent plus grand que la somme de ses parties.

                                          14 juin 2021 à 7:58:38

                                          Je suis un peu étonné du débat , vu que oui même avec GCC , il y'a des "bug "avec l'option -O3 (enfin des optimisations qui enlève une boucle).

                                          Par exemple quelqu'un qui codé sur l'embarqué (dunSTM32) , avait fait une boucle d’attente , mais GCC avait optimisé en virant la boucle ,du coup ben ça marchais moins bien x)
                                          Je sais que sur le Kernel Linux , il y'a des fois justement où l'optimisation est enlevé (parce que ça vire des boucles alors qu'il ne faut pas).
                                          De façon personnel , je désactive aussi les optimisation suivant les fonctions ou fichier que j'utilise (on peut choisir d'enlever/mettre les optimisations de façon local je rappel )

                                          Bref -O3 n'est pas magique, ça optimise et ça prend pas mal de liberté , quelque fois ça pose pas de soucis ,d'autre fois oui.
                                          Si on veut une optimisation correct mais sans que ça prend trop de liberté , c'est l'optimisation -O1 qu'il faut prendre ;)
                                          (mais meme là on peut avoir des mauvaises surprise )
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            14 juin 2021 à 8:35:44

                                            michelbillaud a écrit:

                                            @whitecrow,, continue à ramer, tu verras l'Amérique.

                                            [...]-

                                            Edité par michelbillaud il y a environ 1 heure


                                            White Crow a écrit:

                                            [...]
                                            Bon on va faire hypersimple, montre moi dans le standard où il est stipulé qu'une boucle infinie est un UB. Le standard hein …

                                            [...]

                                            Une section à citer Michel ??? 

                                            Edit juste pour voir hein Michel … pour te faire comprendre que tu as le droit de répondre après la question aussi …

                                            [...]
                                            ----

                                             > montre moi dans le standard où il est stipulé qu'une boucle infinie est un UB. Le standard hein …

                                            Le comportement indéfini en cas de boucle, c'est la lecture que se donne le comité qui fait le standard. Le "current wording" le permet. Si tu n'es pas d'accord avec eux, faut leur dire. Tu nous raconteras.

                                            Un comportement spécifié, il est unique. Ici on a des possibilités de divergences N1528 etc. Donc ... (inférence laissée au lecteur en exercice).

                                            -
                                            Edité par michelbillaud il y a 5 minutes

                                            Donc tu en es incapable,

                                            donc pour suivre tes raisonnements ce n'est pas une UB … et si ce n'est pas une UB … je te laisse finir tout seul hein …

                                            Michel … réellement, je commence à croire que tu réponds n'importe comment juste pour répondre et perdre le lecteur en faisant des édits à tort et à travers !

                                            Donc oui, plus haut je parlais d'honnêteté



                                            -
                                            Edité par White Crow 14 juin 2021 à 9:23:02

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              14 juin 2021 à 8:46:08

                                              L'élimination des boucles infinies, c'est volontaire. Ca conduit à un comportement surprenant, et embêtant pour les programmeurs embarqués, mais le comité a décidé clairement que c'était une optimisation légale. Même si pour nous c'est délirant. C'est pas nous qui faisons le standard.

                                              @HalbaSama donc il faut se méfier des compilateurs. Et si on veut être sûr que ça fait les choses de la façon qu'on veut, activer les options correspondantes - quand elles existent, et tester. C'est merdique, mais bon c'est pas seulement que les compilos ont des bugs, le langage C est bourré de comportements non spécifiés (dans une des notes de meeting, quelqu'un en a recensé 232 je crois), et en plus c'est volontaire.

                                              Un truc qui ressemble plus à un bug avec clang

                                              #include <stdio.h>
                                              
                                              int f(int n) {
                                              	for(;;){};
                                              	return 1;
                                              }
                                              
                                              int main() {
                                              	int n = f(3);
                                              	printf("n = %d\n", n);
                                              }
                                              

                                              avec clang (7.0.1) -O3

                                              • ça ne boucle pas
                                              • mais ça n'affiche pas non plus le texte attendu.
                                              On dirait que la boucle infinie a été remplacée par un arrêt immédiat.

                                              Regardons le code généré avec différents compilateurs

                                              avec gcc 11.1 -03  (avec -ffinite-loops ou sans)

                                              f(int):
                                              .L2:
                                                      jmp     .L2
                                              main:
                                              .L5:
                                                      jmp     .L5

                                              les deux fonctions bouclent

                                              Avec icc (le compilateur d'intel, toujours -O3), l'exécution affiche n = 1

                                              main:
                                                      push      rbp                                           #8.12
                                                      mov       rbp, rsp                                      #8.12
                                                      and       rsp, -128                                     #8.12
                                                      sub       rsp, 128                                      #8.12
                                                      mov       edi, 3                                        #8.12
                                                      xor       esi, esi                                      #8.12
                                                      call      __intel_new_feature_proc_init                 #8.12
                                                      stmxcsr   DWORD PTR [rsp]                               #8.12
                                                      mov       edi, offset flat: .L_2__STRING.0              #10.2
                                                      mov       esi, 1                                        #10.2
                                                      or        DWORD PTR [rsp], 32832                        #8.12
                                                      xor       eax, eax                                      #10.2
                                                      ldmxcsr   DWORD PTR [rsp]                               #8.12
                                                      call      printf                                        #10.2
                                                      xor       eax, eax                                      #11.1
                                                      mov       rsp, rbp                                      #11.1
                                                      pop       rbp                                           #11.1
                                                      ret                                                     #11.1
                                              f(int):
                                              ..B2.2:                         # Preds ..B2.1 ..B2.2
                                                      jmp       ..B2.2        # Prob 100%                     #
                                              .L_2__STRING.0:
                                                      .long   540876910
                                                      .long   680997

                                              Mais bon, c'est juste le compilo d'intel, une startup qui fait des compilos en carton et ne savent pas lire les standards.

                                              Avec icx, ça se passe mal  -est-ce le compiler explorer qui épluche mal les fichiers de résultat ?

                                                  x86-64 icx 2021.2.0 Executor (Editor #1) C++
                                              
                                              x86-64 icx 2021.2.0
                                              
                                              Program returned: 139
                                              
                                              f(int):                                  # 
                                              .LBB0_1:                                # =>This Inner Loop Header: Depth=1
                                                      jmp     .LBB0_1
                                              main:                                   # 
                                                      stmxcsr dword ptr [rsp - 4]
                                                      or      dword ptr [rsp - 4], 32832
                                                      ldmxcsr dword ptr [rsp - 4]


                                              Avec mscv 19 latest, ça doit pas être l'option -03 (j'avoue à la fois mon ignorance et ma flemme de chercher) parce que le compilateur laisse du code inaccessible (mov + ret) dans f. Et bon, le premier optimimiseur venu sait éliminer ça, quand même

                                              $SG5205 DB        'n = %d', 0aH, 00H
                                              unsigned __int64 `__local_stdio_printf_options'::`2'::_OptionsStorage DQ 01H DUP (?) ; `__local_stdio_printf_options'::`2'::_OptionsStorage
                                              
                                              n$ = 8
                                              int f(int) PROC                               ; f
                                                      mov     DWORD PTR [rsp+8], ecx
                                              $LN2@f:
                                                      jmp     SHORT $LN2@f
                                                      mov     eax, 1
                                                      ret     0
                                              int f(int) ENDP                               ; f
                                              
                                              n$ = 32
                                              main    PROC
                                              $LN3:
                                                      sub     rsp, 56                             ; 00000038H
                                                      mov     ecx, 3
                                                      call    int f(int)                          ; f
                                                      mov     DWORD PTR n$[rsp], eax
                                                      mov     edx, DWORD PTR n$[rsp]
                                                      lea     rcx, OFFSET FLAT:$SG5205
                                                      call    printf
                                                      xor     eax, eax
                                                      add     rsp, 56                             ; 00000038H
                                                      ret     0
                                              main    ENDP

                                              avec clang 12.0, ça boucle

                                              f(int):                                  # @f(int)
                                              .LBB0_1:                                # =>This Inner Loop Header: Depth=1
                                                      jmp     .LBB0_1
                                              main:                                   # @main
                                              .LBB1_1:                                # =>This Inner Loop Header: Depth=1
                                                      jmp     .LBB1_1


                                              ____

                                              Du coup on peut chercher ce qui s'est passé avec clang

                                              7.1 :

                                              f(int):                                  # @f(int)
                                              .LBB0_1:                                # =>This Inner Loop Header: Depth=1
                                                      jmp     .LBB0_1
                                              main:                                   # @main

                                              oups, rien dans le main ? 

                                              8.0, 9.0, 10.0, 11.0 : pareil.



                                              ----

                                               > montre moi dans le standard où il est stipulé qu'une boucle infinie est un UB. Le standard hein …

                                              Le comportement indéfini en cas de boucle, c'est la lecture que se donne le comité qui fait le standard. Le "current wording" le permet. Si tu n'es pas d'accord avec eux, faut leur dire. Tu nous raconteras.

                                              Un comportement spécifié, il est unique. Ici on a des possibilités de divergences N1528 etc. Donc ... (inférence laissée au lecteur en exercice).

                                              -
                                              Edité par michelbillaud 14 juin 2021 à 9:09:16

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                14 juin 2021 à 8:53:28

                                                michelbillaud a écrit:

                                                L'élimination des boucles infinies, c'est volontaire. Ca conduit à un comportement surprenant, et embêtant pour les programmeurs embarqués, mais le comité a décidé clairement que c'était une optimisation légale. Même si pour nous c'est délirant. C'est pas nous qui faisons le standard.

                                                [...]

                                                Je réponds donc à ton message avant toutes modifications.

                                                Oui, c'est volontaire. Oui, c'est surprenant. Non, le comité ne décide pas de ce qui est une optimisation légale ou non, Ah c'est donc délirant pour toi aussi ?

                                                En effet ce n'est pas nous qui faisons le standard, mais nous qui le lisons.

                                                Sans doute as-tu trouvé dans standard actuel la section qui affirme qu'une boucle infinie est un UB.

                                                Pourrais-tu nous faire profiter de cette découverte ?

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  14 juin 2021 à 9:17:34

                                                  > Ah c'est donc délirant pour toi aussi ?

                                                  Ben oui. Je préfère les choses bien définies. Pas mal de gens ont argumenté que ça serait bien que le compilateur signale du "unreachable code" après la boucle, sauf présence d'un attribut spécifique.

                                                  Mais la réalité prévaut sur ce que je préfèrerais. Le standard est dans un certain état, pour des raisons historiques qui s'expliquent très bien.

                                                  Je remets le petit bout :

                                                  Le comportement indéfini en cas de boucle, c'est la lecture que se donne le comité qui fait le standard. Le "current wording" le permet. Si tu n'es pas d'accord avec eux, faut leur dire. Tu nous raconteras.

                                                  Un comportement spécifié, il est unique. Ici on a des possibilités de divergences N1528 etc. Donc ... (inférence laissée au lecteur en exercice).

                                                   Quand le standard dit "An iteration statement ... may be assumed by the implementation to terminate. This is intended to allow compiler transformations such as removal of empty loops even when termination cannot be proven"


                                                  ça dit clairement que la transformation peut et ou ne pas être faite (may, allow). Comme quoi le comité se permet de dire ce qui est légal ou pas en termes de transformations. C'est vrai que ça ne place pas les mots unspecified ou undefined. Et comme ça peut donner des comportements différents, voila la question qu'elle est vite répondue.

                                                  Tu connais quelqu'un qui comprend ça autrement ?

                                                  -
                                                  Edité par michelbillaud 14 juin 2021 à 9:55:15

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    14 juin 2021 à 9:30:39

                                                    Tu en es donc incapable.

                                                    Incapable de simplement indiquer la section du standard qui dit qu'une boucle infinie est un UB/

                                                    Alors oui tu exhibe le N1528 de 2010 qui n'a le défaut sur le N2280 que ses 13 ans d'écart.

                                                    Maintenant, je te laisse reprendre, si une boucle infinie n'est pas un UB  …

                                                    Si on n'arrive pas à déterminer si une boucle est infinie ou non … et si son optimisation provoque un changement de résultats dans le programme c'est que les optimisations ont introduit un bug.

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      14 juin 2021 à 9:39:37

                                                      Ce n'est peut être pas écrit, mais les gens qui écrivent le standard en parlent eux-mêmes dans ces termes.

                                                      Ca ne sert à rien de vouloir être plus royaliste que le roi.

                                                      > c'est que les optimisations ont introduit un bug.

                                                      T'as raison. Porte plainte contre intel, microsoft, etc :-)

                                                      > 13 ans d'écart

                                                      La réponse donnée à Pittsburgh (15-18 octobre 2018), c'est que ça n'a pas changé. Et la proposition 2280 n'a pas été retenue ( voir section 9 dans les minutes http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2375.pdf) Mais bon, c'est inutile de faire diversion avec ça, puisque ça ne concerne même pas la terminaison.

                                                      -
                                                      Edité par michelbillaud 14 juin 2021 à 9:53:39

                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        14 juin 2021 à 10:02:18

                                                        michelbillaud a écrit:

                                                        Ce n'est peut être pas écrit, mais les gens qui écrivent le standard en parlent eux-mêmes dans ces termes.

                                                        Ca ne sert à rien de vouloir être plus royaliste que le roi.

                                                        [...]
                                                        -

                                                        Edité par michelbillaud il y a moins de 5s


                                                        En effet d'ou un ptêt qui indique une possible résolution dans mon message :

                                                        White Crow a écrit:

                                                        Et qui sait … ptêt qu'elle trouvera même une résolution dans le futur C23, étant donné que cela pose des problèmes :

                                                        n2280 - Proposal to limit optimization to C semantics

                                                        michelbillaud a écrit:

                                                        [...]
                                                        > c'est que les optimisations ont introduit un bug.

                                                        T'as raison. Porte plainte contre intel, microsoft, etc :-)

                                                        [...]
                                                        -

                                                        Edité par michelbillaud il y a moins de 5s

                                                        En effet pas la peine d'être plus royaliste que le roi, et c'est bien pourquoi il y a eu 11 bug reports auprès de clang qui l'a considéré comme un bug, mais comme la fonctionnalité est intéressante dans de nombreux autres cas ils ne l'ont que partiellement adressé, traitant les autres au cas par cas.
                                                         

                                                        michelbillaud a écrit:

                                                        [...]

                                                        > 13 ans d'écart

                                                        La réponse donnée à Pittsburgh, c'est que ça n'a pas changé. Et la proposition 2280 n'a pas été retenue ( voir section 9 dans les minutes http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2375.pdf) Mais bon, c'est inutile de faire diversion avec ça, puisque ça ne concerne même pas la terminaison.

                                                        -
                                                        Edité par michelbillaud il y a moins de 5s


                                                        En effet, donc on ne parle plus du N2280 ni du N1528 qui était tout de même un de tes arguments pour affirmer qu'une boucle infinie est un UB.

                                                        D'ailleurs il me semble que l'on ne peut pas confirmer ton affirmation dans le standard …

                                                        J'espère qu'il n'y aura pas eu d'autres modifs à ton message que je n'aurai pu lire.

                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          14 juin 2021 à 10:59:07

                                                          En fait, ça ne sert à rien de s'énerver, et il faut savoir ce qu'on veut dire par bug.

                                                          ---

                                                          Quand un programmeur écrit un code source avec l'intention que ça fasse quelque chose, et qu'à l'exécution ça fait autre chose, c'est un bug.

                                                          Maintenant il peut y avoir plusieurs causes

                                                          • le programmeur s'est planté grossièrement (le plus fréquent)
                                                          • le compilateur est parti aux fraises (ça arrive)
                                                          • le cas qui nous intéresse, le programmeur a supposé que le compilateur DEVRAIT obligatoirement traduire son code source d'une certaine façon.
                                                          Par exemple, conserver la boucle infinie qu'on a mis là exprès pour que ça boucle en attente d'une interruption.
                                                          Mais bon, quand la norme du langage laisse la possibilité (qui n'est pas une obligation) aux compilateurs de transformer les programmes et qu'en pratique ça va donner des résultats différents, le bug c'est de croire des trucs à propos du langage sans se méfier.
                                                          En pratique ce qui est embêtant c'est quand le programmeur ne peut pas donner les options pour activer/désactiver explicitement des types de transformations qui peuvent fâcher. Ou qu'il croit que les options par défaut sont les mêmes d'un compilo à l'autre.

                                                          -
                                                          Edité par michelbillaud 14 juin 2021 à 11:02:08

                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            14 juin 2021 à 11:33:41

                                                            michelbillaud a écrit:

                                                            En fait, ça ne sert à rien de s'énerver, et il faut savoir ce qu'on veut dire par bug.

                                                            ---

                                                            Quand un programmeur écrit un code source avec l'intention que ça fasse quelque chose, et qu'à l'exécution ça fait autre chose, c'est un bug.

                                                            [...]

                                                            -
                                                            Edité par michelbillaud il y a 7 minutes


                                                            Merci. Un code qui décrit une boucle infinie doit produire un exécutable qui boucle à l'infini, si ce n'est pas le cas, c'est qu'il y a un bug.
                                                            Intention ou pas du programmeur. Parce que tel que tu le décris, si le programmeur écrit un code pour calculer la somme d'un tableau qu'il écrit un code qui en donne le produit ce n'est pas un bug, c'est une erreur de l'utilisateur.
                                                            En revanche que le programmeur se plante en écrivant une boucle infinie ou qu'il voulait réellement coder une boucle infinie (en embarqué ou comme simple boucle d'événements pour un GUI) et que le programme produit ne boucle pas à l'infini c'est un bug.

                                                            michelbillaud a écrit:

                                                            [...]

                                                            • le cas qui nous intéresse, le programmeur a supposé que le compilateur DEVRAIT obligatoirement traduire son code source d'une certaine façon.
                                                            Par exemple, conserver la boucle infinie qu'on a mis là exprès pour que ça boucle en attente d'une interruption.
                                                            Mais bon, quand la norme du langage laisse la possibilité (qui n'est pas une obligation) aux compilateurs de transformer les programmes et qu'en pratique ça va donner des résultats différents, le bug c'est de croire des trucs à propos du langage sans se méfier.
                                                            [...]
                                                            -

                                                            Edité par michelbillaud il y a 7 minutes

                                                            Là où nous ne sommes pas d'accord c'est que ce sont plutôt les dèv de compilo qui ont poussé trop loin la possibilité de zapper une boucle infinie. L'approche de gcc est à mon sens plus saine car elle laisse le choix au programmeur d'activer ou non cette optimisation très agressive (et de ne pas l'utiliser si il y a un souci), contrairement à clang qui l'intègre dès -O.

                                                            Je ne suis pas contre les optimisations agressives, nous avons déjà eu une discussion sur clang qui produit un code différent de celui du programmeur mais avec exactement le même comportement observable. Et sur le coup clang a assuré du feu de Dieu. Mais pas ici.



                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                              14 juin 2021 à 12:05:54

                                                              "Un code qui décrit une boucle infinie doit produire un exécutable qui boucle à l'infini, si ce n'est pas le cas, c'est qu'il y a un bug."
                                                              Et pourtant ce n'est pas ce que fait le compilo , vu qu'il vire des boucles.

                                                              Pour ma part je peux comprendre que tu veuille un comportement exact de ce que tu fais,et c'est tout à fait possible en réduisant les optimisations (où comme j'ai vu plus haut , une qui respecte les boucles mise).
                                                              Certaine optimisation (comme le -O3 entre autre) prend beaucoup de liberté dans 99% des cas elle posera pas de problème , mais il y'a des cas spécifiques où ça marchera pas et que le programmeur devra rectifié lui même.
                                                              Je trouve que ça reste un bon compromis que de réduire les optimisations pour seulement les cas "rares"

                                                              (je vois que sur le paragraphe suivant c'est plus clang que tu reproche) , mais ce genre de soucis peut arriver aussi sur GCC donc bon.

                                                              -
                                                              Edité par HelbaSama 14 juin 2021 à 12:06:43

                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              bug clang ?

                                                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                              • Editeur
                                                              • Markdown