Data: 2026-06-27
Repo analizzata: /Volumes/Extreme Pro/Claude/php-rust-experiment/php-rust
Obiettivo: suggerire interventi per rendere piu' robusto il runtime PHP-in-Rust, dopo l'introduzione del logging con log4rs.
L'aggiunta di log4rs e' una buona scelta: il progetto usa il facade log, il logging e' spento di default, e l'output va su stderr/file senza contaminare stdout, che deve restare byte-perfect per confronti con PHP.
Le aree dove ora conviene investire sono:
- Logging piu' affidabile e osservabilita' per fasi VM/corpus.
- Igiene repo contro file AppleDouble
._*, che gia' stanno disturbandogit. - Riduzione delle panics raggiungibili e gestione esplicita degli invarianti VM.
- Limiti di risorse configurabili: stack, heap, output, regex cache, include/autoload.
- Hardening di
php-server, che esiste ma non e' nel workspace Cargo. - Tooling di supply-chain, fuzzing e CI locale ripetibile.
Nota tooling: php-rust/CLAUDE.md richiede Serena/Vexp, ma in questa sessione tali MCP non erano disponibili tra gli strumenti esposti. La scansione e' stata fatta con rg, cargo metadata e letture mirate.
php-runtime/src/logging.rsinizializzalog4rsconPHPR_LOG,PHPR_LOG_FILE,PHPR_LOG_CONFIG.php-cliephpt-runnerchiamanophp_runtime::logging::init().- Sono presenti circa 10 call site
log::...!nel runtime: run/compile, include, gc, calls, exceptions. - Una ricerca su sorgenti runtime/builtins/types/cli/runner segnala circa 255 occorrenze
unwrap()/expect()nei sorgenti; molte sono invarianti interne o test inline, ma vanno classificate. - Sono presenti circa 11 occorrenze
unsafe, concentrate soprattutto in wrapper libc/filesystem. git statusha emesso errori su.git/objects/pack/._pack-...idx.- Esistono file
._*dentro sorgenti e crate, per esempiocrates/php-runtime/src/._mod.rs,crates/php-builtins/src/._array.rs,php-rust/._Cargo.toml. crates/php-server/Cargo.tomlesiste, macargo metadata --no-depsnon lo lista neiworkspace_members.- Non risultano config locali per
cargo-deny,cargo-audit, fuzzing,.github/workflows,clippy.tomlorust-toolchain.
Problema:
logging.rsignora il risultato dilog4rs::init_fileelog4rs::init_config.- Se
PHPR_LOG_CONFIGpunta a un file rotto, il logger puo' restare disattivato senza segnale. Onceimpedisce un secondo tentativo nello stesso processo anche dopo un errore iniziale.
Suggerimento:
- Aggiungere
pub fn try_init() -> Result<(), LoggingError>e lasciareinit()come wrapper silenzioso solo per compatibilita'. - In
phprephpt-runner, se l'utente ha impostatoPHPR_LOG*e l'inizializzazione fallisce, stampare un warning su stderr. - Accettare livelli case-insensitive (
WARN,Warn,warn) e renderePHPR_LOG=offesplicito. - Aggiungere una micro-suite di test per:
- logger off di default;
- config path inesistente;
- file appender non scrivibile;
PHPR_LOG_FILEche non deve mai scrivere su stdout.
Il logging oggi e' corretto ma ancora scarno. Aggiungerei target stabili:
phpr::lower: parse/lower start, failure class, line, construct.phpr::compile: unsupported compile con op/expr/stmt e file.phpr::vm: start/end run, fatal class, exit code.phpr::autoload: registrazione/rimozione loader, nome classe, recursion guard.phpr::builtin: missing builtin, host builtin error, warning routed.phpr::limits: superamento limiti runtime.phpr::phpt: test path, status, categoria skip/fail, durata.
Regola importante: non loggare valori PHP completi a livello info o debug se possono essere enormi o sensibili. A trace, troncare e indicare lunghezza.
Problema osservato:
- Ci sono file
._*nei sorgenti. git statusproduce errori su pack index AppleDouble dentro.git/objects/pack.- Le istruzioni locali citano gia' problemi Serena con
._*.rs.
Suggerimento:
- Aggiungere script
scripts/clean-appledouble.sh:- cancella
._*fuori da.git; - opzionalmente segnala quelli dentro
.gitinvece di cancellarli automaticamente.
- cancella
- Aggiungere script
scripts/preflight.shche fallisce se trova._*fuori da.git. - Aggiungere
.gitignorerobusto:._*.DS_Store**/._*
- Documentare per macOS/volumi esterni:
export COPYFILE_DISABLE=1- usare
dot_cleansolo consapevolmente su directory di lavoro, non alla cieca su.git.
Problema:
- Il VM usa molti
expect()su stack operand, frame, iteratori, class id e path. - Molti rappresentano invarianti reali del compilatore bytecode, ma se uno e' raggiungibile da PHP input diventa crash dell'host, non errore PHP.
Suggerimento:
- Introdurre una categoria
VmInvariantErrorcon:- opcode corrente;
- instruction pointer;
- frame/function;
- stack depth;
- file/line PHP se disponibile.
- Creare helper locali:
pop_stack(top, "OpName operand") -> Result<Zval, PhpError>;last_frame() -> Result<usize, PhpError>;expect_object_class(...) -> Result<ClassId, PhpError>.
- Priorita' di conversione:
- Stack pops nel main dispatch loop.
unwrap()in coroutine/generator/fiber state.expect()su sync method result e object class id.expect()in array/object path helpers.
- Lasciare
debug_assert!per invarianti provate dal compiler, ma evitare panic in build release.
phpt-runner --isolate gia' contiene i crash dei singoli test tramite processo figlio. phpr e php-server invece non hanno una boundary.
Suggerimento:
- In
phpr, valutarestd::panic::catch_unwindintorno arun_source_with_argv, restituendo exit code 255 e messaggio interno su stderr quando il runtime panica. - In
php-server, evitare che una panic inspawn_blockingdiventi.await.unwrap()e risponda con crash/task abort. - Loggare panic payload e backtrace quando
PHPR_LOGe' attivo.
Esiste gia' MAX_CALL_DEPTH = 25_000 e PHPT_TIMEOUT_SECS per isolate runner. Mancano pero' limiti omogenei.
Proposta:
pub struct RuntimeLimits {
pub max_call_depth: usize,
pub max_instructions: Option<u64>,
pub max_output_bytes: Option<usize>,
pub max_output_buffer_depth: usize,
pub max_include_depth: usize,
pub max_autoload_depth: usize,
pub max_preg_cache_entries: usize,
pub max_tracked_objects: Option<usize>,
}Usi:
- CLI: default molto permissivo, compatibile con PHP.
- phpt-runner: limiti diagnostici per catturare loop e memory blow-up.
- server: limiti stretti per richiesta.
- test differenziali: limiti fissi e loggati per riproducibilita'.
Punti da guardare:
preg_cache: HashMap<Vec<u8>, Option<Rc<Engine>>>e' per-run ma non sembra avere limite.included_files,autoloaders,autoloading,shutdown_fns,created,generators,fibers,enum_cache,constantscrescono con il programma.- Output buffering e stdout/rendered possono crescere senza soglia.
Suggerimento:
- Per CLI puro si puo' restare quasi illimitati.
- Per runner/server, applicare limiti configurabili e fatal PHP-like quando possibile.
- Aggiungere metriche finali a
phpr::run/phpr::limits: max frames, output bytes, objects tracked, includes, preg cache size.
Punti positivi:
preg.rsfissafancy_regexbacktrack limit a 1_000_000.
Da completare:
- Rendere il limite configurabile per test/server.
- Loggare quando una regex cade sul motore
fancy-regexinvece del motoreregex. - Mettere un limite alla cache PCRE per richiesta.
- Per
onig/mbregex, valutare timeout/limiti dove disponibili o almeno test di pattern patologici.
I builtins file usano direttamente il filesystem host. Questo e' corretto per CLI compatibility, ma non per server o harness non fidato.
Suggerimento:
- Introdurre una
FsPolicyopzionale:open_basedir;- allow/deny write;
- allow symlink follow;
- temp dir controllata;
- path canonicalization centralizzata.
- Il CLI default resta permissivo.
- Il server usa policy restrittiva.
crates/php-server e' il punto piu' acerbo.
Problemi osservati:
- Non e' membro del workspace root.
- Non chiama
php_runtime::logging::init(). - Path traversal difeso solo con
path.contains(".."). - Usa
spawn_blocking(...).await.unwrap(). - Usa
TcpListener::bind(...).await.unwrap()eaxum::serve(...).await.unwrap(). - Risponde sempre
Html<String>senza status code HTTP corretto. - Espone errori runtime come HTML/plain text.
Suggerimenti:
- Decidere: includerlo nel workspace o spostarlo fuori finche' non e' supportato.
- Se resta:
- aggiungere a
[workspace].members; - usare
PathBuf, percent-decoding e canonicalizzazione; - verificare che il path canonicale resti dentro
public/; - restituire
StatusCode; - configurare address/docroot da env/CLI;
- gestire
JoinErrorsenza panic; - inizializzare logging;
- non mostrare dettagli interni in risposta HTTP se non in debug.
- aggiungere a
Mancano config visibili per audit dipendenze e CI.
Suggerimento:
- Aggiungere
rust-toolchain.tomlper fissare toolchain. - Aggiungere
cargo fmt --check. - Aggiungere
cargo clippy --workspace --all-targets -- -D warningsalmeno in CI/preflight. - Aggiungere
cargo denycon:- advisory DB;
- licenze consentite;
- duplicate deps;
- ban/allow per crate native (
onig,libc, crypto).
- Aggiungere
cargo auditse non si usacargo deny advisories. - Aggiungere script
scripts/preflight.shche esegue:- clean/check AppleDouble;
- cargo metadata;
- fmt;
- clippy;
- test;
- phpt smoke selezionato.
Per un runtime di linguaggio, fuzzing e' molto redditizio.
Target consigliati:
-
Parser/lower/compiler:
- input: bytes PHP casuali o corpus mutato da Zend/tests;
- oracle: non deve panicare; se parse/lower fallisce deve tornare errore classificato.
-
VM bytecode invariants:
- input: programmi PHP piccoli generati;
- oracle:
phprnon deve panicare; output confrontato con PHP quando il programma e' nel subset supportato.
-
Builtins puri:
- array/string/number conversion/json/serialize/pack.
- usare
proptestcon confronto a oracle per casi piccoli.
-
Regex:
- pattern e subject generati con limiti;
- oracle: nessun hang, nessuna panic, errore classificato.
Setup:
cargo fuzzper fuzzing byte-level.proptestper proprieta' deterministiche.- corpus seed da
.phptridotti.
Il runner gia' distingue pass/fail/skip e categorie unsupported. Si puo' rendere ancora piu' utile:
- Ogni
Unsupporteddovrebbe avere codice stabile, non solo stringa. - Esempio:
LOWER_VARIABLE_VARIABLE,COMPILE_DYNAMIC_NAMED_CALL,VM_INVARIANT_STACK_UNDERFLOW. - Il runner aggrega per codice e stampa top-N con esempi.
- I log
phpr::phptincludono durata, categoria, fatal class e file. - Salvare report JSON opzionale:
--json-report out.json.
Le occorrenze unsafe sembrano concentrate su libc filesystem (statvfs, access, utimes). Suggerimento:
- Isolare ogni unsafe in funzioni piccole in un modulo
os. - Documentare invarianti sopra ogni unsafe block.
- Aggiungere test per path con byte non UTF-8, symlink, permessi, file mancanti.
- Valutare
cargo geigerperiodico per avere inventario.
- Aggiungere preflight AppleDouble e correggere la repo sporca.
- Rendere
logging::try_init()osservabile e aggiungere test logging. - Decidere destino di
php-server: nel workspace e hardened, oppure fuori scope. - Introdurre
RuntimeLimitsminimo: call depth, output bytes, preg cache entries. - Convertire i primi 20
expect()del VM dispatch in errori interni contestualizzati. - Aggiungere
cargo-deny/cargo-auditerust-toolchain.toml. - Avviare fuzzing su lower/compile "no panic".
Il progetto ha gia' una robustezza non banale: runner isolato con timeout, call-depth guard, backtrack limit regex, logging spento di default e stdout protetto. Il prossimo salto di qualita' e' trasformare queste buone difese locali in una politica coerente: preflight, limiti runtime, panic boundaries, errori invarianti e report riproducibili.