Sumber terbuka: humor kode, trik kode, BUKAN kode

GLib Tua vs Dentang Baru


Mengaduk-aduk dalam beragam perangkat lunak sumber terbuka, saya secara berkala menemukan segala macam hal menarik: kadang-kadang itu hanya komentar lucu, kadang-kadang itu sesuatu yang jenaka dalam arti yang lebih luas. Koleksi serupa secara berkala muncul baik di "Internet global" dan di Habré - misalnya, ada pertanyaan terkenal tentang StackOverflow tentang komentar dalam kode, dan pilihan nama lucu badan hukum dan toponim baru-baru ini diterbitkan di sini. Saya akan mencoba menyusun dan menyusun apa yang saya kumpulkan secara bertahap. Di bawah potongan, kutipan dari QEMU, kernel Linux, dan banyak lagi menunggu untuk Anda.


Kernel Linux


Saya pikir bagi banyak orang bukan rahasia lagi bahwa surat-surat dari Linux Kernel Mailing List secara berkala menyimpang menjadi tanda kutip. Jadi mari kita lihat kodenya dengan lebih baik. Dan segera, sistem rakitan kernel menemui kita dengan kejutan: seperti yang Anda tahu, proyek yang dibangun oleh Autoconf memiliki Makefile dengan dua tujuan standar untuk pembersihan: clean dan clean . Secara alami, kernel tidak dibangun menggunakan Autoconf, dan apa yang hanya menuconfig bernilai, jadi ada lebih banyak tujuan di sini: clean , distclean dan mrproper - ya, ya, Mr.Proper, pembersih inti dua kali lebih cepat .


Berbicara tentang sistem konfigurasi: suatu ketika saya terkejut ketika saya menemukannya selain perintah yang jelas seperti allnoconfig , allyesconfig (Saya menduga bahwa sesuatu yang sangat debugging dapat dikompilasi, jadi sekarang saya tidak akan mengambil risiko mengunduhnya di perangkat keras nyata .. .) dan allmodconfig ke target misterius allrandconfig . "Apakah mereka mengejek," pikir saya, kemudian saya memberi tahu teman saya tentang pengamatan ini, dan dia menjawab bahwa itu mungkin perintah yang benar-benar bermakna, tetapi tidak untuk perakitan nyata, tetapi untuk menguji kebenaran pengaturan dependensi antara opsi - seperti yang saya katakan akan sekarang, semacam parameter konfigurasi fuzzing.


Namun, ada inti kehidupan di luar sistem perakitan: dokumentasi kadang-kadang tidak hanya teknis, tetapi juga, dari jenis, nilai artistik. Misalkan Anda ingin mengingatkan pengguna mode tidur tentang kerapuhannya dan risiko kehilangan data jika aturan tertentu tidak diikuti. Saya akan menulis dengan sedih, mengatakan PERHATIAN: <gantikan beberapa baris yang paling membosankan> . Tetapi pengembang yang menulis ini melakukan sesuatu yang berbeda:


 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] * * ... 

Trik kecil


