Gönderi

Google'ın Regex Kütüphanesine Yeni Özellik Eklemek: Bir Açık Kaynak Hikayesi

Google'ın RE2 projesine nasıl katkıda bulundum? İsviçre'den bir üniversiteyle aynı problemi çözerken tanıştım. İmkansız denilen bir şeyi mümkün kılma hikayesi.

Google'ın Regex Kütüphanesine Yeni Özellik Eklemek: Bir Açık Kaynak Hikayesi

Yazılım dünyasında “bu yapılamaz” denilen şeyler genellikle “henüz kimse yapmadı” anlamına gelir. Bu yazıda, Google’ın yaygın kullanılan bir kütüphanesine “imkansız” denilen bir özelliği ekleme girişimimi anlatacağım. Ve yolda İsviçre’den bir üniversiteyle tanıştım.

Regex Nedir ve Neden Önemli?

Regex (Regular Expression), metin içinde arama ve eşleştirme yapmak için kullanılan bir kalıp dilidir. Günlük hayattan örnekler:

  • E-posta adresinin geçerli olup olmadığını kontrol etmek
  • Log dosyalarında hata mesajlarını bulmak
  • “Şifre en az 8 karakter ve bir rakam içermeli” kuralını doğrulamak
  • Bir metindeki tüm telefon numaralarını maskelemek

Örneğin, bir müşteri veri tabanında telefon numarası aramak istiyorsunuz:

1
0532-123-4567 veya (532) 123 45 67 veya +90 532 1234567

Normal bir arama ile bu üç formatı da bulmak için üç ayrı sorgu yazmanız gerekir. Regex ile tek satırda halledersiniz. Bu yüzden neredeyse her programlama dili ve araç regex desteği sunar.

RE2 Kullanım Alanları Regex kütüphaneleri farklı sistemlerde yaygın olarak kullanılıyor

Google’ın RE2 Projesi

Regex motorları arasında Google’ın RE2 kütüphanesi özel bir yere sahip. Nedenini anlamak için önce bir güvenlik açığından bahsetmem gerekiyor.

ReDoS Saldırısı Nedir?

Normal regex motorları bazı kalıplarla çok yavaşlayabilir. Basit bir örnek: (a+)+$ kalıbını aaaaaaaaaaaaaaaaaaaaaX metninde aramak.

Bu işlem saniyeler, dakikalar, hatta saatler sürebilir. Kötü niyetli bir kullanıcı, özellikle hazırlanmış bir kalıpla web sitenizi çökertebilir. Buna ReDoS (Regex Denial of Service) saldırısı deniyor.

2019’da Stack Overflow bu saldırıyla 30 dakika çökmüştü. Cloudflare da benzer bir sorun yaşamıştı.

RE2’nin Çözümü

RE2 bu sorunu kökünden çözüyor: Her zaman tahmin edilebilir sürede çalışıyor. Metin ne kadar uzun olursa olsun, işlem süresi orantılı artıyor, katlanarak değil.

Bu garantiyi sağlamak için RE2 bazı özelliklerden vazgeçiyor. Ama karşılığında:

  • Google Sheets’te regex kullanabilirsiniz
  • Prometheus sorguları güvenle çalışır
  • Kullanıcı girdisi içeren sistemlerde güvenle regex kullanılabilir

“Lookaround” Özelliği ve Eksikliği

İşte vazgeçilen özelliklerden biri: Lookaround.

Ne İşe Yarıyor?

Lookaround, “şuna bak ama eşleştirmeye dahil etme” demek. Pratik örnekler:

1. Şifre doğrulama: “Şifrede en az bir rakam olmalı” kuralını kontrol etmek istiyorsunuz, ama rakamın kendisini değil, şifrenin geçerli olup olmadığını öğrenmek istiyorsunuz.

2. Loglarda filtre: “ERROR” içeren satırları bulmak istiyorsunuz, ama sadece önünde “DEBUG” yazmıyorsa.

3. Veri temizleme: Bir metindeki “password” kelimelerini maskelemek istiyorsunuz, ama “old_password” gibi değişken isimlerini değil.

1
(?<!old_)password

Bu kalıp, new_password içindeki “password”ü bulur, ama old_password içindekini bulmaz.

Issue #156: 61 Thumbs Up, 0 Solution

Projenin issue tracker’ını incelerken Issue #156’ya rastladım. 2017’de açılmış, 61 kişi “+1” vermiş, ama kapatılmış.

Maintainer açıkça belirtmiş: “RE2 does not support constructs that require backtracking.”

Yani “güvenlik garantimizi bozmadan bu özelliği ekleyemeyiz.”

Akademik Araştırma Akademik araştırmalar pratik problemlere çözüm sunabiliyor

“İmkansız” Denen Çözümü Aramak

Ben meraklandım: Gerçekten imkansız mı, yoksa henüz kimse denemedi mi?

Akademik makaleler araştırmaya başladım. Aylarca okuduktan sonra 2024’te yayınlanan bir makale dikkatimi çekti: JavaScript regex’lerinin güvenli bir şekilde nasıl çalıştırılabileceğini gösteriyordu.

Temel fikir şuydu: Lookaround için geri sarma (backtracking) zorunlu değil. Doğru algoritmayla, güvenlik garantilerini koruyarak lookaround desteklenebilir.

Bu akademik bir kanıttı. Şimdi pratik kısmı geliyordu.

