1 poin oleh GN⁺ 2024-09-30 | 1 komentar | Bagikan ke WhatsApp
  • Sistem glibc 32-bit dapat gagal mengambil waktu saat ini atau memanggil stat() setelah tahun 2038, sehingga Gentoo membutuhkan jalur migrasi yang aman ke time_t 64-bit
  • time64 di glibc harus digunakan bersama Large File Support (LFS), dan di lingkungan 32-bit terdapat ABI lama, ABI LFS, serta ABI LFS+time64 secara berdampingan
  • Jika time_t masuk ke API, struktur, atau argumen fungsi, perubahan lebar tipe dapat menyebabkan ABI rusak, sehingga pencampuran biner time32 dan time64 dapat memicu perilaku runtime yang salah dan risiko keamanan
  • Sebagai distribusi berbasis source, Gentoo dapat menyisakan sistem yang setengah bermigrasi karena kegagalan saat rebuild @world atau dependensi melingkar
  • Setelah koreksi 2024-09-30, perubahan libdir saja tidak lagi cukup; penanda time64 yang mencakup dynamic loader dan berbagai toolchain bahasa tetap menjadi kendala utama

Masalah tahun 2038 dan cakupan transisi time64

  • Aplikasi 32-bit yang memakai time_t 32-bit pada tahun 2038 dapat menerima galat -1 alih-alih waktu saat ini, atau gagal menjalankan stat() pada file
  • Arah dasar transisi adalah mengubah time_t menjadi tipe 64-bit
    • musl sudah melakukan transisi ini
    • glibc mendukungnya sebagai opsi
    • Beberapa distribusi seperti Debian sudah bertransisi
  • Distribusi berbasis source seperti Gentoo membuat pengguna membangun ulang sistemnya sendiri, sehingga waktu paket berada dalam keadaan ABI yang berbeda harus diperkecil
  • Risiko inti adalah perubahan lebar time_t merusak ABI
    • Jika API library memiliki time_t, semua kode yang ditautkan ke library tersebut harus memakai lebar tipe yang sama
    • Mengubah hanya sebagian ke time64 bukanlah cara yang aman

LFS dan tiga sub-ABI 32-bit

  • Pada arsitektur 32-bit, sejak dulu sudah ada masalah lebar tipe terkait file
    • off_t digunakan untuk offset file
    • ino_t digunakan untuk nomor inode
    • Semula keduanya berlebar 32-bit, sehingga file lebih besar dari 2 GiB atau nomor inode yang melampaui rentang 32-bit menjadi bermasalah
  • Untuk mengatasinya, Large File Support (LFS) diperkenalkan
    • Mengubah off_t dan ino_t menjadi varian 64-bit
    • Di glibc, hingga kini ini tetap bersifat opsional
    • Banyak paket telah mengaktifkan LFS di upstream dan menangani kerusakan ABI, tetapi masalahnya belum sepenuhnya selesai
  • Dukungan time64 di glibc mengharuskan penggunaan LFS, sehingga struktur ini menyelesaikan masalah ukuran file dan waktu secara bersamaan
  • Pada sistem 32-bit terdapat tiga sub-ABI
    • ABI lama: tipe 32-bit
    • LFS: off_t 64-bit, ino_t 64-bit, time_t 32-bit
    • time64: LFS + time_t 64-bit
  • Satu build glibc kompatibel dengan ketiga varian, tetapi library yang memakai tipe-tipe ini dalam API tidak dapat mencampur ketiga varian tersebut

Bagaimana perubahan ABI benar-benar merusak program

  • Ketika time_t berubah dari 32-bit menjadi 64-bit, layout struktur ikut berubah
    • Pada contoh struktur dengan urutan int a, time_t b, int c, offset c berbeda antara time_t 32-bit dan time_t 64-bit
    • Jika biner time32 dan time64 dicampur, program dapat membaca atau menulis field yang salah, bahkan memungkinkan akses di luar batas
  • Ukuran struct stat juga berbeda tergantung ABI
    • Default glibc x86 32-bit: 88 byte
    • LFS: 96 byte
    • LFS + time64: 108 byte
  • Bahkan tanpa memakai struktur, masalah muncul pada argumen fungsi
    • Di x86, argumen fungsi diteruskan melalui stack
    • Jika salah satu argumen adalah time_t, posisi stack argumen-argumen berikutnya berubah
  • Dalam eksperimen contoh, nilainya rusak ketika program time32 ditautkan ke library yang dibangun ulang sebagai time64
    • Output semula adalah a = 1, nilai waktu yang normal, c = 3
    • Jika hanya library yang dibangun ulang dengan -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64, b dan c ditafsirkan secara keliru
  • Saat ini tidak ada perlindungan praktis untuk mencegah pencampuran ABI seperti ini, sehingga dapat menimbulkan kerusakan runtime dan masalah keamanan

Mengapa transisi Gentoo lebih sulit

  • Distribusi biner membangun ulang semua paket, lalu pengguna melakukan upgrade dalam tahap yang relatif atomik
    • Repositori pihak ketiga atau program build lokal tetap dapat menimbulkan masalah, tetapi keseluruhan prosesnya relatif aman
  • Gentoo harus mengubah ABI di tempat sambil membangun ulang @world
    • Di antara waktu dua paket masing-masing dibangun ulang, ABI yang tidak kompatibel dapat bercampur
    • Kegagalan sebagian rebuild dapat meninggalkan sistem dalam keadaan setengah bermigrasi
    • Karena dependensi melingkar, membangun ulang paket dependensi dapat merusak build tool, sehingga rebuild berikutnya menjadi mustahil

Mitigasi yang sedang dipertimbangkan

  • Ada tiga arah yang sedang dibahas
    • Mengubah tuple platform CHOST untuk membedakan ABI baru dari ABI 32-bit lama
    • Mengubah libdir ABI baru agar library yang dibangun ulang dipasang terpisah dari library lama
    • Memperkenalkan pembedaan ABI tingkat biner agar biner dari sub-ABI berbeda tidak saling ditautkan
  • Ketiga metode ini dapat diimplementasikan secara cukup independen, tetapi sebagian mungkin saling bergantung
  • String contoh dalam tulisan ini belum tentu merupakan string aktual dari solusi akhir

Membedakan ABI dengan CHOST

  • Tuple platform mengidentifikasi platform target toolchain, dan di Gentoo juga digunakan untuk membedakan ABI secara unik demi dukungan multilib
  • Tuple terdiri dari empat bagian: arsitektur, vendor, sistem operasi, dan libc
    • Contoh: i386-pc-linux-gnu
    • Contoh: i686-pc-linux-gnu
    • Contoh: i686-unknown-linux-gnu
  • Saat memperkenalkan ABI baru, pernah digunakan cara mengubah field vendor atau menambahkan penanda ABI pada field libc
    • Pada ABI ARM hardfloat, dulu dipakai bentuk seperti armv7a-hardfloat-linux-gnueabi dan armv7a-unknown-linux-gnueabihf
  • ABI time64 juga memiliki opsi serupa
    • i686-gentoo_t64-linux-gnu
    • i686-pc-linux-gnut64
    • armv7a-gentoo_t64-linux-gnueabihf
    • armv7a-unknown-linux-gnueabihft64
  • Perubahan tuple tampaknya tidak akan membutuhkan banyak patch
    • GNU toolchain dan GNU build system mengabaikan bagian setelah gnu pada field libc
    • Clang perlu dipatch agar otomatis memilih ABI yang benar sesuai tuple

