Hledání neinicializovaných proměnných

Školení, která pořádám

PHP nás při úrovni chyb E_NOTICE upozorňuje na práci s neinicializovanými proměnnými. Jsou s tím ale spojené dva problémy:

  1. Kontrola probíhá až v době spuštění, což může být pozdě. Pokud kód pracující s neinicializovanou proměnnou nespustíme při testování, tak se o chybě můžeme dozvědět např. až po tom, kdy ji využije útočník.
  2. PHP nás neupozorní na přidání prvku do neinicializovaného pole. Na druhou stranu nás informuje o práci s neexistujícími prvky správně inicializovaného pole, což z pohledu bezpečnosti nevadí.

Napsal jsem proto program, který zdrojový kód zkontroluje, aniž by se kód musel spouštět. Původně jsem ho chtěl umístit na tento blog, ale poněkud se rozrostl, proto jsem pro něj vytvořil samostatný projekt. Program rozebere kód funkcí token_get_all a hledá v něm jakoukoliv práci s neinicializovanými proměnnými zhruba tímto algoritmem:

<?php
$initialized = array();
$tokens = token_get_all($source);
foreach ($tokens as $i => $token) {
    if ($token[0] === T_VARIABLE) {
        if ($tokens[$i+1] === '=') {
            $initialized[$token[1]] = true;
        } elseif (!$initialized[$token[1]]) {
            echo "Uninitialized variable $token[1] on line $token[2].\n";
        }
    }
}
?>

Jde samozřejmě o hrubé zjednodušení. Zohledňují se následující konstrukce:

Naopak některé konstrukce se kontrolují v rozporu s chováním jazyka:

K poslednímu bodu – přestože je tento přístup především jednodušší, tak se jedná spíše o záměrnou vlastnost než nedostatek programu. Porovnejte následující dva kódy:

<?php
if (auth()) {
    $auth = true;
} else {
    $auth = false;
}

$auth = false;
if (auth()) {
    $auth = true;
}
?>

Přestože oba kódy proměnnou správně inicializují, tak je druhý kód lepší – pokud bych do prvního kódu doplnil nějakou další větev, tak se může stát, že na inicializaci v některém případě zapomenu.

Závěr

Vyzkoušejte si, jestli správně inicializujete všechny proměnné. Pokud ano a program vám přesto tvrdí opak, dejte mi prosím vědět.

Jakub Vrána, Řešení problému, 28.7.2008, diskuse: 6 (nové: 0)

Diskuse

ikona tiso:

Pekné, tuším ma predbehneš vo všetkých projektoch čo som si vymyslel... Asi by som ich mal prestať vymýšľať ale začať aj niečo realizovať...

ikona tiso:

Skúšal som si pustiť testy a:
1. prešli len testy 1, 5, 11, 15, 19, 24, 26, 28, ostatné generovali notice
2. po nastavení <?php error_reporting(E_ALL ^ E_NOTICE); ?>
aj tak neprešli testy 6, 8 a 20.
PHP 5.2.5 @ Apache 2.2.4 @ Windows XP Home

ikona Jakub Vrána OpenID:

Díky za upozornění. Můj kód tradičně počítá s vypnutými E_NOTICE, do funkce jsem to doplnil.

Chybu způsobující neprůchodnost zmiňovaných testů jsem také opravil.

ikona tiso:

E_NOTICE - chápem. Ja mám radšej "E_NOTICE save" kód, preto ich mám zapnuté.

ikona v6ak:

JJ, TDD je vysoce návyková látka.

mata:

nahodou jsem dnes narazil na tuto stranku ... ja jsem byl vzdy ucen, ze takovato konstrukce by se mela psat takto:

$auth = auth();

pripadne

$auth = auth();
if ($auth) { ... }

Diskuse je zrušena z důvodu spamu.

avatar © 2005-2024 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.