Fork ve Deneysel Geliştirme

RE2’nin kaynak kodunu kendi hesabıma kopyaladım (fork) ve çalışmaya başladım. C++ ile yazılmış, karmaşık bir kod tabanı. Ama adım adım anlamaya başladım.

Hedefim basitti: Lookaround özelliğini eklemek, ama güvenlik garantilerini bozmamak.

Yaklaşımım

  1. Her lookaround için ayrı bir mini-program oluştur
  2. Bu mini-programları ana aramayla birlikte çalıştır
  3. Geriye bakma mesafesini sınırla (255 karakter)

255 karakter sınırı neden? Çünkü:

  • Pratikte çoğu kullanım senaryosunu kapsıyor
  • Sistemi güvenli tutuyor
  • Bellekte kompakt temsil sağlıyor

Birkaç hafta sonra çalışan bir prototipim vardı:

1
2
3
4
5
6
7
8
9
// "test" kelimesini bul, önünde rakam yoksa
RE2 re("(?<!\\d)test");
RE2::PartialMatch("hello test", re);  // ✓ bulur
RE2::PartialMatch("123test", re);     // ✗ bulmaz

// "world" kelimesini bul, önünde "hello " varsa
RE2 re2("(?<=hello )world");
RE2::PartialMatch("hello world", re2);   // ✓ bulur
RE2::PartialMatch("goodbye world", re2); // ✗ bulmaz

Test Sonuçları Testlerin başarıyla geçmesi her zaman güzel bir his

Issue Açtım, İlginç Bir Şey Oldu

Çalışan prototipimi toplulukla paylaşmak için Issue #585’i açtım. Detaylı bir açıklama yazdım:

  • Ne yaptım
  • Nasıl yaptım
  • Hangi kısıtlamalar var
  • Neden 255 karakter sınırı koydum

Birkaç hafta sonra beklemediğim bir yorum geldi. İsviçre’deki EPFL üniversitesinden bir araştırmacı yazdı:

“İlginç bir şeyle paylaşmak istiyorum - biz de aynı problemi çözdük, ama sınırsız lookbehind’ı destekleyen bir yöntemle.”

Meğer aynı problemi, aynı dönemde, farklı yaklaşımlarla çözmeye çalışan iki grup varmış! Bir tarafta ben, diğer tarafta İsviçre’nin en prestijli üniversitelerinden birinin araştırma ekibi.

Karşılaştırma Farklı algoritma yaklaşımlarının karşılaştırması

İki Yaklaşımın Karşılaştırması

ÖzellikBenim YaklaşımımEPFL Yaklaşımı
Geriye bakma limiti255 karakterSınırsız
İleriye bakma✅ Destekliyor❌ Henüz yok
Kod değişikliği~280 satır~275 satır
YaklaşımPragmatikAkademik

İkisi de güvenlik garantilerini koruyor. İkisi de teorik olarak doğru. Sadece farklı öncelikler:

  • EPFL’in çözümü matematiksel olarak daha zarif
  • Benimki daha fazla senaryoyu kapsıyor (hem ileri hem geri bakma)
  • İkisi de henüz merge edilmedi

Bu Deneyimden Ne Öğrendim?

1. “İmkansız” Çoğu Zaman “Zor” Demek

Yıllardır “yapılamaz” denilen bir şey, doğru yaklaşımla mümkün olabilir. 61 kişi istemesine rağmen 7 yıldır eklenmeyen bir özellik, birkaç haftalık çalışmayla prototip haline geldi.

Önemli olan araştırmak ve denemek.

2. Dünyanın Bir Köşesinde Birisi Aynı Şeyi Düşünüyor

Issue açmak, sadece çözüm paylaşmak değil. Aynı problem üzerinde çalışan insanlarla tanışmak için de bir fırsat. Ben İstanbul’da, onlar İsviçre’de - ama aynı soruna farklı çözümler ürettik.

3. Sonuç Her Zaman “Merge” Değil

PR’ım henüz merge edilmedi. Belki hiç edilmeyecek. Google’ın kritik altyapısına değişiklik kabul etmek zor bir karar - milyonlarca kullanıcıyı etkiliyor.

Ama bu yolculukta kazandığım deneyimler kalıcı:

  • Karmaşık bir kod tabanını analiz etme
  • Akademik makale okuma ve pratiğe çevirme
  • Açık kaynak toplulukla iletişim kurma

Açık Kaynak Katkı Süreci Açık kaynak katkı süreci

4. Küçük Adımlarla Başlayın

İlk açık kaynak katkınız Google’ın kritik altyapısını değiştirmek olmak zorunda değil. Bir dokümantasyon hatası düzeltmek, küçük bir bug fix göndermek veya test eklemek - hepsi değerli katkılar.

Önemli olan başlamak.

Sonuç

Issue #585 hala açık. Tartışma devam ediyor. Belki bir gün merge edilir, belki edilmez.

Ama “imkansız” denilen bir şeyin aslında yapılabilir olduğunu gösterdik - hem ben, hem de dünyanın öbür ucundaki EPFL ekibi. Bu bile başlı başına bir kazanım.

Eğer siz de bir projeye bakıp “bu özellik neden yok?” diye soruyorsanız, belki cevap sizin elinizde olabilir.


Kaynaklar:

BKZ:

Furkan Köykıran Furkan Köykıran - Senior Software Engineer

Bu gönderi CC BY 4.0 lisansı altındadır.