Commit cb54b2b
committed
fix(xml): XmlDocument::Load(filename) rejects an undeclared entity too (#2361)
#2082 rejects an undeclared entity reference by scanning the RAW text, because
tinyxml2 decodes the five predefined entities during parsing and "&nope;" and
"&nope;" are indistinguishable afterwards. LoadXml(string) has the raw text and ran
the check; Load(filename) handed the path straight to tinyxml2::LoadFile and never
held the bytes, so it did not.
So the identical document got two answers depending on which door it came through
-- and the file door's answer LOST DATA. Accepting the reference was recoverable;
reinterpreting it as literal text AND re-escaping it meant that loading and saving
a document changed the document, with no diagnostic anywhere.
Load now reads the file itself and parses the buffer, which is what
tinyxml2::LoadFile does internally anyway (read whole file, call Parse). The read
is BINARY: a text-mode read on Windows would collapse CRLF and move the offsets the
scanner walks.
THE FAILURE PATH DELIBERATELY STILL GOES THROUGH LoadFile. It is what produces
XML_ERROR_FILE_NOT_FOUND / FILE_COULD_NOT_BE_OPENED / FILE_READ_ERROR and the
ErrorStr() this exception message has always carried. Reproducing those categories
from an ifstream failure would be inventing diagnostics rather than keeping them,
so when the read fails the code lets tinyxml2 categorise its own failure and throws
the unchanged message.
TWO MUTATIONS ARE NOT MUTATIONS, and are recorded rather than counted as passes.
* Text mode instead of binary is a no-op ON THIS PLATFORM. Linux makes the two
modes identical, so the mutation is unobservable here by construction; the flag
is a correctness measure for a platform the gate does not run on.
* Parse(c_str()) without the length is SEMANTICALLY EQUIVALENT, and that was
verified by probe rather than assumed. Three NUL placements were measured
through both doors -- NUL mid-document, NUL after a complete document, and NUL
followed by more markup containing an undeclared entity -- and all six results
agree, because tinyxml2 stops at the NUL either way. The explicit length is kept
because it is the clearer spelling, not because a test defends it. The probe
binaries were deleted afterwards, per the build-resource policy.
Three real mutations caught: drop the entity check from Load; treat an unreadable
file as empty content; ReadWholeFile keeps only the first line.
Two cases added (Xml 507 -> 509), including the door-equivalence property itself
and an invariance case covering a legal document, a missing file, malformed
content, and the undeclared-PREFIX check (#2083) that always ran at this door.
Downstream, measured per SA-2 condition 5: neither cna nor mobile-eggbert
references XmlDocument outside their audit notes -- zero live sites in both.
Gate: 17,308 run, 17,308 passed, 0 failed, 0 skipped across 38 executables, GREEN.
docs/Migration-XmlDocumentLoadEntityCheck.md1 parent 331984a commit cb54b2b
5 files changed
Lines changed: 199 additions & 6 deletions
File tree
- docs
- modules/xml
- src/System/Xml
- tests/System/Xml
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
| 6 | + | |
5 | 7 | | |
6 | 8 | | |
7 | 9 | | |
| |||
97 | 99 | | |
98 | 100 | | |
99 | 101 | | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
100 | 122 | | |
101 | 123 | | |
102 | 124 | | |
| |||
548 | 570 | | |
549 | 571 | | |
550 | 572 | | |
551 | | - | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
552 | 595 | | |
553 | 596 | | |
554 | | - | |
555 | | - | |
556 | | - | |
557 | | - | |
| 597 | + | |
558 | 598 | | |
559 | 599 | | |
560 | 600 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
| 24 | + | |
23 | 25 | | |
24 | 26 | | |
25 | 27 | | |
| |||
255 | 257 | | |
256 | 258 | | |
257 | 259 | | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
258 | 326 | | |
259 | 327 | | |
260 | 328 | | |
| |||
Binary file not shown.
0 commit comments