Perubahan libdir dan preserved-libs

  • libdir adalah nama default direktori instalasi library
    • Default umum adalah lib
    • Pada arsitektur padanan 64-bit, secara konvensi sering dipakai lib64
    • ABI x32 pada x86 memakai libx32, ABI n32 pada MIPS memakai lib32
  • Untuk ABI 32-bit time64, sedang dipertimbangkan mengubah libdir dari lib menjadi nilai seperti libt64
  • libdir terpisah menjadi mekanisme untuk mengurangi pencampuran ABI selama transisi
    • Mengurangi risiko executable time64 secara tidak sengaja ditautkan ke library time32
    • Library time32 dapat dipertahankan melalui fitur preserved-libs milik Portage
    • Secara opsional, profil multilib time32 + time64 dapat disediakan untuk menjaga kompatibilitas dengan aplikasi pra-build time32 yang sudah ada
  • Dengan preserved-libs, executable lama terus memakai library time32 sampai dibangun ulang, sementara library yang dibangun ulang sebagai time64 dipasang ke libdir baru
  • Perubahan libdir membutuhkan patch toolchain
    • glibc dapat diperlakukan khusus karena satu set library yang sama valid untuk beberapa sub-ABI
    • Mungkin diperlukan ld.so terpisah agar .interp milik executable time64 merujuk ke ld.so untuk time64
  • Untuk dukungan multilib yang benar, tuple platform yang unik untuk ABI tersebut juga diperlukan

Penandaan inkompatibilitas tingkat biner

  • Mencampur biner dari ABI berbeda umumnya harus dicegah oleh linker atau dynamic loader
    • Jika program 64-bit ditautkan ke library 32-bit, linker menolak dengan file in wrong format
    • Dynamic loader juga menolak dengan galat seperti wrong ELF class: ELFCLASS32
  • Beberapa mekanisme digunakan untuk pembedaan ABI yang ada
    • ELFCLASS32 dan ELFCLASS64
    • Machine identifier seperti EM_386 dan EM_X86_64
    • Field flags pada ARM dan MIPS
    • Attribute section khusus arsitektur
  • time32 dan time64 juga memerlukan mekanisme serupa, tetapi ini tidak sederhana
    • Tampaknya tidak ada mekanisme generik yang dapat dipakai ulang
    • Diperlukan solusi yang sesuai untuk banyak arsitektur
    • Menambahkan ELF note section baru dan mengimplementasikan dukungan toolchain tampak sebagai kandidat yang realistis
  • Kemungkinan pengguna menonaktifkan perlindungan juga harus dipertimbangkan
    • Jika software pra-build tanpa source tidak memanggil API yang memakai time_t, ia mungkin tetap bisa berjalan dengan library sistem
    • Memblokirnya tanpa syarat bisa menjadi obat yang lebih buruk daripada penyakitnya
  • Dengan libdir terpisah, pemeriksaan QA nonfatal yang relatif sederhana dapat dibuat
    • Membedakan executable time64 melalui .interp
    • Memastikan program time32 tidak memuat library dari libt64
    • Memastikan program time64 tidak memuat library langsung dari lib

Batasan aplikasi 32-bit pra-build

  • Terpisah dari paket yang dibangun dari source, pada x86 dan PowerPC ada aplikasi lama yang hanya tersedia sebagai biner pra-build
    • Terutama software proprietary dan game lama
  • Aplikasi ini menghadapi baik masalah kompatibilitas dengan library sistem maupun masalah tahun 2038 itu sendiri
  • Untuk masalah kompatibilitas, struktur multilib yang ada memberi sebagian solusi
    • Untuk mendukung software 32-bit di amd64, sudah ada layout multilib dan mekanisme untuk membangun beberapa versi library
    • Ini dapat diperluas dengan membedakan abi_x86_32 dan abi_x86_t64
    • Profil x86 multilib baru yang mendukung kedua ABI dapat dibuat
  • Kegagalan program 32-bit itu sendiri setelah tahun 2038 tetap menjadi masalah yang lebih sulit
    • Mengendalikan waktu sistem dengan faketime adalah salah satu opsi
    • Menjalankan VM yang waktunya diputar ke masa lalu juga memungkinkan

