Beispiel #1
0
/** run tests on a function. the code is passed in $txt */
function check_function($name, $txt, $offset)
{
    global $API_params;
    if (preg_match_all('/zend_parse_parameters(?:_ex\\s*\\([^,]+,[^,]+|\\s*\\([^,]+),\\s*"([^"]*)"\\s*,\\s*([^{;]*)/S', $txt, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) {
        $GLOBALS['current_function'] = $name;
        foreach ($matches as $m) {
            $GLOBALS['error_few_vars_given'] = false;
            update_lineno($offset + $m[2][1]);
            $vars = get_vars(substr($txt, 0, $m[0][1]));
            // limit var search to current location
            $params = get_params($vars, $m[2][0]);
            $optional = $varargs = false;
            $last_last_char = $last_char = '';
            $j = -1;
            $len = strlen($m[1][0]);
            for ($i = 0; $i < $len; ++$i) {
                switch ($char = $m[1][0][$i]) {
                    // separator for optional parameters
                    case '|':
                        if ($optional) {
                            error("more than one optional separator at char #{$i}");
                        } else {
                            $optional = true;
                            if ($i == $len - 1) {
                                error("unnecessary optional separator");
                            }
                        }
                        break;
                        // separate_zval_if_not_ref
                    // separate_zval_if_not_ref
                    case '/':
                        if (!in_array($last_char, array('r', 'z'))) {
                            error("the '/' specifier cannot be applied to '{$last_char}'");
                        }
                        break;
                        // nullable arguments
                    // nullable arguments
                    case '!':
                        if (!in_array($last_char, array('a', 'C', 'f', 'h', 'o', 'O', 'r', 's', 't', 'z', 'Z'))) {
                            error("the '!' specifier cannot be applied to '{$last_char}'");
                        }
                        break;
                    case '&':
                        if (version_compare(VERSION, '6', 'ge')) {
                            if ($last_char == 's' || $last_last_char == 's' && $last_char == '!') {
                                check_param($params, ++$j, 'UConverter*', $optional);
                            } else {
                                error("the '&' specifier cannot be applied to '{$last_char}'");
                            }
                        } else {
                            error("unknown char ('&') at column {$i}");
                        }
                        break;
                    case '+':
                    case '*':
                        if (version_compare(VERSION, '6', 'ge')) {
                            if ($varargs) {
                                error("A varargs specifier can only be used once. repeated char at column {$i}");
                            } else {
                                check_param($params, ++$j, 'zval****', $optional);
                                check_param($params, ++$j, 'int*', $optional);
                                $varargs = true;
                            }
                        } else {
                            error("unknown char ('{$char}') at column {$i}");
                        }
                        break;
                    default:
                        if (isset($API_params[$char])) {
                            foreach ($API_params[$char] as $exp) {
                                check_param($params, ++$j, $exp, $optional);
                            }
                        } else {
                            error("unknown char ('{$char}') at column {$i}");
                        }
                }
                $last_last_char = $last_char;
                $last_char = $char;
            }
        }
    }
}
Beispiel #2
0
/** run tests on a function. the code is passed in $txt */
function check_function($name, $txt, $offset)
{
    global $API_params;
    $regex = '/
		(?: zend_parse_parameters(?:_throw)?               \\s*\\([^,]+
		|   zend_parse_(?:parameters_ex|method_parameters) \\s*\\([^,]+,[^,]+
		|   zend_parse_method_parameters_ex                \\s*\\([^,]+,[^,]+,[^,+]
		)
		,\\s*"([^"]*)"\\s*
		,\\s*([^{;]*)
	/Sx';
    if (preg_match_all($regex, $txt, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) {
        $GLOBALS['current_function'] = $name;
        foreach ($matches as $m) {
            $GLOBALS['error_few_vars_given'] = false;
            update_lineno($offset + $m[2][1]);
            $vars = get_vars(substr($txt, 0, $m[0][1]));
            // limit var search to current location
            $params = get_params($vars, $m[2][0]);
            $optional = $varargs = false;
            $last_char = '';
            $j = -1;
            $spec = $m[1][0];
            $len = strlen($spec);
            for ($i = 0; $i < $len; ++$i) {
                $char = $spec[$i];
                switch ($char = $spec[$i]) {
                    // separator for optional parameters
                    case '|':
                        if ($optional) {
                            error("more than one optional separator at char #{$i}");
                        } else {
                            $optional = true;
                            if ($i == $len - 1) {
                                error("unnecessary optional separator");
                            }
                        }
                        break;
                        // separate_zval_if_not_ref
                    // separate_zval_if_not_ref
                    case '/':
                        if (in_array($last_char, array('l', 'L', 'd', 'b'))) {
                            error("the '/' specifier should not be applied to '{$last_char}'");
                        }
                        break;
                        // nullable arguments
                    // nullable arguments
                    case '!':
                        if (in_array($last_char, array('l', 'L', 'd', 'b'))) {
                            check_param($params, ++$j, 'zend_bool*', $optional);
                        }
                        break;
                        // variadic arguments
                    // variadic arguments
                    case '+':
                    case '*':
                        if ($varargs) {
                            error("A varargs specifier can only be used once. repeated char at column {$i}");
                        } else {
                            check_param($params, ++$j, 'zval**', $optional);
                            check_param($params, ++$j, 'int*', $optional);
                            $varargs = true;
                        }
                        break;
                    case 's':
                    case 'p':
                        check_param($params, ++$j, 'char**', $optional, $allow_uninit = true);
                        check_param($params, ++$j, 'size_t*', $optional, $allow_uninit = true);
                        if ($optional && !$params[$j - 1][2] && !$params[$j][2] && $params[$j - 1][0] !== '**dummy**' && $params[$j][0] !== '**dummy**') {
                            error("one of optional vars {$params[$j - 1][0]} or {$params[$j][0]} must be initialized", 1);
                        }
                        break;
                    case 'C':
                        // C must always be initialized, independently of whether it's optional
                        check_param($params, ++$j, 'zend_class_entry**', false);
                        break;
                    default:
                        if (!isset($API_params[$char])) {
                            error("unknown char ('{$char}') at column {$i}");
                        }
                        // If an is_null flag is in use, only that flag is required to be
                        // initialized
                        $allow_uninit = $i + 1 < $len && $spec[$i + 1] === '!' && in_array($char, array('l', 'L', 'd', 'b'));
                        foreach ($API_params[$char] as $exp) {
                            check_param($params, ++$j, $exp, $optional, $allow_uninit);
                        }
                }
                $last_char = $char;
            }
        }
    }
}