วันนี้เมื่อผมไปถึงที่ทำงาน เปิด laptop ขึ้นมา และ update packages แล้วก็พบว่า maliit-keyboard มัน crash รัวๆ อีกแล้ว ทั้งๆ ที่ผมก็ update เป็นตัว maliit-keyboard-robust ตัวล่าสุดที่ได้ปรับปรุงต่อจากภาคที่แล้วไปเยอะแล้ว ผมเลยเรียก qwen-code ขึ้นมาคุย
ผม: Qwen เจ้า maliit-keyboard มัน crash รัวๆ อีกแล้วว่ะ เราแก้ bug กันไปหมดแล้วไม่ใช่เหรอ ลอง analyze error นี้หน่อย (แล้วผมก็แปะ stack trace ที่ได้จาก ABRT ให้มันดู)
Qwen: คราวนี้ไม่ใช่ความผิดของเรานะ มัน crash ที่ maliit-framework ต่างหาก ถ้าจะแก้ให้หายขาดก็ต้องแก้ code ของ maliit-framework
ผม: จริงดิ เราไม่มีทางป้องกันจาก maliit-keyboard ได้เลยเหรอ
Qwen: ไม่ได้เพราะ maliit-framework มันถูก load ขึ้นมาอยู่ใน memory space เดียวกับ maliit-keyboard แล้ว ถ้ามันตายมันก็จะทำให้ maliit-keyboard ตายไปด้วย
ผม: แต่เราสร้าง package maliit-keyboard-robust มา override maliit-keyboard ไปตัวนึงแล้วไง ไม่อยากสร้าง maliit-framework-robust ขึ้นมาอีกน่ะ อีกอย่าง project maintainer เขาก็เกลียดเราแล้วด้วยเพราะดันเอา AI code ไปแปดเปื้อน project เขา ไหนแกลองวิเคราะ code ทั้งระบบอีกทีสิว่ามีอะไรที่เราทำได้อีกบ้างจากฝั่ง maliit-keyboard
Qwen: ... ไม่มีทาง เราทำทุกอย่างที่ทำได้ไปหมดแล้ว ยังไงก็ต้องแก้ code ของ maliit-framework
ผม: ... เออ ก็ได้วะ
แล้วผมก็ fork repo ต้นน้ำออกมาเป็น maliit-framework-robust แล้วก็เริ่มให้ Qwen วิเคราะห์อีกรอบจาก stack trace จนเจอต้นตอว่าการ crash เกิดขึ้นใน QString::fromUtf8() เมื่อมีการแปลงค่าตำแหน่งแบบ unsigned ที่มีขนาดใหญ่มาก (เช่น 2154852192 ซึ่งตรงกับ issue maliit/framework#131) ไปเป็น signed int ทำให้ได้ค่าขนาดติดลบ ซึ่งนำไปสู่การเกิด qBadAlloc() abort หรือ buffer overflow ฟังดูคล้ายๆ กับปัญหาเดิมใน maliit-keyboard แต่อันนั้นมันเกิดจาก surrounding text ขนาดมหาศาลจนล้น buffer ซึ่งเจ้า Qwen ก็แก้ให้และออกมาเป็น commit 52f9fbf หลังจากนั้นผมก็ให้ Qwen วิเคราะห์ code ทั้งหมดอีกรอบว่ามี bug ตรงไหนอีกบ้าง ไหนๆ แก้แล้วจะได้แก้ให้หมด ซึ่งสิ่งที่เจอมันเหลือเชื่อมาก คือมี bug อีกทั้งหมด 9 ตัว รวมตัวแรกด้วยก็เป็น 10 ตัว ซึ่งผมก็แก้ทีละตัวต่อ commit จึงได้ git log ดังนี้
$ git log --oneline
082f010 Fix integer underflow in BITS2BYTES macro
2ec53a3 Fix null pointer dereference in WindowGroup methods
136d82c Fix thread safety in MImSettings factory initialization
7a88893 Fix use-after-free in DBus server disconnection
44ed47c Fix use-after-free in DBus input context disconnection
a951ae5 Fix buffer overflow in enabledSubViews neighbor lookup
390679d Add null check for wl_display_get_registry return value
b420523 Fix null pointer dereferences in Wayland connection methods
83141bb Fix crash when Wayland is not available
df45fb6 Fix crash from invalid Wayland surrounding text cursor/anchor positions
สิ่งที่เหลือเชื่อที่บอกไว้ตอนแรกก็คือ maliit-keyboard และ maliit-framework เป็นซอฟต์แวร์ที่ใช้กันมายาวนานในหลากหลายอุปกรณ์ และที่ผ่านมาหลายปีเราก็อยู่กับ bug เหล่านี้มาโดยตลอด bug บางตัวเป็นสิ่งที่น่าจะเห็นได้ง่ายๆ ด้วยซ้ำ เช่น integer underflow และ buffer overflow แต่ project maintainer ก็ไม่ได้แก้อะไร แถมยังไม่มี commit มาจากผู้สร้างหลักๆ นานหลายปีแล้วด้วย หลังๆ ก็จะมีแต่ merge PR (pull request) จากคนอื่นเข้ามาเท่านั้น หรือสิ่งนี้จะเป็นสัญญานที่บ่งบอกถึงข้อจำกัดของนักพัฒนาซอฟต์แวร์ที่เป็นมนุษย์ ซึ่งถ้าเขาเปิดใจยอมรับการช่วยเหลือจาก AI ให้ช่วยตรวจหา bug มันก็อาจจะถูกแก้ไปนานแล้วก็ได้
ผมได้สร้าง COPR สำหรับ maliit-framework-robust อยู่ที่ https://copr.fedorainfracloud.org/coprs/cwt/maliit-framework-robust/ และ source code ที่ถูกแก้ไขแล้วอยู่ที่ https://github.com/cwt/maliit-framework-robust
สำหรับการติดตั้งตอนนี้จำเป็นจะต้องติดตั้งทั้งคู่ด้วยคำสั่ง
$ sudo dnf copr enable cwt/maliit-framework-robust
$ sudo dnf copr enable cwt/maliit-keyboard-robust
$ sudo dnf install maliit-keyboard-robust maliit-framework-robust --allowerasing