Skip to content

Add support for sensitive parameters in stubs #8689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Zend/zend_attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,19 @@ static zend_always_inline zend_attribute *zend_add_class_constant_attribute(zend
return zend_add_attribute(&c->attributes, name, argc, flags, 0, 0);
}

static zend_always_inline zend_attribute *zend_mark_function_parameter_as_sensitive(const HashTable *table, const char *func_name, uint32_t parameter)
{
zend_function *func = zend_hash_str_find_ptr(table, func_name, strlen(func_name));
ZEND_ASSERT(func != NULL);

return zend_add_parameter_attribute(
func,
parameter,
zend_ce_sensitive_parameter->name,
0
);
}

void zend_register_attribute_ce(void);
void zend_attributes_shutdown(void);

Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_constants.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ void zend_startup_constants(void)

void zend_register_standard_constants(void)
{
register_zend_constants_consts(0);
register_zend_constants_symbols(0);

REGISTER_MAIN_LONG_CONSTANT("DEBUG_BACKTRACE_PROVIDE_OBJECT", DEBUG_BACKTRACE_PROVIDE_OBJECT, CONST_PERSISTENT | CONST_CS);
REGISTER_MAIN_LONG_CONSTANT("DEBUG_BACKTRACE_IGNORE_ARGS", DEBUG_BACKTRACE_IGNORE_ARGS, CONST_PERSISTENT | CONST_CS);
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_constants_arginfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@



static void register_zend_constants_consts(int module_number)
static void register_zend_constants_symbols(int module_number)
{
REGISTER_LONG_CONSTANT("E_ERROR", E_ERROR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("E_WARNING", E_WARNING, CONST_CS | CONST_PERSISTENT);
Expand Down
172 changes: 130 additions & 42 deletions build/gen_stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -759,21 +759,33 @@ class ArgInfo {
public $phpDocType;
/** @var string|null */
public $defaultValue;
/** @var bool */
public $isSensitive;

public function __construct(string $name, int $sendBy, bool $isVariadic, ?Type $type, ?Type $phpDocType, ?string $defaultValue) {
public function __construct(
string $name,
int $sendBy,
bool $isVariadic,
?Type $type,
?Type $phpDocType,
?string $defaultValue,
bool $isSensitive
) {
$this->name = $name;
$this->sendBy = $sendBy;
$this->isVariadic = $isVariadic;
$this->setTypes($type, $phpDocType);
$this->defaultValue = $defaultValue;
$this->isSensitive = $isSensitive;
}

public function equals(ArgInfo $other): bool {
return $this->name === $other->name
&& $this->sendBy === $other->sendBy
&& $this->isVariadic === $other->isVariadic
&& Type::equals($this->type, $other->type)
&& $this->defaultValue === $other->defaultValue;
&& $this->defaultValue === $other->defaultValue
&& $this->isSensitive === $other->isSensitive;
}

public function getSendByString(): string {
Expand Down Expand Up @@ -925,6 +937,7 @@ interface FunctionOrMethodName {
public function getDeclaration(): string;
public function getArgInfoName(): string;
public function getMethodSynopsisFilename(): string;
public function getAttributeName(): string;
public function __toString(): string;
public function isMethod(): bool;
public function isConstructor(): bool;
Expand Down Expand Up @@ -970,6 +983,10 @@ public function getMethodSynopsisFilename(): string {
return implode('_', $this->name->parts);
}

public function getAttributeName(): string {
Copy link
Member

@iluuu1994 iluuu1994 Jun 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name is a bit confusing. It's not the attribute name but the canonicalized (ie lowercased) function/method name to attach the given attribute to.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right. However, I think it's better if the method name reflects the use-case (similarly togetMethodSynopsisFilename() and getArgInfoName()) instead of using "canonicalized". That's why I changed getAttributeName() for getNameForAttributes() in b2ed625. Hopefully, it addresses your comments and make intention more clear.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, perfect 🙂

return strtolower($this->name->toString());
}

public function __toString(): string {
return $this->name->toString();
}
Expand All @@ -989,7 +1006,7 @@ public function isDestructor(): bool {

class MethodName implements FunctionOrMethodName {
/** @var Name */
private $className;
public $className;
/** @var string */
public $methodName;

Expand All @@ -1014,6 +1031,10 @@ public function getMethodSynopsisFilename(): string {
return $this->getDeclarationClassName() . "_{$this->methodName}";
}

public function getAttributeName(): string {
return strtolower($this->methodName);
}

public function __toString(): string {
return "$this->className::$this->methodName";
}
Expand Down Expand Up @@ -2896,7 +2917,7 @@ public function getVariableName(): string {

if ($this->name === "param") {
preg_match('/^\s*[\w\|\\\\\[\]]+\s*\$(\w+).*$/', $value, $matches);
} elseif ($this->name === "prefer-ref") {
} elseif ($this->name === "prefer-ref" || $this->name === "sensitive-param") {
preg_match('/^\s*\$(\w+).*$/', $value, $matches);
}

Expand Down Expand Up @@ -2946,34 +2967,54 @@ function parseFunctionLike(
if ($comment) {
$tags = parseDocComment($comment);
foreach ($tags as $tag) {
if ($tag->name === 'prefer-ref') {
$varName = $tag->getVariableName();
if (!isset($paramMeta[$varName])) {
$paramMeta[$varName] = [];
}
$paramMeta[$varName]['preferRef'] = true;
} else if ($tag->name === 'alias' || $tag->name === 'implementation-alias') {
$aliasType = $tag->name;
$aliasParts = explode("::", $tag->getValue());
if (count($aliasParts) === 1) {
$alias = new FunctionName(new Name($aliasParts[0]));
} else {
$alias = new MethodName(new Name($aliasParts[0]), $aliasParts[1]);
}
} else if ($tag->name === 'deprecated') {
$isDeprecated = true;
} else if ($tag->name === 'no-verify') {
$verify = false;
} else if ($tag->name === 'tentative-return-type') {
$tentativeReturnType = true;
} else if ($tag->name === 'return') {
$docReturnType = $tag->getType();
} else if ($tag->name === 'param') {
$docParamTypes[$tag->getVariableName()] = $tag->getType();
} else if ($tag->name === 'refcount') {
$refcount = $tag->getValue();
} else if ($tag->name === 'compile-time-eval') {
$supportsCompileTimeEval = true;
switch ($tag->name) {
case 'alias':
case 'implementation-alias':
$aliasType = $tag->name;
$aliasParts = explode("::", $tag->getValue());
if (count($aliasParts) === 1) {
$alias = new FunctionName(new Name($aliasParts[0]));
} else {
$alias = new MethodName(new Name($aliasParts[0]), $aliasParts[1]);
}
break;

case 'deprecated':
$isDeprecated = true;
break;

case 'no-verify':
$verify = false;
break;

case 'tentative-return-type':
$tentativeReturnType = true;
break;

case 'return':
$docReturnType = $tag->getType();
break;

case 'param':
$docParamTypes[$tag->getVariableName()] = $tag->getType();
break;

case 'refcount':
$refcount = $tag->getValue();
break;

case 'compile-time-eval':
$supportsCompileTimeEval = true;
break;

case 'prefer-ref':
case 'sensitive-param':
$varName = $tag->getVariableName();
if (!isset($paramMeta[$varName])) {
Copy link
Member

@iluuu1994 iluuu1994 Jun 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isset block is redundant, $paramMeta[$varName][$tag->name] = true; will automatically create the outer array.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I also noticed this, but didn't want to touch it as this piece of code was originally written by Nikita

$paramMeta[$varName] = [];
}
$paramMeta[$varName][$tag->name] = true;
break;
}
}
}
Expand All @@ -2984,7 +3025,8 @@ function parseFunctionLike(
$foundVariadic = false;
foreach ($func->getParams() as $i => $param) {
$varName = $param->var->name;
$preferRef = !empty($paramMeta[$varName]['preferRef']);
$preferRef = !empty($paramMeta[$varName]['prefer-ref']);
$isSensitive = !empty($paramMeta[$varName]['sensitive-param']);
unset($paramMeta[$varName]);

if (isset($varNameSet[$varName])) {
Expand Down Expand Up @@ -3031,7 +3073,8 @@ function parseFunctionLike(
$param->variadic,
$type,
isset($docParamTypes[$varName]) ? Type::fromString($docParamTypes[$varName]) : null,
$param->default ? $prettyPrinter->prettyPrintExpr($param->default) : null
$param->default ? $prettyPrinter->prettyPrintExpr($param->default) : null,
$isSensitive
);
if (!$param->default && !$param->variadic) {
$numRequiredArgs = $i + 1;
Expand Down Expand Up @@ -3555,7 +3598,11 @@ function findEquivalentFuncInfo(array $generatedFuncInfos, FuncInfo $funcInfo):
return null;
}

/** @param iterable $infos */
/**
* @template T
* @param iterable<T> $infos
* @param Closure(T): string|null $codeGenerator
*/
function generateCodeWithConditions(
iterable $infos, string $separator, Closure $codeGenerator): string {
$code = "";
Expand Down Expand Up @@ -3593,7 +3640,7 @@ function generateArgInfoCode(
$generatedFuncInfos = [];
$code .= generateCodeWithConditions(
$fileInfo->getAllFuncInfos(), "\n",
function (FuncInfo $funcInfo) use(&$generatedFuncInfos) {
static function (FuncInfo $funcInfo) use (&$generatedFuncInfos) {
/* If there already is an equivalent arginfo structure, only emit a #define */
if ($generatedFuncInfo = findEquivalentFuncInfo($generatedFuncInfos, $funcInfo)) {
$code = sprintf(
Expand All @@ -3615,7 +3662,7 @@ function (FuncInfo $funcInfo) use(&$generatedFuncInfos) {
$generatedFunctionDeclarations = [];
$code .= generateCodeWithConditions(
$fileInfo->getAllFuncInfos(), "",
function (FuncInfo $funcInfo) use($fileInfo, &$generatedFunctionDeclarations) {
static function (FuncInfo $funcInfo) use ($fileInfo, &$generatedFunctionDeclarations) {
$key = $funcInfo->getDeclarationKey();
if (isset($generatedFunctionDeclarations[$key])) {
return null;
Expand All @@ -3636,14 +3683,27 @@ function (FuncInfo $funcInfo) use($fileInfo, &$generatedFunctionDeclarations) {
}

if ($fileInfo->generateClassEntries) {
if (!empty($fileInfo->constInfos)) {
$code .= "\nstatic void register_{$stubFilenameWithoutExtension}_consts(int module_number)\n";
$classEntriesWithSensitiveParams = [];
$attributeInitializationCode = generateAttributeInitialization($fileInfo, $classEntriesWithSensitiveParams);

if ($attributeInitializationCode !== "" || !empty($fileInfo->constInfos)) {
$classEntriesWithSensitiveParams = array_unique($classEntriesWithSensitiveParams);
$code .= "\nstatic void register_{$stubFilenameWithoutExtension}_symbols(int module_number";
foreach ($classEntriesWithSensitiveParams as $ce) {
$code .= ", zend_class_entry *$ce";
}
$code .= ")\n";
$code .= "{\n";

foreach ($fileInfo->constInfos as $constInfo) {
$code .= $constInfo->getDeclaration($allConstInfos);
}

if (!empty($attributeInitializationCode !== "" && $fileInfo->constInfos)) {
$code .= "\n";
}

$code .= $attributeInitializationCode;
$code .= "}\n";
}

Expand Down Expand Up @@ -3677,7 +3737,7 @@ function generateFunctionEntries(?Name $className, array $funcInfos): string {
}

$code .= "\n\nstatic const zend_function_entry {$functionEntryName}[] = {\n";
$code .= generateCodeWithConditions($funcInfos, "", function (FuncInfo $funcInfo) {
$code .= generateCodeWithConditions($funcInfos, "", static function (FuncInfo $funcInfo) {
return $funcInfo->getFunctionEntry();
});
$code .= "\tZEND_FE_END\n";
Expand All @@ -3686,14 +3746,42 @@ function generateFunctionEntries(?Name $className, array $funcInfos): string {
return $code;
}

function generateAttributeInitialization(FileInfo $fileInfo, array &$classEntriesWithSensitiveParams): string {
return generateCodeWithConditions(
$fileInfo->getAllFuncInfos(),
"",
static function (FuncInfo $funcInfo) use (&$classEntriesWithSensitiveParams) {
$code = null;

foreach ($funcInfo->args as $index => $arg) {
if (!$arg->isSensitive) {
continue;
}

if ($funcInfo->name instanceof MethodName) {
$classEntry = "class_entry_" . str_replace("\\", "_", $funcInfo->name->className->toString());
$functionTable = "&{$classEntry}->function_table";
$classEntriesWithSensitiveParams[] = $classEntry;
} else {
$functionTable = "CG(function_table)";
}

$code .= " zend_mark_function_parameter_as_sensitive($functionTable, \"" . $funcInfo->name->getAttributeName() . "\", $index);\n";
}

return $code;
}
);
}

/** @param FuncInfo<string, FuncInfo> $funcInfos */
function generateOptimizerInfo(array $funcInfos): string {

$code = "/* This is a generated file, edit the .stub.php files instead. */\n\n";

$code .= "static const func_info_t func_infos[] = {\n";

$code .= generateCodeWithConditions($funcInfos, "", function (FuncInfo $funcInfo) {
$code .= generateCodeWithConditions($funcInfos, "", static function (FuncInfo $funcInfo) {
return $funcInfo->getOptimizerInfo();
});

Expand Down Expand Up @@ -4090,7 +4178,7 @@ function initPhpParser() {
installPhpParser($version, $phpParserDir);
}

spl_autoload_register(function(string $class) use($phpParserDir) {
spl_autoload_register(function(string $class) use ($phpParserDir) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you made the one above static, this one can also be static.

if (strpos($class, "PhpParser\\") === 0) {
$fileName = $phpParserDir . "/lib/" . str_replace("\\", "/", $class) . ".php";
require $fileName;
Expand Down
2 changes: 1 addition & 1 deletion ext/calendar/calendar.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ ZEND_GET_MODULE(calendar)

PHP_MINIT_FUNCTION(calendar)
{
register_calendar_consts(module_number);
register_calendar_symbols(module_number);

return SUCCESS;
}
Expand Down
2 changes: 1 addition & 1 deletion ext/calendar/calendar_arginfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE_END
};

static void register_calendar_consts(int module_number)
static void register_calendar_symbols(int module_number)
{
REGISTER_LONG_CONSTANT("CAL_GREGORIAN", CAL_GREGORIAN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_JULIAN", CAL_JULIAN, CONST_CS | CONST_PERSISTENT);
Expand Down
2 changes: 1 addition & 1 deletion ext/date/php_date.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,8 @@ ZEND_MODULE_POST_ZEND_DEACTIVATE_D(date)
PHP_MINIT_FUNCTION(date)
{
REGISTER_INI_ENTRIES();
register_php_date_consts(module_number);
date_register_classes();
register_php_date_symbols(module_number);

php_date_global_timezone_db = NULL;
php_date_global_timezone_db_enabled = 0;
Expand Down
2 changes: 1 addition & 1 deletion ext/date/php_date_arginfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ static const zend_function_entry class_DatePeriod_methods[] = {
ZEND_FE_END
};

static void register_php_date_consts(int module_number)
static void register_php_date_symbols(int module_number)
{
REGISTER_STRING_CONSTANT("DATE_ATOM", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
ZEND_ASSERT(strcmp(DATE_FORMAT_RFC3339, "Y-m-d\\TH:i:sP") == 0);
Expand Down
2 changes: 1 addition & 1 deletion ext/dom/php_dom.c
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ PHP_MINIT_FUNCTION(dom)
zend_hash_add_ptr(&classes, dom_xpath_class_entry->name, &dom_xpath_prop_handlers);
#endif

register_php_dom_consts(module_number);
register_php_dom_symbols(module_number);

php_libxml_register_export(dom_node_class_entry, php_dom_export_node);

Expand Down
Loading