Skip to content

Crash: "Infinity or NaN toInt" in _createRealSizePartialImage — non-finite pageScale (2.4.7) #687

Description

@yairfaye

Summary

PdfViewer throws Unsupported operation: Infinity or NaN toInt from
_PdfViewerState._createRealSizePartialImage during real-size partial
rendering, when the computed pageScale is non-finite (Infinity or NaN).
The value reaches .toInt() unguarded and throws.

This is a distinct path from the two existing reports:

Environment

  • pdfrx: 2.4.7 (latest at time of writing)
  • Flutter 3.44.6 / Dart 3.x
  • Observed on iOS; the code path is platform-independent
  • Non-fatal for us (thrown from an internal Timer), but frequent in production
    (hundreds of events across ~120+ users / 90 days) and it fails the high-res
    render + floods error tracking.

Captured stack (top frames)

#0  _PdfViewerState._createRealSizePartialImage (package:pdfrx/src/widgets/pdf_viewer.dart)
#1  _PdfViewerState._requestRealSizePartialImage.<anonymous closure> (package:pdfrx/src/widgets/pdf_viewer.dart)
#2  TickerFuture.whenCompleteOrCancel.thunk (package:flutter/src/scheduler/ticker.dart)
#3  _Timer._runTimers (dart:isolate-patch/timer_impl.dart)

Root cause (line numbers for 2.4.7)

pageScale divides by the page dimensions:

// pdf_viewer.dart ~L1567
final pageScale =
    scale * max(rect.width / page.width, rect.height / page.height);
if (!enableLowResolutionPagePreview || pageScale > previewScaleLimit) {
  _requestRealSizePartialImage(cache, page, pageScale, targetRect); // ~L1570
}

If page.width or page.height is 0 the division is Infinity; 0 / 0 is
NaN. A non-finite scale reaches the same point. It is then used unguarded:

// pdf_viewer.dart ~L1807-1810, in _createRealSizePartialImage
final x = (inPageRect.left * scale).toInt();
final y = (inPageRect.top * scale).toInt();
final width = (inPageRect.width * scale).toInt();   // throws on Infinity/NaN
final height = (inPageRect.height * scale).toInt();

double.toInt() throws UnsupportedError: Infinity or NaN toInt for a
non-finite receiver.

Suggested fix

A finite guard before the conversion — at the call site:

if (!pageScale.isFinite) return;   // before _requestRealSizePartialImage(...)

or inside _createRealSizePartialImage, before the .toInt() block:

if (!scale.isFinite) return null;

Guarding the page-dimension division (page.width == 0 || page.height == 0)
would remove the non-finite value at the source.

Repro notes

Data/timing dependent — reproduces with a page reporting a zero dimension, or
when the viewer is laid out in a transiently zero-sized box while a zoom render
is requested. The guard fixes it regardless of which input goes non-finite.

Related: #587, #550

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions