Open Source: Code Humor, Code Tricks, NICHT Code

Old GLib gegen New Clang


Beim Stöbern in einer vielfältigen Open-Source-Software finde ich regelmäßig alle möglichen interessanten Dinge: Manchmal ist es nur ein lustiger Kommentar, manchmal ist es im weiteren Sinne etwas Witziges. Ähnliche Sammlungen erscheinen regelmäßig sowohl im "globalen Internet" als auch in Habré - zum Beispiel gibt es bei StackOverflow eine bekannte Frage zu Kommentaren im Code, und kürzlich wurde hier eine Auswahl lustiger Namen von juristischen Personen und Toponymen veröffentlicht . Ich werde versuchen zu strukturieren und darzulegen, was ich allmählich angesammelt habe. Unter dem Strich warten Zitate von QEMU, dem Linux-Kernel und anderen auf Sie.


Linux-Kernel


Ich denke, für viele ist es kein Geheimnis, dass Briefe aus der Linux-Kernel-Mailingliste regelmäßig in Anführungszeichen zerfallen. Schauen wir uns also den Code genauer an. Und sofort überrascht uns das Kernel-Assembly-System: Wie Sie wissen, haben von Autoconf erstellte Projekte ein Makefile mit zwei Standardzielen für die Reinigung: clean und distclean . Natürlich wird der Kernel nicht mit Autoconf erstellt, und was nur menuconfig wert ist, daher gibt es hier weitere Ziele: clean , distclean und mrproper - ja, ja, Mr.Proper, ein Kernreiniger doppelt so schnell .


Apropos Konfigurationssystem: Es war einmal überrascht, als ich neben klaren Befehlen wie allnoconfig , allyesconfig (ich vermute, dass etwas sehr Debugging kompiliert werden kann, sodass ich jetzt nicht riskieren würde, es auf echte Hardware herunterzuladen. .) und allmodconfig zum mysteriösen Ziel allrandconfig . "Verspotten sie", dachte ich, dann erzählte ich meinem Freund von dieser Beobachtung, auf die er antwortete, dass es wahrscheinlich ein völlig aussagekräftiger Befehl sei, aber nicht für eine echte Montage, sondern um die Richtigkeit der Anordnung der Abhängigkeiten zwischen Optionen zu testen - wie gesagt würde nun eine Art unscharfe Konfigurationsparameter.


Es gibt jedoch Leben im Kern jenseits des Montagesystems: Dokumentation ist manchmal nicht nur technisch, sondern auch von künstlerischem Wert. Angenommen, Sie möchten Benutzer im Schlafmodus auf ihre Fragilität und das Risiko eines Datenverlusts aufmerksam machen, wenn bestimmte Regeln nicht befolgt werden. Ich würde traurig schreiben und sagen ACHTUNG: <Ersetzen Sie ein paar der langweiligsten Zeilen> . Aber der Entwickler, der das geschrieben hat, hat etwas anderes gemacht:


 Some warnings, first. * BIG FAT WARNING ********************************************************* * * If you touch anything on disk between suspend and resume... * ...kiss your data goodbye. * * If you do resume from initrd after your filesystems are mounted... * ...bye bye root partition. * [this is actually same case as above] * * ... 

Kleine Tricks


Es ist nicht überraschend, dass nicht jeder Code mit Optimierungen kompiliert werden kann: Als ich versuchte, das #error für alle Objektdateien zu erzwingen, stieß ich natürlich auf eine Entropiequelle oder etwas Ähnliches, das #error wenn die Optimierung #error war. Kryptographie ist so. Aber möchten Sie einen Code, der nicht zusammengestellt wird, wenn Sie alle Optimierungen, Inlining usw. deaktivieren? Wie ist das möglich? Und das ist so eine statische Behauptung:


 /* SPDX-License-Identifier: GPL-2.0 */ // ... /* * This function doesn't exist, so you'll get a linker error if * something tries to do an invalidly-sized xchg(). */ extern void __xchg_called_with_bad_pointer(void); static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) { unsigned long ret, flags; switch (size) { case 1: #ifdef __xchg_u8 return __xchg_u8(x, ptr); #else local_irq_save(flags); ret = *(volatile u8 *)ptr; *(volatile u8 *)ptr = x; local_irq_restore(flags); return ret; #endif /* __xchg_u8 */ // ... default: __xchg_called_with_bad_pointer(); return x; } } 

Anscheinend wird angenommen, dass diese Funktion bei jeder Verwendung mit einem konstanten Argument in nur einen switch Zweig erweitert wird, und wenn sie mit einem gültigen Argument verwendet wird, ist dieser Zweig nicht default:
In einer nicht optimierten Form verursacht diese Funktion fast absichtlich einen Verbindungsfehler ...


Wissen Sie


  • ... dass der Kernel einen Bytecode-JIT-Compiler aus dem Benutzermodus hat? Diese Technologie heißt eBPF und wird für Routing, Tracing und vieles mehr verwendet. Übrigens, wenn Sie keine Angst vor experimentellen "nuklearen" Werkzeugen haben, schauen Sie sich das bpftools-Paket an.
  • ... dass der Kernel etwa fünf Minuten Prozessorzeit benötigt? Es gibt einen solchen sendfile -Systemaufruf, der Bytes von einem Dateideskriptor in einen anderen kopiert. Wenn Sie ihm denselben Deskriptor mitteilen und den richtigen Versatz in der Datei festlegen, spult er dieselben Daten zurück, bis er 2 GB kopiert.
  • ... dass es eine Variante der vom Benutzerprozess ausgeführten Ruhezustandsarbeit gibt - ich bin nicht überrascht, wenn Sie sie auch im Netzwerkspeicher speichern können.

QEMU


Als ich Robert Love über das Linux-Kernel-Gerät las und dann in die QEMU-Quellen stieg, hatte ich im Allgemeinen ein gewisses Gefühl von Deja Vu. Es gab Listen, die nach Wert in Strukturen eingebettet waren (und nicht wie im ersten Programmierkurs, den sie lernten - durch Zeiger), und ein bestimmtes RCU-Subsystem (was es ist, habe ich immer noch nicht vollständig verstanden, aber es existiert auch im Kernel) und wahrscheinlich viel ähnlicher.


Was ist das erste, was eine nette Person an einem Projekt arbeiten möchte, um es kennenzulernen? Wahrscheinlich mit Codierungsstil. Und schon in diesem, könnte man sagen, zeremoniellen Dokument sehen wir:


 1. Whitespace Of course, the most important aspect in any coding style is whitespace. Crusty old coders who have trouble spotting the glasses on their noses can tell the difference between a tab and eight spaces from a distance of approximately fifteen parsecs. Many a flamewar has been fought and lost on this issue. 

Hier ist die ewige Frage nach der maximalen Zeilenlänge:


 Lines should be 80 characters; try not to make them longer. ... Rationale: - Some people like to tile their 24" screens with a 6x4 matrix of 80x24 xterms and use vi in all of them. The best way to punish them is to let them keep doing it. ... 

(Hmm ... Es ist auf jeder Achse doppelt so groß als ich es manchmal benutze. Ist es so Linux HD?)


Es gibt noch viel Interessantes - lesen .


Und wieder Tricks


Sie sagen, C sei eine einfache Sprache. Aber wenn es gut ist, pervers zu sein, können Sie die Wunder der Codegenerierung zur Kompilierungszeit ohne Scala oder sogar C ++ zeigen.


Beispielsweise ist die Datei softmmu_template.h in der QEMU-Codebasis softmmu_template.h . Als ich diesen Namen sah, dachte ich, dass er in meine TCG-Backend-Implementierung kopiert und optimiert werden sollte, bis die richtige TLB-Implementierung herauskam. Egal wie! So verwenden Sie es richtig :


accel / tcg / cputlb.h:


 define DATA_SIZE 1 #include "softmmu_template.h" #define DATA_SIZE 2 #include "softmmu_template.h" #define DATA_SIZE 4 #include "softmmu_template.h" #define DATA_SIZE 8 #include "softmmu_template.h" 

Wie Sie sehen können, Fingerspitzengefühl und kein C ++. Dies ist jedoch ein ziemlich einfaches Beispiel. Wie wäre es mit etwas Komplizierterem?


Es gibt eine solche Datei: tcg / tcg-opc.h . Sein Inhalt ist ziemlich mysteriös und sieht ungefähr so ​​aus:


 ... DEF(mov_i32, 1, 1, 0, TCG_OPF_NOT_PRESENT) DEF(movi_i32, 1, 0, 1, TCG_OPF_NOT_PRESENT) DEF(setcond_i32, 1, 2, 1, 0) DEF(movcond_i32, 1, 4, 1, IMPL(TCG_TARGET_HAS_movcond_i32)) /* load/store */ DEF(ld8u_i32, 1, 1, 1, 0) DEF(ld8s_i32, 1, 1, 1, 0) DEF(ld16u_i32, 1, 1, 1, 0) DEF(ld16s_i32, 1, 1, 1, 0) ... 

In der Tat ist alles sehr einfach - es wird so verwendet:


tcg / tcg.h:


 typedef enum TCGOpcode { #define DEF(name, oargs, iargs, cargs, flags) INDEX_op_ ## name, #include "tcg-opc.h" #undef DEF NB_OPS, } TCGOpcode; 

Oder so:


tcg / tcg-common.c:


 TCGOpDef tcg_op_defs[] = { #define DEF(s, oargs, iargs, cargs, flags) \ { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags }, #include "tcg-opc.h" #undef DEF }; 

Es ist sogar seltsam, dass im Laufe anderer Anwendungsfälle keine gefunden wurde. Und beachten Sie, dass es in diesem Fall keine kniffligen Skripte für die Codegenerierung gibt - nur C, nur Hardcore.


Wissen Sie


  • ... dass QEMU nicht nur im Emulationsmodus eines kompletten Systems arbeiten kann, sondern auch einen separaten Prozess für eine andere Architektur ausführen kann, die mit dem Host-Kernel kommuniziert?

Java, JVM und alles in allem


Was bin ich alles über Linux? Lassen Sie uns über etwas plattformübergreifendes sprechen. Zum Beispiel über die JVM. Nun, über GraalVM haben wahrscheinlich viele Entwickler in diesem Ökosystem bereits gehört. Wenn Sie nicht gehört haben, dann auf den Punkt gebracht: Es ist episch. Nachdem wir über Graal gesprochen haben, gehen wir weiter zur guten alten JVM.


Manchmal muss die JVM alle verwalteten Threads stoppen - die Garbage Collection-Phase ist so eingängig oder etwas anderes - aber das Problem ist, dass Sie Threads nur an sogenannten Sicherheitspunkten stoppen können. Wie hier beschrieben , nimmt eine normale Überprüfung einer globalen Variablen viel Zeit in Anspruch, einschließlich einer Art Schamanismus mit Gedächtnisbarrieren. Was haben die Entwickler gemacht? Sie beschränkten sich auf einen variablen Messwert.


Fast wie in HQ9 +

Es gibt so eine Comic-Sprache - HQ9 + . Es wurde als "sehr praktische pädagogische Programmiersprache" entwickelt, dh es ist sehr einfach, die typischen Aufgaben auszuführen, die die Schüler stellen:


  • Der Befehl 'H' Interpreter druckt Hallo, Welt!
  • beim Befehl 'Q' wird der Text des Programms selbst gedruckt (quine)
  • auf '9' druckt er die texte für 99 flaschen bier
  • um 'i' erhöht es die Variable i um eins
  • er kann nichts anderes tun, aber warum?

Wie erreicht die JVM das Ziel mit einer Anweisung? Es ist jedoch sehr einfach: Wenn ein Stopp erforderlich ist, wird die Anzeige für die Speicherseite mit dieser Variablen entfernt. Die Flows fallen auf SIGSEGV, und die JVM parkt sie und hält sie an, wenn die „Wartung“ endet. Ich erinnere mich an StackOverflow, als ich nach einem Interview gefragt wurde. Wie stürzt eine JVM ab? antwortete:


JNI. Tatsächlich ist bei JNI ein Absturz die Standardbetriebsart. Sie müssen besonders hart arbeiten, damit es nicht abstürzt.

Scherz als Scherz, und manchmal ist es in der JVM wirklich so.


Nun, da ich die Codegenerierung in Scala erwähnt habe und wir gerade über dieses Ökosystem sprechen, ist hier eine interessante Tatsache für Sie: Die Codegenerierung in Scala (die Makros enthält) ist folgendermaßen aufgebaut: Sie schreiben Code in Scala mithilfe der API Compiler und kompilieren Sie es. Dann übergeben Sie beim nächsten Start des Compilers einfach den resultierenden Codegenerator an den Klassenpfad des Compilers selbst, und dieser, der eine spezielle Direktive sieht, ruft ihn auf, indem er die während des Aufrufs empfangenen Syntaxbäume übergibt. Als Antwort erhält er einen AST, der am Ort des Anrufs ersetzt werden muss.


Merkmale von Lizenzierungsideologien


Ich mag die Ideologie der freien Software, aber sie hat auch einige lustige Funktionen.


Vor ungefähr zehn Jahren habe ich einmal meinen Debian-Stall aktualisiert und, unter Berücksichtigung der Syntax eines Befehls, gewöhnlich den man <> eingegeben, der eine ausführliche Beschreibung wie „[Programmname] ist ein Programm mit unter Lizenz vertriebener Dokumentation GNU GFDL mit unveränderlichen Abschnitten, die nicht DFSG-frei sind. " Sie sagen, dass dieses Programm von einigen bösen Besitzern von einigen FSF geschrieben wurde ... (Jetzt ist die Diskussion Google.)


Und einige kleine, aber wichtige Bibliotheken werden von einigen Distributionen als nicht freie Software angesehen, da der Autor an die standardmäßige zulässige Lizenz schrieb, dass dieses Programm zum Guten und nicht zum Bösen verwendet werden sollte . Lachen, Lachen und auch ich hätten wahrscheinlich Angst, so etwas in die Produktion aufzunehmen - man weiß nie, was der Autor über Gut und Böse denkt.


Sonstiges


Merkmale des internationalen Compilerbaus während des Moore-Gesetzes


Die harten LLVM-Entwickler haben die unterstützte Ausrichtung eingeschränkt:


Die maximale Ausrichtung beträgt 1 << 29.

Wie sie sagen, bringt es Sie zuerst zum Lachen und dann zum Nachdenken : der erste Gedanke - aber wer braucht eine Ausrichtung bei 512 MiB. Dann las ich über die Entwicklung des Kernels in Rust und dort schlagen sie vor, eine "Seitentabellen" -Struktur zu erstellen, die auf 4096 Bytes ausgerichtet ist. Und wie liest du Wikipedia, also dort allgemein:


Eine vollständige Zuordnungshierarchie von 4 KB-Seiten für den gesamten 48-Bit-Speicherplatz würde etwas mehr als 512 GB Speicher benötigen (etwa 0,195% des virtuellen Speicherplatzes von 256 TB).

Formatversion - wie speichern?


Einmal habe ich mich entschlossen herauszufinden, warum der Export in einem Programm nicht funktioniert, aber es funktioniert ... oder nicht?


Nachdem ich die Backend-Befehle manuell gestartet hatte, wurde mir klar, dass im Prinzip alles in Ordnung ist. Nur die Version sollte als "2.0" übertragen werden, aber nur "2". Ich double getVersion() eine triviale Korrektur durch Bearbeiten einer String-Konstante und finde die Funktion double getVersion() - aber was, Dur, Moll ist, ist sogar ein Punkt! Am Ende war jedoch alles nicht viel komplizierter als erwartet, ich nur verbesserte Ausgabegenauigkeit Leiten Sie den Datentyp weiter und leiten Sie die Zeilen weiter.


Über den Unterschied zwischen Theoretikern und Praktikern


Meiner Meinung nach habe ich irgendwo auf Habré bereits eine Übersetzung eines Artikels über die minimalen Abstürze beim Start gesehen, aber immer noch ein kompiliertes Programm in C? int main; - Es gibt ein Hauptsymbol, und technisch können Sie die Kontrolle darauf übertragen. sirikid hat richtig bemerkt, dass hier auch int bytes überflüssig sind. Selbst wenn es sich um ein Programm mit einer Größe von 9 Bytes handelt, ist es im Allgemeinen besser, die Behauptungen nicht zu streuen, dass es das kleinste ist ... Zwar wird das Programm fallen, aber dies entspricht vollständig den Regeln.


Wir wissen also, wie man das fallen lässt, was funktionieren soll, aber was ist mit dem Starten eines nicht startenden?


 $ ldd /bin/ls linux-vdso.so.1 (0x00007fff93ffa000) libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f0b27664000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0b2747a000) libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f0b27406000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f0b27400000) /lib64/ld-linux-x86-64.so.2 (0x00007f0b278e9000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0b273df000) $ /lib/x86_64-linux-gnu/libc.so.6 

... und libc ihn menschliche Stimme ::


 GNU C Library (Ubuntu GLIBC 2.28-0ubuntu1) stable release version 2.28. Copyright (C) 2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compiled by GNU CC version 8.2.0. libc ABIs: UNIQUE IFUNC ABSOLUTE For bug reporting instructions, please see: <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>. 

Programmierer spielen Golf


Auf StackExchange gibt es eine ganze Website, die sich Code Golf widmet - Wettbewerbe mit dem Stil "Lösen Sie dieses Problem mit einer minimalen Strafe, abhängig von der Größe des Quellcodes." Das Format selbst beinhaltet sehr ausgefeilte Lösungen, aber manchmal werden sie sehr ausgefeilt. Daher wurde in einer der Fragen eine Sammlung von standardmäßigen verbotenen Lücken gesammelt. Ich mag dieses besonders:


Verwenden von MetaGolfScript
MetaGolfScript ist eine Familie von Programmiersprachen. Das leere Programm in MetaGolfScript-209180605381204854470575573749277224 gibt beispielsweise "Hallo Welt!" Aus.

In einer Zeile



Woher kommt schließlich der Titel des Artikels? Dies ist ein paraphrasierter Trick aus der Ausgabe des emcc Compilers von Emscripten :


 $ emcc --help ... emcc: supported targets: llvm bitcode, javascript, NOT elf (autoconf likes to see elf above to enable shared object support) 

Source: https://habr.com/ru/post/de437832/


All Articles