Recursive AI

Fuzz results

All onedocument docs

The 1.0 fuzz campaign: every target in fuzz/run.sh for 600 s under libFuzzer with SharpFuzz instrumentation (the library assemblies and OneArchive), one process and one core per target, seeded from each target's WriteSeeds corpus. How to run and add targets: fuzz/README.md.

  • Run with tools/fuzz-campaign.sh prepare, then tools/fuzz-campaign.sh run 600 <target>...: one build, nine to eleven targets side by side per job (12 cores), per-input timeout 10 s, memory limit 1024 MB.
  • Machine: 32-core x64 build host, .NET 10.0.14, libFuzzer host and SharpFuzz as pinned in the tools directory.
  • A target is clean when it finishes its 600 s with no crash, hang, out-of-memory or invariant failure. All 70 targets finished clean on the final code. In the first pass six of the 62 targets then in fuzz/run.sh reported findings (five distinct causes, listed below); each was fixed, and the affected targets plus the targets that share the changed code were run again for 600 s.
  • exec/s is low for the targets that build whole documents per input (rtf, html, markdown, xlsb, richtext, doc, stream, pivot); the feature counts still plateaued.
  • Where a target ran twice, the row shows the final run; the first run is named in the last column.

Results

Executions, exec/s and features are from the final 600 s run of each target.

TargetsExecutionsexec/sFeaturesCrashes foundFixed in
formula60013,221,74821,99914,3561 (R1C1 text of an unquoted sheet name that reads as coordinates)5019576
formulaeval600400,30966630,6340-
finfuncs6004,067,7416,76818,6471 hang (CUMPRINC, periods past 2^53)9dcc11c
statfuncs600804,3901,33836,0851 hang (CUMIPMT, same loop)9dcc11c
funcs6004,578,4037,61759,2071 (PERCENTOF overflow gave infinity)9dcc11c
lookups6004,152,1536,90811,8100-
sniff6009,896,32116,4665,7200-
xml6005,677,6409,4464,4010-
markup6008,092,98513,4656,2360-
opc6001,843,1643,06621,2790-
cfb6003,752,7356,2447,7080-
sdt6004,597,2697,64916,4390-
sdtpath6008,596,14014,30311,0420-
text6008,938,90914,8738,1920-
revisions6007,545,25912,55417,7340-
stories6005,628,2719,36414,2980-
pptx6003,322,5675,52813,3120-
fieldinstr60022,705,25137,7795830-
fields6006,200,19110,31613,9900-
numfmt6004,822,9468,02415,2520-
numfmtfmt6008,182,63913,61512,5740-
sheet6003,970,6666,60616,2990-
sst6006,037,79710,0468,7220-
wbpart6006,652,51211,0699,9490-
styles6002,303,8073,83315,7770-
sheetfeat6002,403,8733,99914,7800-
table6002,077,9103,4578,0480-
pivot600207,71634512,0590-
csv6001,750,1822,91217,6070-
stream600203,22333813,9440-
streamwrite600861,7761,43315,2940-
template600770,8561,28030,3971 hang ({{ N:ak }} read 24 million variable names)9dcc11c
richtext60095,80015931,8690-
mailmerge600269,56444816,4190-
math6008,879,98814,77513,0070-
sheetrender6002,790,6104,64330,8850-
rtf60062,93110432,4700-
rtftree60013,991,41523,2802,0690-
smartart600584,21296526,9200-
doc600124,34420619,5640-
sprm60024,230,69240,3174220-
xls600472,13878561,2451 (lone surrogate in a string failed the shared string write)9dcc11c
ptg60017,070,53628,4036,9760-
ppt6002,018,8553,35928,4550-
xml20036003,158,9625,25620,9070-
xlsb60060,56110024,4970-
olepropset6002,871,3894,77711,5180-
oleobject6005,132,9858,5407,9240-
encinfo6005,580,1219,2844,6900-
filepass6008,539,30414,2082,2600-
html60034,8665823,3650-
markdown60048,6998140,7000-
markdownparse6005,846,4289,72722,4080-
vbacompress60021,427,45135,6523650-
vbadir6002,099,5593,4934,7490-
vbaproject6006,257,24510,4118,0930-
vbaremove6002,083,5373,4663,9870-
odfpkg6001,281,3272,13116,0660-
odt600196,64232724,6010-
odp600497,31182724,8600-
ods600429,18371443,2550-
openformula60017,621,04229,31911,4800-
chart6007,504,49512,48629,4986 files, 5 causes (see below)4d2df65
drawing6006,224,98410,35714,2966 files, 5 causes4d2df65
docparts6002,969,8824,94118,0500-
docxlayout600564,51593927,85814d2df65
pptxlayout600522,34486913,0540-
xlsxprint6003,744,2536,23039,04714d2df65
metafile600258,2364276,9123 files, 3 causes4d2df65
operations600113,41018828,1580-

Findings

Each reduced to the smallest formula, template or text that triggers it, and kept as a regression test.

FindingCauseFixTest
finfuncs, statfuncs hangCUMIPMT/CUMPRINC walked the periods with a double counter; past 2^53 p++ does not change p, so the loop never endedonly spans below 2^53 are walked, larger ones use the closed form (src/OneDocument/Calc/Functions/Financial/FinancialFunctions.cs)FuzzRegressionTests.CumulativePaymentsWithHugePeriodsReturnPromptly
funcs invariantPERCENTOF(256,4.4E-323) divided into infinity and returned it as a numbera non-finite quotient is #NUM! (Functions/Arrays/GroupFunctions.cs)PercentOfAnOverflowingQuotientIsANumberError
template timeout (27 s, 14 bytes){{ N:ak }} is a whole-column range; each cell reads a template variable, 24 columns × 1,048,576 rowsthe template resolver clips whole-axis areas to 256 rows or columns (Templating/TemplateEngine.cs)TemplateWholeColumnRangeIsBounded
xls untyped ArgumentExceptiona BIFF string with a lone UTF-16 surrogate: the shared-string encoder's quick scan did not flag it, so the part writer refused itthe scan flags surrogates and the encoder escapes the unpaired ones as _xHHHH_ (Spreadsheets/SharedStrings.cs)SharedStringEncodingEscapesLoneSurrogates
formula round tripR:1Shet3!E1 (A1 text) kept its unquoted spelling when printed as R1C1 text, where it reads as coordinates and parses as something elseR1C1 printing builds an unquoted prefix from its parts, so the name is quoted (Calc/FormulaPrinter.cs)R1C1TextQuotesSheetNamesThatLookLikeCoordinates

The formula target found the last one twice: the first input (R05C2:\xff!C:B) is the same cause. The target's own guard for such names had matched only word characters and was left unchanged, so the product fix is what the final run tested.

Output changes: R1C1 formula text now quotes an unquoted sheet prefix that reads as coordinates (it is not written to any file format); the shared-string part escapes unpaired surrogates as _xD800_, the way Excel does.

Second pass: the targets added for the gaps

Eight targets cover what the first pass listed as missing (chart also reads the chart-theme override part). docparts, pptxlayout and operations found nothing in 600 s. Everything below is in src/OneDocument.Rendering unless noted, and each has a reduced test in tests/OneDocument.Rendering.Tests/FuzzRegressionTests.cs. A common cause: OneRender's display list refuses coordinates that are not finite or lie beyond a billion pixels, sizes of zero and blur radii above 4096, and a hostile file can ask for any of them. Each painter now brings such values into range or leaves the shape out, and a list-limit exception becomes an OfficeLimitException.

TargetFindingFixTest
charta bar taller than the coordinate range (a value far beyond a fixed axis maximum)every coordinate the chart canvas writes is clamped (Charts/ChartCanvas.cs)ChartBarFarBeyondTheAxisPaints
charta font size of 1e90 and a font size of 0text sizes are clamped to 0 to 2000 points, and size 0 draws nothingChartTextWithAnAbsurdFontSizePaints, ChartTextWithAZeroFontSizePaints
chartSequence contains no elements: a group with no series, in the axis range, the category count and the radial, legend and funnel sizingMax over a possibly empty list takes a default (Charts/ChartRenderer*.cs)StackedBarGroupWithoutSeriesPaints
chart, drawinga display-list limit (too many points, glyphs or segments) escaped as OneRender's own exceptionChartPainter.Paint and DrawingPainter.DrawShapes throw OfficeLimitException("DisplayList")covered by the fuzz runs
drawinga path command with too few points (<a:moveTo/>) indexed past its argumentssuch a command draws nothing (Drawing/GeometryDefinition.cs)CustomGeometryCommandWithoutPointsDrawsNothing
drawinga shape placed at an offset of 1e50 EMU gave a transform beyond rangea shape whose transform is out of range is left out and noted drawing.shape-out-of-range (Drawing/DrawingPainter.cs)ShapeFarOffThePageIsLeftOut
drawingan outline width of 1e22 EMU pushed the stroked path out of rangeline widths are capped, and a path with an out-of-range coordinate is not drawnLineWithAnAbsurdWidthPaints
drawinga shadow offset or blur radius of 1e16offsets are clamped to a million pixels and blur to the list's 4096ShadowWithAbsurdOffsetAndBlurPaints
xlsxprinta print-titles name naming row 1,048,577 indexed past the last rowa title row outside 1 to 1,048,576 is ignored (Spreadsheets/SheetPrintSettings.cs)PrintTitlesOutsideTheSheetAreIgnored
docxlayouta page gutter of 6.7e14 twips put the first glyph out of rangepage size and margins are clamped to a million twips in the layout (Layout/Pages/SectionGeometry.cs); the hub still reports the stated valuePageWithAnAbsurdGutterPaints
metafiletransformed points beyond rangeevery transformed point is clamped (Metafiles/MetafileVisitor.cs)MetafilePathBeyondTheCoordinateRangePaints
metafilea record the list refuses part-way through left clips and transforms open, and the closing pop then threwthe painter tracks what it opened, closes it on failure, reports render.metafile-damaged and keeps what was drawn (Metafiles/MetafilePainter.cs, MetafileVisitor.cs)MetafileWithARecordTheListRefusesLeavesABalancedList (testdata/fuzz/metafile-record-refused.emf)
metafileOneImage's interpreter raised OverflowException on a pen record (EmfInterpreter.CreatePen)the adapter reports render.metafile-damaged for an arithmetic or index failure from the interpreter; the defect itself is OneImage'sMetafileThatOverflowsTheInterpreterIsReportedAsDamaged (testdata/fuzz/metafile-createpen-overflow.emf)

Output changes: a drawing shape beyond range, a chart value beyond range and a metafile record the list refuses are now left out instead of failing the page; page margins above a million twips are laid out as a million.

Parsers of untrusted input without a target

None known. The first pass listed DrawingML and chart parts, the Word style, numbering, section and table readers, document and slide layout, the metafile adapter, and the inspect, sanitise, redaction and accessibility passes; the eight targets above cover them. The remaining untargeted code reads only what other targets already feed it, or is not a parser: the SVG and PNG page writers, the PDF writers (OnePDF's) and the CLI argument parser.