Skip to content

Fix lazy object inspection executing property hooks - #621

Open
mildabre wants to merge 37 commits into
nette:masterfrom
mildabre:lazy-property-hook-exposer
Open

Fix lazy object inspection executing property hooks#621
mildabre wants to merge 37 commits into
nette:masterfrom
mildabre:lazy-property-hook-exposer

Conversation

@mildabre

Copy link
Copy Markdown

When Tracy inspects a lazy object, reading a property via ReflectionProperty::getValue() may execute its getter hook.

This is unsafe for a debugging tool because a getter can execute arbitrary application code, mutate object state, initialize dependencies, or throw an exception — especially when the object is inspected in an incomplete lifecycle state.

This PR:

reads initialized properties using getRawValue() instead of getValue()
excludes virtual properties, which have no backing storage
keeps lazy and uninitialized properties excluded as before

A debugging tool should inspect the existing object state, not execute property getter code just to obtain a value.

dg and others added 30 commits July 18, 2026 02:36
- PHP 8.4 virtual hooked property renders as {virtual} instead of the
  misleading 'unset'
- WeakReference shows the target object or (dead)
- PHP 8.5 Uri\Rfc3986\Uri and Uri\WhatWg\Url show the address and components
- Closure shows the class of bound $this
- uninitialized lazy object exposes eagerly-initialized private and
  protected properties too and no longer throws on uninitialized ones
…d marker is written only after successful sending

- invalid $emailSnooze string (strtotime failure) silently disabled throttling and caused an email per error
- concurrent requests could both pass the mtime check and send duplicate emails (TOCTOU)
- when the mailer threw, the notification was lost for the whole snooze window
…r/Toggle init, keyboard activation of toggle links works; FileSession: concurrent GC no longer triggers warnings
…dds no information; Stringable message is cast to string
sendAssets() no longer throws when a second enable() runs after output
has started and there is nothing to send.
…beVar() dispatches via match

- the comparator returns 0 for unrelated pairs and understands
  interface-keyed exposers (class_exists() is false for interfaces)
- describeVar() uses match instead of building a method name from
  gettype(), so the calls are visible to static analysis
- getAttribute('href', 2) IE flag, keyCode, navigator.platform,
  window.screenLeft feature test, document.write() in the panel popup
- evalScripts() no longer accumulates executed <script> clones in the DOM
- non-browser agents (curl, HTTP clients, CI) can request markdown output
  by sending the X-Tracy-Agent header
- XMLHttpRequest patch no longer stacks a load listener per open() call
  and uses the current request id when the instance is reused
- a dump with a broken payload no longer aborts initialization of the
  remaining dumps on the page
Single helper replacing e.target everywhere; with shadow DOM coming,
composedPath()[0] is the element the event actually originated from.
Infrastructure for distributing styles as constructed stylesheets;
nothing consumes it yet.
CSS is no longer injected into the host page's document.head. Styles are
distributed as constructed stylesheets (adoptedStyleSheets) built from
the Tracy.css registry, so host-page styling cannot be affected by Tracy
and vice versa. This also makes Tracy styles work under CSP without
'unsafe-inline' style-src.

- Bar: <tracy-bar> shadow host, panels live inside a <tracy-div id=tracy-debug>
  wrapper kept for backward compatibility of third-party panel CSS; the
  panel popup window adopts the stylesheets explicitly in toWindow()
- BlueScreen: <tracy-bs> shadow host; the standalone error page keeps a
  document-level <style> so it renders without JavaScript
- standalone dumps: <tracy-dump> custom element with shadow root; upgrade is
  deferred while the parser is still constructing children
The shadow boundary now provides the isolation, so the #tracy-debug and
#tracy-bs selector prefixes and most of reset.css are no longer needed.
Layers are named tracy-base and tracy-components so they cannot collide
with the host page's own cascade layers (e.g. Tailwind).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants