Commit fb59905
Fix Markdown preview crash on UTF-8 files with >2MB size and <1.5M characters (#47391)
`NavigateToString` throws `ArgumentException` when previewing Markdown
files containing many multi-byte UTF-8 characters (e.g., CJK) — file
size exceeds 2MB but character count stays under 1.5M, bypassing the
guard.
## Summary of the Pull Request
The size guard in `MarkdownPreviewHandlerControl` used
`markdownHTML.Length` (character count / UTF-16 code units), but
WebView2's `NavigateToString` limit is measured in **bytes**. A string
with 700K CJK characters has only 700K `.Length` units but ~2.1MB of
UTF-8 bytes — enough to crash the API while passing the old check.
**Changes:**
- **`MarkdownPreviewHandlerControl.cs`**: Replace character-count guard
with UTF-8 byte count:
```csharp
// Before
if (markdownHTML.Length > 1_500_000)
// After
if (System.Text.Encoding.UTF8.GetByteCount(markdownHTML) > 1_500_000)
```
When the byte threshold is exceeded, content is written to a temp file
and loaded via `_browser.Source` instead of `NavigateToString` —
existing fallback path, now correctly triggered.
- **`MarkdownPreviewHandlerTest.cs`**: Added 3 regression tests to
prevent this class of bug from recurring:
1. Multi-byte UTF-8 content (CJK, <1.5M chars but >2MB bytes) →
temp-file navigation path
2. Small ASCII content within both thresholds → `NavigateToString` path
3. Large ASCII content exceeding 1.5M chars → temp-file navigation path
## PR Checklist
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
## Detailed Description of the Pull Request / Additional comments
The existing fallback (write HTML to a temp file, navigate via
`_browser.Source`) was already correct and handles arbitrarily large
content safely. The only bug was in the guard condition that decides
when to use it — it measured the wrong unit (characters vs. bytes).
Single-byte ASCII content is unaffected; only multi-byte Unicode content
was under-counted.
The tests use reflection to read the private `_localFileURI` field.
Since this field is set synchronously before `Controls.Add(_browser)`,
the check is race-free: once the wait loop exits with `Controls.Count >
0`, `_localFileURI` is guaranteed to have its final value.
## Validation Steps Performed
- Verified the fix by reasoning through the byte math: a file with 700K
CJK characters → `Length` = 700K (passes old check) → UTF-8 bytes ≈
2.1MB (fails new check → uses temp file path, no crash).
- Added 3 targeted unit tests in `UnitTests-MarkdownPreviewHandler`
covering the multi-byte threshold boundary; all 14 tests in the suite
pass (14/14).
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: MuyuanMS <116717757+MuyuanMS@users.noreply.github.com>
Co-authored-by: Muyuan Li (from Dev Box) <muyuanli@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent 38882fd commit fb59905
2 files changed
Lines changed: 145 additions & 2 deletions
File tree
- src/modules/previewpane
- MarkdownPreviewHandler
- UnitTests-MarkdownPreviewHandler
Lines changed: 3 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
182 | 182 | | |
183 | 183 | | |
184 | 184 | | |
185 | | - | |
186 | | - | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
187 | 188 | | |
188 | 189 | | |
189 | 190 | | |
| |||
Lines changed: 142 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
7 | 10 | | |
8 | 11 | | |
9 | 12 | | |
| |||
16 | 19 | | |
17 | 20 | | |
18 | 21 | | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
19 | 25 | | |
20 | 26 | | |
21 | 27 | | |
| |||
161 | 167 | | |
162 | 168 | | |
163 | 169 | | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 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 | + | |
164 | 306 | | |
165 | 307 | | |
0 commit comments