Koreksi 2024-09-30: libdir saja tidak cukup

  • Rancangan awal terlalu optimistis, dan perubahan libdir saja sulit menghasilkan pemisahan yang stabil
  • Karena semua libdir tercantum dalam ld.so.conf, kita tidak dapat bergantung pada cara meng-hardcode path libdir di dalam ld.so
    • Prefix LLVM kustom pun sudah menyesuaikan path, dan kasus ini juga memerlukan penanganan khusus
  • Akibatnya, perubahan libdir kemungkinan besar harus bergantung pada pembedaan inkompatibilitas biner
  • Ada tiga tujuan dasar yang harus dipenuhi
    • Dynamic loader harus membedakan biner time32 dan time64
    • Semua biner tanpa penanda time64 eksplisit harus dianggap sebagai time32 demi kompatibilitas mundur
    • Semua biner yang baru dibangun harus memiliki penanda time64 eksplisit, termasuk biner yang dibangun di lingkungan non-C seperti Rust
  • Tujuan ini merupakan pekerjaan pada tingkat harus mem-patch banyak toolchain dari banyak bahasa
    • Sulit bagi Gentoo untuk memeliharanya hanya secara lokal, dan dibutuhkan kerja sama dari banyak pihak
    • Arsitektur target umumnya dianggap legacy atau dalam beberapa kasus tidak lagi cukup didukung
  • Apakah toolchain lain akan menghasilkan executable time64 yang benar juga menjadi masalah tersendiri
    • Jika tidak disesuaikan agar mengikuti _TIME_BITS seperti program C, toolchain dapat meng-hardcode lebar time_t tertentu dan rusak
  • Karena semua biner tanpa penanda time64 eksplisit akan memakai library time32, Gentoo tidak akan bisa menjalankan executable pihak ketiga yang belum dipatch agar memberi penanda yang benar
  • Alternatif dengan target lebih rendah juga dipertimbangkan
    • Menyuntikkan RPATH ke semua executable time64 agar memaksa penggunaan libdir time64 secara langsung
    • Cara ini tidak sepenuhnya mencegah dynamic loader memakai library time32, tetapi dapat membantu transisi tanpa masalah kompatibilitas besar
  • Sebaliknya, ada juga opsi untuk tidak mengubah libdir time64 secara permanen, melainkan mengubah libdir time32 sementara
    • Menyuntikkan RPATH ke program lama dan mengubah nama libdir
    • Library time64 baru dipasang ke libdir lama
    • Program time64 baru tidak memiliki RPATH yang memaksa library time32
    • Keuntungannya adalah kompatibilitas dengan distribusi lain yang sudah bertransisi dapat dipertahankan

Tugas yang tersisa

  • Jika ketiga solusi diimplementasikan semua, sistem Gentoo 32-bit yang memakai glibc dapat memperoleh jalur transisi yang lebih bersih dan relatif aman
  • Namun solusi-solusi ini terutama berlaku untuk paket yang dibangun dari source
  • Aplikasi 32-bit pra-build tetap menghadapi masalah tahun 2038 meskipun kompatibilitas ABI dipertahankan
  • Desain keseluruhan masih berupa draf dan dapat terus berubah mengikuti eksperimen, diskusi, serta pengajuan patch

1 komentar

 
GN⁺ 2024-09-30
Komentar Hacker News
  • Di Gentoo ada beberapa opsi yang tidak dibahas dalam tulisan tersebut, dan sepertinya terlewat karena beban kerjanya besar mengingat desain sistem Gentoo

    1. Memungkinkan sebuah paket dibangun dengan menargetkan paket itu tanpa harus menginstalnya. Intinya, proses build dan instalasi paket di Gentoo merupakan satu tahap, sehingga beberapa komponen yang saling bergantung tidak bisa dibangun lebih dulu lalu hasilnya diinstal secara atomik. Saat pembaruan yang mengubah ABI berlangsung, sistem mudah rusak sebagian
    2. Memperluas manajemen versi .so yang umum agar juga mencerminkan perubahan ABI pada paket dependensi. Biasanya shared library memiliki nomor versi pada nama file dan versi internal, seperti libfoo.so.1.0.0, dan paket melacak kerusakan ABI-nya sendiri. Untuk mendukung time_t 64-bit, perlu ditambahkan elemen versi yang dikendalikan oleh ABI dependensi tiap .so. Hasilnya mirip dengan “menggunakan libdir lain” dalam tulisan, tetapi bisa menjadi fondasi yang dapat dipakai ulang untuk perubahan ABI di masa depan, meski kemungkinan jauh lebih invasif
    • Untuk “build tanpa menginstal”, pembaruan bertahap parsial tampaknya paling cocok
      Beberapa build paket baru dapat dijadwalkan dan dibangun di sandbox, lalu kompilasi baru dibuat agar melihat sandbox terlebih dahulu melalui union dan fallback ke sistem. Setelah semuanya selesai dibangun, hasilnya dapat dipaketkan dan dipindahkan dari sandbox ke sistem nyata. Dengan cara ini, seluruh pembaruan Gentoo bisa dibuat seperti transaksi, yang juga memberi keuntungan besar di aspek lain
    • Gentoo sudah mendukung poin 1 dengan cara menentukan direktori tempat image yang sudah selesai akan diinstal. Cukup ubah ROOT, yang biasanya disetel ke /
      Seluruh @system dan @world dapat dibangun ulang lalu diinstal ke subdirektori yang ditentukan, kemudian disinkronkan sekaligus. Jika memungkinkan sebaiknya dilakukan dari live session, dan secara teori juga bisa dengan bind mount / ke subdirektori di lokasi yang baru diinstal, masuk melalui chroot, lalu menyinkronkannya ke / induk yang sebenarnya
      https://devmanual.gentoo.org/ebuild-writing/variables/#root
    • Gentoo sudah mempertahankan library lama sampai semua dependensi diperbarui, jadi masalah ini bisa diselesaikan dengan mengenkode perubahan ABI pada arsitektur dan SONAME, yaitu tempat semestinya perubahan ABI dicatat
  • Cara Mac OS X menangani off_t dan ino_t bisa menjadi petunjuk. Pemanggilan dan struct lama tetap mempertahankan perilakunya, sementara pemanggilan dan tipe baru dengan sufiks 64 ditambahkan, dan target referensi sebenarnya dapat dipilih dengan makro preprosesor, meski jarang digunakan secara langsung
    Sebagai gantinya, OS dan SDK diberi versi, dan saat build Anda dapat menentukan versi OS tertua tempat biner harus berjalan. Header otomatis memilih makro yang sesuai berdasarkan itu, dan anotasi API baru/API usang juga menggunakan mekanisme yang sama untuk membuat weak link atau peringatan. Awalnya ini ditangani dengan preprosesor, tetapi sekarang compiler memahami apa yang Apple sebut ketersediaan API dengan lebih canggih, sehingga pendekatan yang sama tampaknya mungkin di platform lain

    • Ini tidak menyelesaikan masalah inti yang dijelaskan TFA. Aplikasi yang menggunakan “versi OS target kompilasi” berbeda tidak lagi bisa saling link
      Meski berjalan di OS v.B, aplikasi X yang dideklarasikan menargetkan OS v.B mungkin tidak dapat link dengan aplikasi Y yang dideklarasikan menargetkan OS v.A. Sebenarnya pendekatan ini mirip dengan apa yang sudah dilakukan hampir semua platform, dan jika dilakukan berbeda, kompatibilitas biner lama akan langsung rusak
    • Library pendukung non-glibc tidak akan mendefinisikan beberapa salinan fungsi untuk tiap ukuran off_t, dan juga tidak akan ada switch di header yang secara transparan memilih kumpulan fungsi yang benar sesuai ukuran tipe yang diinginkan program klien
      Meski begitu, tulisan tersebut menekankan bahwa time_t adalah masalah yang lebih besar daripada off_t. Alasan yang masuk akal adalah karena time_t jauh lebih tersebar luas. off_t adalah tipe POSIX yang terlibat dalam relatif sedikit interface, sedangkan time_t termasuk ISO C dan digunakan di banyak tempat. Selain itu, banyak kode C mengasumsikan time_t adalah tipe integer dengan lebar yang sama seperti int, sementara asumsi seperti itu terhadap off_t lebih jarang
    • Kedengarannya seperti solusi yang elegan, tetapi pada praktiknya terbaca seperti hack yang mengerikan. Makro tanpa tipe adalah mimpi buruk yang tidak ingin saya tangani lagi
    • Ini hanya berfungsi jika Anda bisa memaksa seluruh platform untuk ikut. Solusinya memang bagus, tetapi Anda harus mengendalikan C library. Gentoo tidak mengendalikan apa yang dilakukan libc, dan pengguna bisa memakai GNU libc, musl, atau yang lain
  • Debian juga sangat menyakitkan. Beberapa orang mungkin mengalami burnout, dan banyak yang menunjuk distro berbasis source sambil berkata “di sana pasti sangat mudah”

    • Saya penasaran dengan materi yang menjelaskan secara rinci seberapa menyakitkannya transisi time64 di Debian. Dari luar, tampaknya relatif mulus dan tanpa banyak kontroversi; misalnya terlihat jauh lebih baik daripada penggabungan /usr
    • Saya menangani transisi m68k, powerpc, sh4, dan juga membantu sebagian untuk hppa; dengan bantuan pengembang Debian lain, saya masih bertahan
    • Jika “mudah” berarti “cukup suruh pengguna membangun ulang semuanya sekaligus”, sepertinya benar
  • Setiap kali melihat orang bergulat dengan masalah seperti ini, saya merasa sangat beruntung bahwa pada masa port amd64 awal FreeBSD, masalah ini didorong sampai tuntas. Kami bisa menentukan tipe dasar ABI, dan memutuskan untuk melihat ke masa depan, bukan masa lalu
    amd64 punya karakteristik menarik yang membuat pekerjaan ini lebih mudah. Karena argumen fungsi 32-bit otomatis di-cast menjadi 64-bit saat pemanggilan fungsi, meneruskan bilangan bulat waktu 32-bit ke fungsi yang mengharapkan time_t 64-bit pun pada tahap awal pengerjaan platform kebanyakan langsung berfungsi. Jadi detail-detail kecil bisa ditunda belakangan
    Saat itu ada platform 64-bit lain, tetapi belum ada time_t 64-bit, dan FreeBSD/amd64 adalah yang pertama di lini itu sekitar 2003–2005. Seingat saya sparc64 juga pindah ke time_t 64-bit
    Masalah terbesar saat itu adalah tzcode tidak aman untuk 64-bit. Algoritma normalisasi struct tm terjebak dalam kondisi degeneratif, seperti mencoba menghitung ulang hari/bulan/tahun untuk time_t(2^62). Alih-alih mengubah besar-besaran tzcode, seingat saya kira-kira dibuat agar gagal untuk waktu sebelum tahun 1900 atau sesudah tahun 10000. Sekarang kemungkinan besar sudah diperbaiki di upstream sejak lama
    Selama beberapa tahun, kami menangani kebingungan waktu 32/64-bit akibat kode pihak ketiga yang asal memperlakukan int/long/time_t dalam struktur data file atau jaringan, seperti bermain pukul tikus tanah, tetapi secara umum itu bukan masalah besar. Menggunakan time_t 64-bit sejak hari pertama membuat sebagian besar masalah bisa dihindari, dan melakukannya sejak awal itu mudah. Linux melewatkan peluang besar untuk melakukan hal yang sama ketika memulai port amd64/x86_64
    Sebagai tambahan, saat itu ino_t 64-bit tidak sempat diselesaikan. Nomor inode 32-bit terekspos di sangat banyak tempat, seperti struktur on-disk sistem file dan struktur direktori UFS. Ketika FreeBSD/amd64 masih menjadi platform kelas bawah, tidak ada cara realistis untuk menanganinya sejak awal tanpa mengguncang besar-besaran arsitektur tier-1 lain. Pekerjaan itu dilakukan dua kali, tetapi akhirnya diselesaikan oleh orang lain, sekaligus memperbaiki konstanta yang terlalu pendek seperti panjang path mountpoint

    • Sepemahaman saya, semua port Linux 64-bit sejak awal menggunakan time_t, off_t, dan ino_t 64-bit. Masalah sekarang adalah memindahkan Linux 32-bit ke time_t 64-bit
    • FreeBSD juga menangani off_t dengan lebih berani, sehingga sudah menjadi 64-bit sejak 2.0. Pada versi Linux 32-bit, jejak ukuran lama masih tersisa
      Bagian bahwa argumen fungsi 32-bit otomatis di-cast menjadi 64-bit saat pemanggilan, setahu saya hanya berlaku untuk argumen tak bertanda. Itu karena ketika dimuat ke %edi, bagian atas %rdi dihapus. Spesifikasi SysV ABI untuk x86-64 tidak mengatakan bahwa semua nilai di register atau stack diperluas menjadi nilai penuh 64-bit, dan catatan tentang boolean juga menyatakan semacam bahwa hanya 1 byte bawah yang bermakna, yang mengisyaratkan bahwa ini adalah aturan umum
    • Kalau maksudnya saat amd64 muncul FreeBSD juga mem-port time_t i386 menjadi 64-bit, itu cukup mengejutkan. Saya penasaran apakah arsitektur 32-bit lain seperti Motorola 68000 atau sparc32 juga dipindahkan ke time_t 64-bit
  • Di sebuah sistem Unix 32-bit besar yang sudah tua, untuk menangani tanggal masa depan, saya pernah mengganti fungsi-fungsi libc time_t 32-bit bertanda dengan padanan time_t 32-bit tak bertanda. Dengan ini kami mendapat tambahan 68 tahun setelah 2038, dan pada saat itu saya mungkin sudah tidak ada
    Kekurangannya adalah tidak bisa merepresentasikan tanggal sebelum epoch Unix, yaitu 1970, tetapi karena ini sistem manajemen jadwal, hal itu tidak menjadi masalah. Kalau tanggal masa lalu penting, epoch bisa digeser beberapa puluh tahun, atau resolusi waktu bisa diturunkan dari 1 detik menjadi 2 detik. Masing-masing punya masalah halus sendiri, jadi tergantung kasus penggunaannya

    • Kalau bisa mengubah seluruh sistem dari bertanda menjadi tak bertanda, saya penasaran kenapa tidak mengubahnya ke 64-bit
  • Di halaman manual BSD asli, bagian “Bugs” untuk tunefs memuat lelucon terkenal: “You can tune a file system, but you can't tune a fish.” Menurut “Expert C Programming”, di source code halaman manual itu ada komentar seperti ini di samping lelucon tersebut
    “Jika ini dihapus, daemon UNIX akan mengejar Anda dengan empat kaki mulai sekarang sampai time_t wrap around.”
    Ketika kalimat ini ditulis pada era 70-an, tahun 2038 pasti terasa sebagai masa depan yang tak terbayangkan jauhnya
    https://progforperf.github.io/Expert_C_Programming.pdf

  • Hal yang paling saya rasakan adalah, meski menghargai upayanya, sebagai pengguna saya ingin pindah saja ke distribusi non-berbasis source seperti Debian dan mengakhiri masalah ini

    • Kesulitan distribusi berbasis source tampaknya muncul dari upaya melakukan upgrade di tempat sambil membuat perubahan yang tidak kompatibel pada ABI. Jadi pindah ke distribusi yang sama sekali lain bisa sama disruptive-nya, setidaknya, dengan melakukan instalasi bersih Gentoo yang memakai ABI baru, meski mungkin memakan waktu lebih sedikit
    • Di Gentoo pun ada cara yang mudah. Boot dari USB atau semacamnya, jalankan mkfs.ext4 atau sistem file yang digunakan pada partisi / dan /usr, lalu mount, ekstrak stage3, masuk chroot, dan jalankan emerge $all-my-packages-that-where-installed-before-mkfs
      Alih-alih melakukan upgrade bertahap, Anda bisa memasang salinan Gentoo baru
    • Pembeda bahwa cukup pindah ke distribusi non-berbasis source sebenarnya lebih subtil. Distribusi berbasis source seperti NixOS tidak punya masalah yang sama. Intinya bukan apakah membangun dari source, melainkan pada cara Gentoo membangun dan memasang paket
      Jika ada perangkat lunak pihak ketiga closed source, sistem biner pun tetap bisa bermasalah. Paket first-party yang dipasang terpisah sebagai tahap independen juga bisa menimbulkan masalah
  • Saya bukan pakar C, tetapi saya mengira alias tipe seperti off_t diperkenalkan agar bisa diubah nanti. Namun tampaknya ini tidak bekerja dengan jelas, jadi saya penasaran apakah pemahaman saya keliru

    • Ini perbedaan antara kompatibilitas source dan kompatibilitas biner. Jika memakai typedef seperti off_t, biasanya Anda tidak perlu menulis ulang kode, tetapi semua hal yang menggunakan tipe itu harus dikompilasi ulang
    • Sampai batas tertentu memang bekerja, tetapi kurang cocok untuk distro berbasis source. Jika setelah mengubah definisi off_t Anda bisa membangun ulang @world secara atomik, tidak ada masalah, tetapi distro berbasis source tidak membangun ulang @world secara atomik; paket dibangun ulang satu per satu
      Akibatnya bisa muncul masalah seperti libc.so memakai off_t 64-bit sementara gcc dibangun dengan asumsi off_t 32-bit, lalu gcc berhenti. Paket yang diperlukan untuk membangun ulang @world seperti bash, coreutils, make, dan binutils juga bisa rusak, dan pada titik itu Anda mentok. Karena itu upgrade seperti ini perlu kehati-hatian
    • Itu baru tahap pertama dari teka-teki, bahkan mungkin baru setengah tahap. Seperti yang dikatakan artikel, begitu off_t masuk ke dalam struct, dipakai dalam pemanggilan fungsi, atau diintegrasikan ke protokol, abstraksinya hilang dan ukuran sebenarnya menjadi penting
      Jika kode lama dan baru dicampur saat memuat library atau berkomunikasi lewat protokol, offset akan bergeser dan crash mulai terjadi. Pada akhirnya, untuk transisi ini semua orang harus memisahkan program menjadi “legacy” dan “sudah di-porting atau setidaknya sudah ditinjau”, sehingga prosesnya sangat menyakitkan
    • Alias tipe hanya mempermudah pada level source code. Itu bukan abstraksi yang nyata, apalagi abstraksi penuh. Misalnya, jika tipe internal diubah menjadi tipe floating-point, maknanya berubah besar dan sepenuhnya terlihat oleh kode pengguna
      Mengubahnya ke tipe yang lebih besar dengan makna serupa pun bisa merusak. Contoh sederhananya adalah padding pada struct, dan banyak juga penggunaan yang mengubah pointer menjadi integer lalu mengembalikannya; jika representasi internal berubah, pasti bisa rusak. Apakah itu praktik yang baik adalah soal lain, tetapi itu bukan hal yang jarang. Intinya adalah kompatibilitas ABI
    • Memang bekerja, tetapi perubahan ABI punya masalah bahwa saat diubah, ia harus diubah di semua tempat sekaligus. Pada dasarnya tidak ada mekanisme yang mencegah library yang dibangun dengan off_t 32-bit di-link dengan library yang dibangun dengan off_t 64-bit, dan perilaku hasilnya bisa sangat tidak terduga
  • Pada contoh struct, disebutkan bahwa offset c adalah 8 ketika time_t 32-bit dan 12 ketika tipenya 64-bit, tetapi sebenarnya bukankah seharusnya 16? Karena b harus disejajarkan sebagai 64-bit, padding harus masuk di antara a dan b. Ini justru memperkuat argumen yang ingin dibuat penulis

    • Sebagian besar ABI x86 tidak memaksa padding untuk tipe 64-bit, karena saat itu tidak ada load 64-bit
  • Melihat semua ini, representasi waktu Windows yang aneh—yaitu menghitung dalam satuan 100ns dengan 64-bit sejak 1 Januari 1601 pukul 00:00 GMT menurut kalender Gregorian—punya sedikit kelebihan. Resolusinya juga luar biasa, dan akan tetap bekerja sampai seluruh galaksi ditaklukkan