Commit ff6a0a6
committed
Snapshot add_ids' scope, retire dead registrations (#356)
Two findings on the shadow-mode id registry.
add_ids recorded one spec per attribute name over the *scope*, and the
replay re-walked that scope when something was signed — so the ids a
signature could resolve were the ones the tree carried by then, not the
ones xmlSecAddIDs had registered at the call. An element appended to the
scope afterwards became resolvable where the fast path had never
registered it; and the walk applied one name at a time across the whole
scope, where xmlSecAddIDs takes the elements in document order and the
names within each element. With <Y B="v"/><X A="v"/> and
add_ids(root, ['A', 'B']), the raw path signs Y and the shadow signed X:
both happily, over different content.
RecordIds now expands the scope where the registration happens: one spec
per element carrying one of the names, element by element in document
order, names in the caller's order. Specs are single-node throughout —
AddIdsBelow, the replay's subtree walk and the duplicate check's XPath
probe over a scope are gone — so the shadow registers exactly the
attributes the caller registered, never one that appeared later.
A registration also outlived its element. The registry holds the element
proxy (lxml refuses weak references) and released the slot only with the
whole document entry, so a document that registers and drops temporary
elements grew without bound, and kept claiming their id values:
registering a value a dropped element had carried raised "duplicated
id." where the fast path, whose id entry dies with the attribute,
accepts it. A slot is now retired when the registry holds the only
reference to the proxy, the tree it hangs in is not its document's, and
no other proxy remains anywhere in that tree — exactly when lxml frees
such a subtree and libxml2 drops the id entries of the attributes in it.
Vacated slots are reused, so neither the elements nor the list grow, and
the sweep runs before every registration and before every duplicate
check.
What this does not reproduce is lxml clearing its own id entry whenever
an element is *moved* — even within the one document, and for a whole
subtree when an ancestor moves (verified against lxml's id hash). The
registry cannot observe a move, so a #id the fast path stops resolving
keeps resolving under the shadow, to the element it was registered for
and never to another one. Documented with the other divergences.
Cost, worst case (2000 id-bearing elements): add_ids 0.000 -> 0.035 s,
the sign that follows 11 -> 14 ms, and 2000 register_id calls on that
document 0.54 -> 1.18 s, each call now sweeping 2000 registrations.
328 passed / 6 skipped on the mismatch build, also at
PYXMLSEC_TEST_ITERATIONS=50; 340 / 6 on the matched static wheel, plain
and with PYXMLSEC_FORCE_SHADOW=1. 10k sign+verify with an element
registered and dropped per iteration: RSS 26.2 -> 26.3 MiB, output
byte-identical throughout; 20k registration churn on one document
25.9 -> 25.9 MiB, where it was 27.2 -> 34.0 before. Three new tests fail
on the shadow path before the fix and pass on the raw path; two more
guard against retiring a registration that is still live.1 parent b86e624 commit ff6a0a6
5 files changed
Lines changed: 393 additions & 132 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
217 | 217 | | |
218 | 218 | | |
219 | 219 | | |
220 | | - | |
221 | | - | |
222 | | - | |
223 | | - | |
224 | | - | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
225 | 235 | | |
226 | 236 | | |
227 | 237 | | |
228 | 238 | | |
229 | 239 | | |
230 | 240 | | |
231 | | - | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
232 | 249 | | |
233 | 250 | | |
234 | 251 | | |
| |||
238 | 255 | | |
239 | 256 | | |
240 | 257 | | |
241 | | - | |
242 | | - | |
| 258 | + | |
| 259 | + | |
243 | 260 | | |
244 | 261 | | |
245 | 262 | | |
| |||
292 | 309 | | |
293 | 310 | | |
294 | 311 | | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
295 | 319 | | |
296 | 320 | | |
297 | 321 | | |
| |||
0 commit comments