Alors, bon, je vais essayer de rester calme et objectif, histoire de faire en sorte que ça soit compréhensible par le plus grand monde possible.
Il y avait ruby 1.8.6 patchlevel 0, et il marchait, enfin, tout les morceaux que j’en utilisent marchaient. Et puis, il y a eu une vulnérabilité, je ne sais pas trop quoi, alors, ça a été mis à jour, en ruby 1.8.6 patchlevel 111…
Et c’est là que ça s’est gâté :-(
Je suis un grand utilisateur de la bibliothèque REXML qui est une boite à tout faire pour lire, manipuler et générer du XML, y’a du xpath, et d’autres choses que même pas on veut savoir. Toujours est-il que dans la version 1.8.6 patchlevel 0 (que j’appellerai plus loin «pl0») il marchait, et que dans la version 1.8.6 patchlevel 111 (que j’appellerai «pl111») ben, il est complêtement pété.
Je m’explique (attention, ça va être un peu long)…
Donc, premier point, dans pl0 :
irb(main):001:0> require 'rexml/document'
=> true
irb(main):002:0> REXML::Document.new('<foo><bar>baz<baz/></bar></foo>').write($stderr, 2, true, true)
<foo
><bar>baz<baz
/></bar
></foo
>=> [<?xml ... ?>, <foo> ... </>]
Oui, je sais, ça ne veux rien dire à personne, mais c’est un document XML valide, qui est parsé, et recraché dans un autre format.
Maintenant, dans la pl111 :
irb(main):001:0> require 'rexml/document'
=> true
irb(main):002:0> REXML::Document.new('<foo><bar>baz<baz/></bar></foo>').write($stderr, 2, true, true)
NameError: undefined local variable or method `transitive' for <UNDEFINED> ... </>:REXML::Document
from /usr/local/lib/ruby/1.8/rexml/document.rb:186:in `write'
from (irb):2
Ah, ça commence mal, un crétin à appelé une variable trans dans la définition de la méthode, et l’a appelée transitive quand il a voulu l’utiliser. Pas grave me dis-je, je vais modifier, et ça va rouler…
irb(main):002:0> REXML::Document.new('<foo><bar>baz<baz/></bar></foo>').write($stderr, 2, true, true)
NameError: uninitialized constant REXML::Formatters::Transitive
from /usr/local/lib/ruby/1.8/rexml/document.rb:187:in `write'
from (irb):2
Ah, un autre crétin a du jouer au grand, je recherche un peu, y’a plusieurs formatters qui sont tous inclus dans un autre fichier, pour faire propre, je vais faire ça au bon endroit (c’est à dire dans rexml/node.rb), et je me dis, bon, ça va rouler…
irb(main):002:0> REXML::Document.new('<foo><bar>baz<baz/></bar></foo>').write($stderr, 2, true, true)
ArgumentError: wrong number of arguments (2 for 1)
from /usr/local/lib/ruby/1.8/rexml/document.rb:187:in `initialize'
from /usr/local/lib/ruby/1.8/rexml/document.rb:187:in `new'
from /usr/local/lib/ruby/1.8/rexml/document.rb:187:in `write'
from (irb):2
Non, toujours pas, ils ont du s’y mettre à plusieurs pour faire tout ça. Bon, je regarde, le constructeur de REXML::Formatters::Transitive ne prends qu’un seul argument, je vire le deuxième (a pile ou face), et je me dis, bon, ça va rouler…
irb(main):002:0> REXML::Document.new('<foo><bar>baz<baz/></bar></foo>').write($stderr, 2, true, true)
<foo
><bar
>baz<baz
/></bar
></foo
>=> [<?xml ... ?>, <foo> ... </>]
Oh, miracle, ça ne crie plus. Bon, ça ne génère pas tout à fait le même xml (parce qu’en fait, je me suis apperçu que le deuxième paramètre de la fonction write avait, sans changer de nom, changé de sens), mais c’est pas grave, je me dis, cool, ça va rouler, mais j’ai un autre truc qui m’a chiffoné dans du XML qu’il a généré, je me penche donc dessus.
Donc, dans p0 :
irb(main):001:0> require 'rexml/document'
=> true
irb(main):002:0> d=REXML::Document.new('<tata/>')
=> <UNDEFINED> ... </>
irb(main):003:0> REXML::Text.new("toto\ntutu", true, d.root)
=> "toto\ntutu"
irb(main):004:0> d.write($stdout, 2)
<tata>toto
tutu</tata>=> [<?xml ... ?>, <tata> ... </>]
En gros, je donne un petit document xml avec juste une racine, et j’ajoute un élément texte en lui passant en deuxième paramètre vrai pour lui dire de bordel, tu touche pas aux espaces ! Et comme on peut voir, ça fonctionne, il me rends bien ce que je lui ai donné, en respectant les espaces et en n’y touchant pas.
Maintenant, p111 :
irb(main):001:0> require 'rexml/document'
=> true
irb(main):002:0> d=REXML::Document.new('<tata/>')
=> <UNDEFINED> ... </>
irb(main):003:0> REXML::Text.new("toto\ntutu", true, d.root)
=> "toto\ntutu"
irb(main):004:0> d.write($stdout, 2)
<tata>
toto tutu
</tata>=> [<?xml ... ?>, <tata> ... </>]
Oh, comme c’est bizarre, j’ai beau lui avoir dit tout pareil, et ben, il m’a tout mangé mes espaces que je lui avais dit bordel t’y touche pas…
Snif, c’est bien triste tout ça, mais là, j’en ai eu assez de patcher le bordel qu’ils nous ont mis, alors, ben, j’ai arrêté de chercher, et j’ai envoyé un mail au committer FreeBSD qui avait commis ça, qu’il se débrouiller avec :-)