Skip to content
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
3 changes: 3 additions & 0 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
Wrote /compiler/docs/capabilities.md (279 builtins).
Wrote /compiler/docs/stdlib-jit-audit.md (missing=0, deferred=0, present=265)
# Capability matrix

Auto-generated by `script/capability-matrix.php`. Do not edit by hand.
Expand Down Expand Up @@ -149,6 +151,7 @@ Auto-generated by `script/capability-matrix.php`. Do not edit by hand.
| `is_scalar` | yes | yes | yes | standard | |
| `is_string` | yes | yes | yes | types | JIT PHPT; AOT PHPT |
| `is_subclass_of` | yes | yes | yes | standard | |
| `is_uploaded_file` | yes | yes | yes | standard | JIT PHPT; AOT PHPT |
| `is_writable` | yes | yes | yes | standard | JIT PHPT; AOT PHPT |
| `join` | yes | yes | yes | standard | JIT PHPT; AOT PHPT |
| `json_decode` | yes | yes | yes | standard | JIT PHPT; AOT PHPT |
Expand Down
5 changes: 3 additions & 2 deletions docs/stdlib-jit-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Auto-generated by `script/audit-stdlib-jit.php`. Regenerate: `php script/audit-s

| Metric | Count |
|--------|------:|
| `call()` implementations | 263 |
| With JitStringArg/JitLongArg (or zero-arg LLVM) | 261 |
| `call()` implementations | 264 |
| With JitStringArg/JitLongArg (or zero-arg LLVM) | 262 |
| Missing arg helpers (actionable for JIT) | 0 |
| Deferred (VM-only) | 0 |
| Self-host auto-stub batch | 0 |
Expand Down Expand Up @@ -153,6 +153,7 @@ _None — all JIT `call()` builtins are lowered or deferred._
- `is_readable` — `ext/standard/is_readable.php`
- `is_scalar` — `ext/standard/is_scalar.php`
- `is_subclass_of` — `ext/standard/is_subclass_of_.php`
- `is_uploaded_file` — `ext/standard/is_uploaded_file.php`
- `is_writable` — `ext/standard/is_writable.php`
- `json_decode` — `ext/standard/json_decode.php`
- `json_encode` — `ext/standard/json_encode.php`
Expand Down
29 changes: 29 additions & 0 deletions ext/standard/JitIsUploadedFile.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\ext\standard;

use PHPCompiler\JIT\Builtin\StringFsDir;
use PHPCompiler\JIT\Context;
use PHPLLVM\Builder;
use PHPLLVM\Value;

/** LLVM lowering for is_uploaded_file() via __compiler_is_uploaded_file (issue #2204). */
final class JitIsUploadedFile
{
/** @return Value */
public static function invoke(Context $context, Value $pathStr): Value
{
StringFsDir::ensureLinked($context);

$i32 = $context->getTypeFromString('int32');
$ret = $context->builder->call(
$context->lookupFunction('__compiler_is_uploaded_file'),
$pathStr
);
$one = $i32->constInt(1, false);

return $context->builder->icmp(Builder::INT_EQ, $ret, $one);
}
}
3 changes: 3 additions & 0 deletions ext/standard/JitMoveUploadedFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace PHPCompiler\ext\standard;

use PHPCompiler\JIT\Builtin\StringFsDir;
use PHPCompiler\JIT\Context;
use PHPLLVM\Builder;
use PHPLLVM\Value;
Expand All @@ -14,6 +15,8 @@ final class JitMoveUploadedFile
/** @return Value */
public static function invoke(Context $context, Value $fromStr, Value $toStr): Value
{
StringFsDir::ensureLinked($context);

$i32 = $context->getTypeFromString('int32');
$ret = $context->builder->call(
$context->lookupFunction('__compiler_move_uploaded_file'),
Expand Down
1 change: 1 addition & 0 deletions ext/standard/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ public function getFunctions(): array
new chmod_(),
new rename_(),
new move_uploaded_file(),
new is_uploaded_file(),
new copy_(),
new move_uploaded_file(),
new touch_(),
Expand Down
46 changes: 46 additions & 0 deletions ext/standard/is_uploaded_file.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\ext\standard;

use PHPCompiler\Frame;
use PHPCompiler\Func\Internal;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPCompiler\VM\Variable;
use PHPLLVM\Value;

/** is_uploaded_file() — VM via VmFs; JIT/AOT via __compiler_is_uploaded_file (issue #2204). */
final class is_uploaded_file extends Internal
{
public function __construct()
{
parent::__construct('is_uploaded_file');
}

public function execute(Frame $frame): void
{
if (1 !== \count($frame->calledArgs)) {
throw new \LogicException('is_uploaded_file() requires exactly one argument in this compiler build');
}
if (null === $frame->returnVar) {
return;
}
$pathVar = $frame->calledArgs[0]->resolveIndirect();
if (Variable::TYPE_STRING !== $pathVar->type) {
throw new \LogicException('is_uploaded_file() requires a string path in this compiler build');
}
$frame->returnVar->bool(VmFs::isValidUploadTempPath($pathVar->toString()));
}

public function call(Context $context, JITVariable ...$args): Value
{
if (1 !== \count($args)) {
throw new \LogicException('is_uploaded_file() requires exactly one argument in this compiler build');
}
$path = $this->jitString($context, $args[0], 'is_uploaded_file() path');

return JitIsUploadedFile::invoke($context, $path);
}
}
2 changes: 2 additions & 0 deletions lib/AOT/Linker.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ final class Linker
__DIR__.'/runtime/strtr.c',
__DIR__.'/runtime/filter_validate.c',
__DIR__.'/runtime/phpc_fs_dir.c',
__DIR__.'/runtime/phpc_upload_temp.c',
__DIR__.'/runtime/phpc_session_id_storage.c',
__DIR__.'/runtime/phpc_session_name_storage.c',
__DIR__.'/runtime/phpc_value_box.c',
Expand Down Expand Up @@ -50,6 +51,7 @@ final class Linker
/** Runtime units that need host libc headers (glob/scandir; llvm sysroot lacks linux/limits.h). */
private const RUNTIME_HOST_LIBC_BASENAMES = [
'phpc_fs_dir.c',
'phpc_upload_temp.c',
'preg_match.c',
'password_crypto.c',
];
Expand Down
9 changes: 7 additions & 2 deletions lib/AOT/runtime/builtin_function_names.inc
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ static const char *phpc_builtin_functions[] = {
"count",
"crc32",
"date",
"debug_backtrace",
"decbin",
"dechex",
"decoct",
Expand Down Expand Up @@ -102,6 +103,7 @@ static const char *phpc_builtin_functions[] = {
"glob",
"gmdate",
"hash",
"hash_equals",
"hash_hmac",
"header",
"header_list",
Expand Down Expand Up @@ -141,6 +143,7 @@ static const char *phpc_builtin_functions[] = {
"is_scalar",
"is_string",
"is_subclass_of",
"is_uploaded_file",
"is_writable",
"join",
"json_decode",
Expand All @@ -151,8 +154,8 @@ static const char *phpc_builtin_functions[] = {
"lstat",
"ltrim",
"max",
"md5",
"mb_strlen",
"md5",
"method_exists",
"microtime",
"min",
Expand Down Expand Up @@ -195,6 +198,7 @@ static const char *phpc_builtin_functions[] = {
"readlink",
"realpath",
"rename",
"restore_error_handler",
"rmdir",
"round",
"rtrim",
Expand All @@ -206,6 +210,7 @@ static const char *phpc_builtin_functions[] = {
"session_regenerate_id",
"session_start",
"session_write_close",
"set_error_handler",
"setcookie",
"setrawcookie",
"sha1",
Expand Down Expand Up @@ -275,4 +280,4 @@ static const char *phpc_builtin_functions[] = {
"web_string",
"wordwrap",
};
static const size_t phpc_builtin_functions_count = 268;
static const size_t phpc_builtin_functions_count = 279;
100 changes: 0 additions & 100 deletions lib/AOT/runtime/phpc_fs_dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,106 +389,6 @@ __string__ *__compiler_sys_get_temp_dir(void)
return cstr_to_string(dir);
}

#define PHPC_UPLOAD_TEMP_PREFIX "phpc_upload_"

static int phpc_path_has_parent_traversal(const char *path)
{
const char *p;
const char *start;

if (NULL == path) {
return 1;
}
start = path;
for (p = path; ; p++) {
if ('\0' == *p || '/' == *p) {
size_t len = (size_t) (p - start);
if (2 == len && 0 == strncmp(start, "..", 2)) {
return 1;
}
if ('\0' == *p) {
break;
}
start = p + 1;
}
}

return 0;
}

static int phpc_is_valid_upload_temp(const char *path)
{
char resolved[PATH_MAX];
char tmpdir[PATH_MAX];
const char *base;
const char *dir;
char *real_from;
char *real_tmp;
size_t tmp_len;

if (NULL == path || '\0' == path[0] || phpc_path_has_parent_traversal(path)) {
return 0;
}
base = strrchr(path, '/');
base = (NULL != base) ? base + 1 : path;
if (0 != strncmp(base, PHPC_UPLOAD_TEMP_PREFIX, strlen(PHPC_UPLOAD_TEMP_PREFIX))) {
return 0;
}
real_from = realpath(path, resolved);
if (NULL == real_from) {
return 0;
}
dir = getenv("TMPDIR");
if (NULL == dir || '\0' == *dir) {
dir = getenv("TEMP");
}
if (NULL == dir || '\0' == *dir) {
dir = getenv("TMP");
}
if (NULL == dir || '\0' == *dir) {
dir = "/tmp";
}
real_tmp = realpath(dir, tmpdir);
if (NULL == real_tmp) {
return 0;
}
tmp_len = strlen(real_tmp);
if (tmp_len + 1 >= sizeof(tmpdir)) {
return 0;
}
if ('/' != real_tmp[tmp_len - 1]) {
real_tmp[tmp_len] = '/';
real_tmp[tmp_len + 1] = '\0';
tmp_len++;
}
if (0 != strncmp(real_from, real_tmp, tmp_len)) {
return 0;
}

return 1;
}

/** move_uploaded_file() — rename upload temp only under system temp (issue #2005). */
int __compiler_move_uploaded_file(__string__ *from, __string__ *to)
{
const char *src;
const char *dst;

if (NULL == from || NULL == to) {
return 0;
}
src = phpc_strdata(from);
dst = phpc_strdata(to);
if (!phpc_is_valid_upload_temp(src) || phpc_path_has_parent_traversal(dst) || '\0' == dst[0]) {
return 0;
}
if (0 != rename(src, dst)) {
return 0;
}

return 1;
}

/** tempnam() — unique temp path in directory with prefix (issue #1201, #2005). */
__string__ *__compiler_tempnam(__string__ *directory, __string__ *prefix)
{
Expand Down
Loading