Skip to content

Commit cfac2d8

Browse files
committed
docs: add changelog entries for issues #20, #42, #43, #44
1 parent 95a9ea4 commit cfac2d8

1 file changed

Lines changed: 45 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,51 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
### Security
11+
12+
- **Fix exponential-time entity recursion check** (#42, thanks @hey-jj). The
13+
WFC: No Recursion walks in the DTD validator re-visited entities once per
14+
path, so a 474-byte document with chained entity declarations took 8+
15+
seconds to parse and a 694-byte one about 22 hours. The walks (including
16+
parameter entities and ATTLIST-default validation) now memoize entities
17+
proven acyclic, making the check linear in the size of the DTD. Cycle
18+
detection is unaffected.
19+
- **Bound element nesting across entity expansions.** Entity replacement text
20+
is parsed by nested sub-parsers, which now inherit the outer parser's
21+
nesting depth so total element depth stays bounded by
22+
`ParseOptions::max_depth` instead of `max_depth` per expansion level.
23+
24+
### Fixed
25+
26+
- **General entity replacement text is parsed as content** per XML 1.0 §4.4
27+
(#43, thanks @hey-jj). `EntityRef` nodes now carry their parsed expansion
28+
as children: character references in declarations are expanded when
29+
replacement text is built (§4.5), nested entity references are included,
30+
and markup-bearing entities produce real element children instead of
31+
escaped text — while serialization still emits `&name;`, keeping
32+
round-trips lossless. Replacement text must match the content production
33+
(§4.3.2); unbalanced or split tags are rejected. Entity expansion is
34+
subject to the expansion counter, a nesting-depth cap, and the 5x
35+
amplification guard, matching libxml2. DTD content-model validation sees
36+
through entity references (§4.4.3), so entity-supplied elements are
37+
validated too.
38+
- **XPath `!=` uses its own existential semantics for node-sets** per XPath
39+
1.0 §3.4 (#44, thanks @hey-jj). `!=` was evaluated as `not(=)`, inverting
40+
empty-node-set comparisons and breaking multi-node sets (both `=` and `!=`
41+
can hold at once). Node-set vs boolean keeps boolean-conversion semantics;
42+
scalar comparisons are unchanged. An absent attribute step now also yields
43+
an empty node-set (false under both `=` and `!=`) instead of an
44+
empty-string sentinel.
45+
- **XPath filter-path continuations navigate instead of filtering** (#20,
46+
thanks @ancientcatz). `(//a)[1]/@href` parsed to the same AST as
47+
`(//a)[@href]`, so the trailing path acted as a predicate and
48+
`string((//a)[1]/@href)` returned the anchor text. A new
49+
`Expr::FilterPath` AST variant evaluates the continuation steps against
50+
the filter's node-set. **Breaking:** downstream exhaustive matches on
51+
`xpath::ast::Expr` must handle the new variant.
52+
853
## [0.4.4] - 2026-07-20
954

1055
### Security

0 commit comments

Comments
 (0)