Tidak mengherankan bahwa tidak setiap kode dapat dikompilasi dengan optimisasi: ketika saya mencoba memaksa mereka untuk dihidupkan untuk semua file objek, saya secara alami bertemu dengan beberapa sumber entropi atau sesuatu yang serupa yang #error jika optimasi dihidupkan. Nah, kriptografi seperti itu. Tetapi apakah Anda menginginkan kode yang tidak akan dikumpulkan jika Anda mematikan semua optimisasi, inlining, dll.? Bagaimana ini mungkin? Dan ini adalah pernyataan yang statis:


 /* 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; } } 

Diasumsikan, rupanya, bahwa untuk setiap penggunaan dengan argumen konstan, fungsi ini akan berkembang menjadi hanya satu cabang switch , dan ketika digunakan dengan argumen yang valid , cabang ini tidak akan menjadi default:
Dalam bentuk yang tidak dioptimalkan, fungsi ini akan menyebabkan kesalahan tautan hampir oleh ...


Apakah anda tahu


  • ... bahwa kernel memiliki bytecode JIT compiler dari mode pengguna? Teknologi ini disebut eBPF dan digunakan untuk routing, penelusuran, dan banyak lagi. Omong-omong, jika Anda tidak takut dengan alat "nuklir" eksperimental, lihat paket bpftools.
  • ... bahwa kernel dapat berjalan selama sekitar lima menit waktu prosesor? Ada semacam panggilan sistem sendfile yang menyalin byte dari satu file descriptor ke yang lain. Jika Anda memberi tahu deskriptor yang sama dan mengatur offset yang benar dalam file, ia akan memundurkan data yang sama hingga ia menyalin 2 GB.
  • ... bahwa ada varian pekerjaan hibernasi yang dilakukan oleh proses pengguna - saya tidak akan terkejut jika Anda dapat menyimpannya ke penyimpanan jaringan juga.

QEMU


Secara umum, ketika saya membaca Robert Love tentang perangkat kernel Linux, dan kemudian naik ke sumber QEMU, saya merasakan deja vu. Ada daftar yang tertanam dalam struktur berdasarkan nilai (dan tidak seperti dalam kursus pemrograman awal yang mereka pelajari - melalui pointer), dan subsistem RCU tertentu (apa itu, saya masih belum sepenuhnya mengerti, tetapi juga ada di kernel) dan, mungkin jauh lebih mirip.


Apa hal pertama yang ingin dikerjakan oleh orang yang rapi dalam suatu proyek? Mungkin dengan gaya Coding. Dan sudah dalam hal ini, bisa dikatakan, seremonial, dokumen, kita melihat:


 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. 

Inilah pertanyaan abadi tentang panjang garis maksimum:


 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 ... Ini dua kali lebih besar pada setiap sumbu daripada yang kadang-kadang saya gunakan. Apakah itu Linux HD?)


Masih banyak yang menarik - baca .


Dan lagi trik


Mereka mengatakan C adalah bahasa tingkat rendah. Tetapi jika itu bagus untuk diselewengkan, Anda dapat menunjukkan keajaiban pembuatan kode waktu kompilasi tanpa Scala atau bahkan C ++.


Misalnya, file softmmu_template.h softmmu_template.h di basis kode QEMU. Ketika saya melihat nama ini, saya berpikir bahwa itu seharusnya disalin ke implementasi backend TCG saya dan tweak sampai implementasi TLB yang benar keluar dari itu. Bagaimanapun caranya! Berikut cara menggunakannya dengan benar :


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" 

Seperti yang Anda lihat, sulap dan tidak ada C ++. Tetapi ini adalah contoh yang cukup sederhana. Bagaimana dengan sesuatu yang lebih rumit?


Ada file seperti itu: tcg / tcg-opc.h . Isinya agak misterius dan terlihat seperti ini:


 ... 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) ... 

Faktanya, semuanya sangat sederhana - digunakan seperti ini:


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; 

Atau lebih:


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 }; 

Bahkan aneh bahwa selama kasus penggunaan lain tidak ditemukan. Dan perhatikan, dalam hal ini tidak ada skrip yang rumit untuk pembuatan kode - hanya C, hanya hardcore.


Apakah anda tahu


  • ... bahwa QEMU dapat bekerja tidak hanya dalam mode emulasi sistem yang lengkap, tetapi juga menjalankan proses terpisah untuk arsitektur lain yang berkomunikasi dengan kernel host?

Java, JVM dan semuanya


Apa yang saya semua tentang Linux? Mari kita bicara tentang sesuatu lintas platform. Tentang JVM, misalnya. Nah, tentang GraalVM, mungkin, banyak pengembang di ekosistem ini sudah mendengar. Jika Anda belum pernah mendengarnya, maka secara singkat: ini epik. Jadi, setelah berbicara tentang Graal, mari kita beralih ke JVM tua yang baik.


Terkadang JVM perlu menghentikan semua utas yang dikelola - tahap pengumpulan sampah sangat menarik atau sesuatu yang lain - tetapi masalahnya adalah, Anda bisa menghentikan utas hanya pada apa yang disebut titik aman. Seperti dijelaskan di sini , pemeriksaan normal variabel global membutuhkan banyak waktu, termasuk semacam perdukunan dengan hambatan memori. Apa yang dilakukan pengembang? Mereka membatasi diri pada satu bacaan variabel.


Hampir seperti di HQ9 +

Ada bahasa komik seperti itu - HQ9 + . Itu dibuat sebagai "bahasa pemrograman pendidikan yang sangat nyaman", yaitu, sangat sederhana untuk melakukan tugas-tugas khas yang ditanyakan siswa:


  • perintah 'H' interpreter mencetak Halo, Dunia!
  • pada perintah 'Q' mencetak teks dari program itu sendiri (quine)
  • pada '9' dia mencetak lirik untuk 99 botol bir
  • dengan 'i' itu menambah variabel i per satu
  • dia tidak bisa melakukan hal lain, tetapi mengapa? ..

Bagaimana JVM mencapai tujuan dengan satu instruksi? Tapi itu sangat sederhana - jika perlu untuk berhenti, itu menghilangkan tampilan untuk halaman memori dengan variabel ini - utas jatuh pada SIGSEGV, dan JVM memarkirkannya dan menjeda mereka ketika "pemeliharaan" berakhir. Saya ingat di StackOverflow ketika ditanya dari sebuah wawancara. Bagaimana Anda menabrak JVM? dijawab:


JNI. Bahkan, dengan JNI, menabrak adalah mode operasi standar. Anda harus bekerja ekstra keras agar tidak crash.

Bercanda sebagai lelucon, dan terkadang dalam JVM itu benar-benar.


Nah, karena saya menyebutkan pembuatan kode dalam Scala, dan kami hanya berbicara tentang ekosistem ini sekarang, inilah fakta menarik untuk Anda: pembuatan kode dalam Scala (yang memiliki makro) disusun seperti ini: Anda menulis kode dalam Scala menggunakan API kompiler, dan kompilasi. Kemudian, pada awal kompilator berikutnya, Anda cukup meneruskan pembuat kode yang dihasilkan ke classpath dari kompiler itu sendiri, dan yang, melihat arahan khusus, memanggilnya, melewati pohon sintaksis yang diterima selama panggilan. Sebagai tanggapan, ia menerima AST, yang harus diganti di tempat panggilan.


Fitur ideologi perizinan


Saya suka ideologi perangkat lunak bebas, tetapi juga memiliki beberapa fitur yang menyenangkan.


Suatu kali, sekitar sepuluh tahun yang lalu, saya memperbarui stabil Debian saya dan, memikirkan sintaksis dari beberapa perintah, biasanya mengetik man <> , yang menerima deskripsi lengkap seperti “[nama program] adalah program dengan dokumentasi yang didistribusikan di bawah lisensi GNU GFDL dengan bagian yang tidak dapat diubah, yang tidak bebas DFSG. " Mereka mengatakan bahwa program ini ditulis oleh beberapa pemilik jahat dari beberapa FSF ... (Sekarang diskusi adalah google.)


Dan beberapa perpustakaan kecil, tetapi penting dianggap oleh beberapa distribusi sebagai perangkat lunak tidak bebas, karena penulis menulis ke lisensi permisif standar bahwa program ini harus digunakan untuk kebaikan dan bukan untuk kejahatan . Tertawa, tawa, dan saya juga mungkin akan takut untuk mengambil hal seperti itu dalam produksi - Anda tidak pernah tahu apa yang penulis pikirkan tentang yang baik dan yang jahat.


Lain-lain


Fitur bangunan kompiler internasional selama Hukum Moore


Pengembang LLVM yang keras telah membatasi penyelarasan yang didukung:


Penjajaran maksimum adalah 1 << 29.

Seperti yang mereka katakan, itu membuat Anda tertawa lebih dulu, dan kemudian berpikir : pikiran pertama - tetapi siapa yang butuh keselarasan pada 512 MiB. Lalu saya membaca tentang pengembangan kernel di Rust , dan di sana mereka mengusulkan untuk membuat struktur "halaman tabel" yang disejajarkan dengan 4.096 byte. Dan bagaimana Anda membaca Wikipedia, sehingga umumnya ada:


Hirarki pemetaan penuh 4 halaman KB untuk seluruh ruang 48-bit akan memakan sedikit lebih dari 512 GB memori (sekitar 0,195% dari ruang virtual 256 TB).

Format versi - bagaimana cara menyimpan?


Suatu ketika saya memutuskan untuk mencari tahu mengapa ekspor tidak bekerja dalam satu program, tetapi ternyata berhasil ... Atau tidak?


Setelah memulai perintah backend secara manual, saya menyadari bahwa, pada prinsipnya, semuanya beres, hanya versi yang harus dikirimkan sebagai "2.0", tetapi hanya "2" yang keluar. Mengantisipasi koreksi sepele dengan mengedit konstanta string, saya menemukan fungsi double getVersion() - tetapi apa, mayor, minor, bahkan ada titik! Namun, pada akhirnya, semuanya diputuskan tidak jauh lebih rumit dari yang diharapkan, aku hanya meningkatkan akurasi keluaran Meneruskan tipe data dan meneruskan garis.


Tentang perbedaan antara ahli teori dan praktisi


Menurut pendapat saya, di suatu tempat di Habré saya sudah melihat terjemahan dari sebuah artikel tentang apa itu crash minimal pada saat startup, tetapi masih merupakan program yang dikompilasi di C? int main; - ada simbol main , dan secara teknis , Anda dapat mentransfer kontrol ke sana. sirikid dengan benar memperhatikan bahwa bahkan byte int tidak perlu di sini. Secara umum, bahkan berbicara tentang program berukuran 9 byte, lebih baik tidak menyebarkan klaim bahwa itu adalah yang terkecil ... Benar, programnya akan jatuh, tetapi ini sepenuhnya konsisten dengan aturan.


Jadi, kita tahu bagaimana menjatuhkan apa yang harus bekerja, tetapi bagaimana dengan meluncurkan yang tidak meluncurkan?


 $ 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 

... dan libc dia suara manusia :


 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>. 

Programmer bermain golf


Ada seluruh situs di StackExchange yang ditujukan untuk Golf Golf - kompetisi dengan gaya "Selesaikan masalah ini dengan penalti minimum, tergantung pada ukuran kode sumber." Formatnya sendiri melibatkan solusi yang sangat canggih, tetapi terkadang mereka menjadi sangat canggih. Oleh karena itu, dalam salah satu pertanyaan , kumpulan celah standar yang dilarang dikumpulkan. Saya terutama menyukai yang ini:


Menggunakan MetaGolfScript
MetaGolfScript adalah keluarga bahasa pemrograman. Sebagai contoh, program kosong di MetaGolfScript-209180605381204854470575573749277224 mencetak "Halo, Dunia!".

Dalam satu baris



Akhirnya, dari mana judul artikel itu berasal? Ini adalah trik yang diparafrasekan dari output kompilator emcc dari 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/id437832/


All Articles