Epic: ALERT w PHP i niespodziewane białe ekrany śmierci
Zacznę od tego, że problemu nie zdołałem rozwiązać, gdyż zwyczajnie brakowało mi czasu i nerwów. Zamiast tego, zrobiłem obejścia, które… no, działają. A dlaczego? Nie wiem. Może jakiś doświadczony czytelnik zostawi odpowiedź w komentarzu…
Tak więc onegdaj, podczas wesołej pracy z PHP, zdarzyło się kilka razy, że przy prostej i klarownej operacji na dobrze określonych wartościach, PHP rzucał białym ekranem śmierci, a w logach pojawiało się niejasne:
ALERT - canary mismatch on efree() - heap overflow detected (attacker '127.0.0.1', file '/home/mcv/htdocs/cośtam/dispatch.php')
Czasami tylko zamiast efree było erealloc.
Chwila kombinowania wykazała, że taki efekt daje następująca linia:
$ids = array_merge ($this->f1(), $this->f2(), $this->f3());
Nazwy metod zostały zmienione dla większej czytelności. Wartości zwracane przez metody były najzwyklejszymi, PHP-owymi tablicami zawierającymi jedynie liczby całkowite. Liczba? Na pewno nie większa niż około 5800 w sumie. 5800 intów to dużo czy jak?
Po straceniu stosownej ilości nerwów, wpadłem na to, żeby trochę PHP-a oszukać. Dodałem zmienne pomocniczne:
$a = $this->f1();
$b = $this->f2();
$c = $this->f3();
$ids = array_merge ($a, $b, $c);
Magia! Wszystko zaczęło działać. Czy PHP znowu coś przede mną ukrywa?
W międzyczasie Pan Google pomógł skojarzyć dziwne wpisy w logach z „utwardzaczem” PHP, tj. Suhosinem, który ma za zadanie uodparniać dziurawego PHP na różne ataki włamywaczy. I niestety tylko tyle. Trop się urwał, a ja nie wnikałem, skoro obejście zadziałało. Pewnie coś z parserem PHP nie tak (jak zwykle), albo Suhosin narobił jakiegoś bałaganu. Łorewer.
Kilka dni później, po dodaniu nowego argumentu do zupełnie innej metody:
ALERT - canary mismatch on efree() - heap overflow detected (attacker '127.0.0.1', file '/home/mcv/htdocs/cośtam/dispatch.php')
Co? Że jak? Niniejszy kod:
public function render ($partial_name, array $locals = array())
{ … }
zastąpiłem nastepującym:
public function render ($partial_name, array $locals = array(), array $options = array())
{ … }
Od tej pory biały ekran śmierci (+wpis w logu) powodowały wszelkie możliwe rodzaje wywołań:
$this->render ('xyz');
$this->render ('xyz', array ('var' => 'value'));
$this->render ('xyz', array ('var' => 'value'), array());
# itp.
Znów zacząłem tracić czas i nerwy, aż w końcu dobra dusza Zergu zasugerował, żebym zrobił to samo co ostatnio. Chwila szukania w pamięci dała poniższy efekt.
function render ($partial_name, array $locals = array(), array $options = array())
{
$this->render_old ($partial_name, $locals, $options);
}
function render_old ($partial_name, array $locals = array(), array $options = array())
{ … }
Magia, proszę Państwa! Działa! Nigdy nie lekceważcie potęgi nic-nie-robiącej funkcji opakowującej. Ani niepotrzebnych zmiennych tymczasowych. Bo mogą jednak okazać się potrzebne. A może ktoś zna wytłumaczenie dla tego bezsensownego zachowania PHP? Bo ja tego zupełnie nie rozumiem. Ale wiem już, że gdy zobaczę czyjś kod podobny do powyższego, to wcale nie z programisty będę się śmiał, a z czego innego… :^)
Dobranoc państwu i Wesołych Świąt.
Brak podobnych wpisów.





ten kod, ktory zmieniales wcale nie musial powodowac tych nadpisan buforow, to moze dziac sie juz gdzies wczesniej – komunikaty do logow zostaja wyswietlone w momencie gdy funkcja sprawdzajaca canary wykryje jakas nieprawidlowosc, czyli np. jakis bufor jest alokowany a wczesniej struktura heap (np. naglowek chunku) zostala czyms nadpisana i uszkodzona. proponuje zainstalowac nowsza wersje php jesli to nie pomoze pronouje zainstalowac starsza.