Wie CONAN OpenSSL sprengt

Manche Geschichten aus dem Programmierer-Alltag sind so kurios, dass sie es verdienen dokumentiert zu werden.

Und eine davon ist die Geschichte vom CONAN Build-Pfad, der das Compilieren von OpenSSL gebrochen hat.


Mit OpenSSL verbindet mich eine emotionale Hassliebe. Einerseits war diese Bibliothek früher die einzige und gleichsam beste Möglichkeit, Kryptographie von SSL bis TLS in sein Projekt zu bekommen und andererseits hat OpenSSL das aus meiner bescheuertste Build-System überhaupt.

Denn wenn man für ein Projekt in Programmiersprache A (also C) eine Hilfssprache B braucht (also Perl), dann läuft etwas gehörig schief.
Der Nachfolger libreSSL beweist außerdem, dass es auch ohne solche Kunstgriffe geht, und man nicht per Perl-Script alle Header anpassen muss.

Neulich in der Firma …

Eine neue Buildplattform kam hinzu und damit mussten diverse 3rd-Party-Libs eben für diese Plattform neu gebaut werden.
Da gibt es immer wieder ein paar Problemchen, die man mit diversen Tricks, Compilerswitches und Environment-Variablen lösen muss.

Doch beim Bauen einer statischen Version von OpenSSL unter Windows trat plötzlich folgender Fehler auf:

1 .\crypto\cversion.c(82): warning C4129: 'c': unrecognized character escape sequence
2 .\crypto\cversion.c(82): error C2022: '289': too big for character
3 .\crypto\cversion.c(82): warning C4129: 'i': unrecognized character escape sequence

Und was steht in Zeile 82 ?

 1 const char *SSLeay_version(int t)
 2 {
 3   ...
 4   if (t == SSLEAY_CFLAGS) {
 5 #ifdef CFLAGS
 6     return (CFLAGS);    /* <-- line 82 */
 7 #else
 8     return ("compiler: information not available");
 9 #endif
10   }
11   ...
12 }

Und CFLAGS sollte die Compiler-Switches enthalten, die zum Bauen des Projektes benutzt werden.

Jetzt gibt es zahlreiche andere Pipelines, die nie ein Problem mit dem Code hatten, also warum schlägt das plötzlich bei einer einzelnen Pipeline fehlt?

Vorsicht mit Windows Dateisystempfaden!

Der Compiler-Aufruf beinhaltet neben zahlreichen Steuer-Makros wie -DOPENSSL_NO_SSL2, -DSHA1_ASM usw. auch den Parameter
-IC:\conan_cache\441b83\1\include

Und dabei handelt es sich um den Include-Pfad einer CONAN-Abhängigkeit, dessen Unterverzeichnis durch einen Hash von CONAN generiert wird.

Tja … und ein \c von \conan_cache und \i von \include erklären die Warnungen, die ich bei weiterer Analyse auch in anderen Windows-Builds finden konnte.

Aber \441b83 ist ein lustiger Zufall, denn Backslash + 3-Ziffern sind in C eine Oktalzahl und \441 wird im Dezimalsystem dann zur 289.
Und 289 ist wiederum für ein Byte zu viel (weil größer 255) und so erklärt sich dann auch der Fehler mit dem String, der den Build abbricht.

Da die CONAN Hashes für die Builds einen quasi zufälligen Charakter haben, hatten wir bei den anderen Build-Pipelines einfach Glück und die erzeugten Strings hatten einfach “lustige” Zeichen in sich und generierten weitere Warnungen, doch wenn der Hash mit der Ziffer 4 beginnt und zwei weitere Ziffern folgen, hört der Spaß beim C-Compiler auf.

Lösung: CFLAGS unter Windows ausblenden

Ich passe nur ungern 3rd-Party Codes an, aber um das Problem “schnell” aus dem Weg zur räumen, habe ich einfach ein lokales Patch-File erstellt, welches die Zeilen:

1 #if defined(WIN32) && defined(CFLAGS)
2 #  undef CFLAGS
3 #endif

implantiert.
Denn schließlich kann in jeder künftigen CONAN basierten Pipeline wieder so ein lustiges Hash-Unterverzeichnis entstehen. Und ungewollte Backslashes in Strings aus dem Dateisystem sind hier generell ein Problem.

Meines Erachtens wird diese Versions-API nirgends produktiv “benutzt”, sie dient nur der Rückverfolgung des Bauprozesses der Bibliothek.

Fazit

What - the - fu** …

Nach unzähligen Jahren in der Softwareentwicklung vergeht kein Jahr, wo mir nicht wieder zig neue Varianten von Build-Systemen unterkommen, die durch Seiteneffekte den Quellcode vernudeln können.
CONAN Builds unter Windows, deren Dateipfade in Strings ins Programm geprägt werden, sind also wieder “so eine Abart”, die ich in Zukunft zu meiden versuchen werde.

Nun … ich muss sie bei meinen Codes nicht meiden, weil ich auch noch nie CFLAGS als String wo aufgenommen hätte. Aber ich werde nun bei weiteren Bibliotheken aus dem Unix Umfeld genauer aufpassen, dass sie keinen Schaden anrichten, wenn sie in Windows übernommen werden.

Denn, wer weiß schon, ob nicht irgend wo anders schon mal ein \0 aus einem Dateipfad in einem Codefragment “versehentlich” eine Backdoor aufgemacht hat, wenn ein std::string::size() dann plötzlich was anderes zurückgibt, als ein strlen() auf den gleichen char Puffer ….

Und die Moral von der Geschicht’:
CONAN Pfade speichern darf man nicht!