Skip to content

App crash (SIGTRAP / TRAP_BRKPT) when calling TextPainter.getPositionForOffset with specific string #163128

@MBulli

Description

@MBulli

Steps to reproduce

Calling TextPainter.getPositionForOffset() with a specific string results in SIGTRAP.
The actual string depends on the platform and probably the resolution of the display.

The sample code demonstrates the problem and implements a brute-force search to trigger the bug.
I was able to reliably reproduce the bug on a real Android device, the Android emulator and Windows.

Running the app should trigger the crash within a few seconds (5s to 30s).

After finding a random string, this string can be used to deterministically crash the application.

This crash happened in production with real data on a customer's phone.

Expected results

No crash.

Actual results

App crashes.

Code sample

Repo: https://github.com/MBulli/text_overflow_bug

Code sample
import 'dart:async';
import 'dart:math';

import 'package:flutter/material.dart';

void main() {
  runApp(const SearchForCrashValue());
}

class CrashOnMyDevice extends StatelessWidget {
  const CrashOnMyDevice({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: SizedBox(
          width: 100,
          child: TextLineOverflow('sgtkgdfamuqum', maxLines: 1), // crash on android phone
          //child: TextLineOverflow('pkcfrdsbihhoem', maxLines: 1), // crash on windows
        ),
      ),
    );
  }
}

/// Renders a lot of random strings that eventually lead to a crash
class SearchForCrashValue extends StatefulWidget {
  const SearchForCrashValue({super.key});

  @override
  State<SearchForCrashValue> createState() => _SearchForCrashValueState();
}

class _SearchForCrashValueState extends State<SearchForCrashValue> {
  @override
  void initState() {
    // After 1sec rebuild every 20ms
    Future.delayed(const Duration(seconds: 1)).then(
      (value) {
        Timer.periodic(
          const Duration(milliseconds: 20),
          (timer) {
            setState(() {});
          },
        );
      },
    );

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: SizedBox(
          width: 100,
          child: Column(children: _textLines(40).toList()),
        ),
      ),
    );
  }

  Iterable<Widget> _textLines(int count) sync* {
    for (var i = 0; i < count; i++) {
      final len = Random().nextInt(80) + 1;
      final text = _randomString(len).join();
      yield TextLineOverflow(text, maxLines: 1);
    }
  }

  Iterable<String> _randomString(int len) sync* {
    const chars = r'abcdefghijklmnopqrstvuxyz';

    for (var i = 0; i < len; i++) {
      final idx = Random().nextInt(chars.length);
      yield chars[idx];
    }
  }
}

/// Text('bla\nbla', maxLines: 1, overflow: TextOverflow.ellipsis) does not work.
/// See: https://github.com/flutter/flutter/issues/50168
/// So we do this ourselves.
class TextLineOverflow extends StatelessWidget {
  final String data;
  final int maxLines;
  final TextStyle? style;

  const TextLineOverflow(this.data, {super.key, required this.maxLines, this.style}) : assert(maxLines > 0);

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        assert(constraints.hasBoundedWidth);

        final text = TextSpan(text: data, style: style);
        final painter = TextPainter(
          text: text,
          maxLines: maxLines,
          textDirection: TextDirection.ltr,
          ellipsis: '…',
        );

        painter.layout(minWidth: constraints.minWidth, maxWidth: constraints.maxWidth);

        final String resolvedText;

        if (painter.didExceedMaxLines) {
          final textSize = painter.size;

          print('$data - $textSize');

          final pos = painter.getPositionForOffset(Offset(textSize.width, textSize.height));
          final endIndex = painter.getOffsetBefore(pos.offset - 1);

          resolvedText = data.substring(0, endIndex) + painter.ellipsis!;
        } else {
          resolvedText = data;
        }

        return Text(
          resolvedText,
          style: style,
        );
      },
    );
  }
}

Screenshots or Video

No response

Logs

Logs
/libc    ( 8549): Fatal signal 5 (SIGTRAP), code 1 (TRAP_BRKPT), fault addr 0x789da11fe4 in tid 8603 (1.ui), pid 8549 (lutter.fentools)
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'motorola/odessa_retaile/odessa:11/RPAS31.Q2-59-17-4-5-5/af8e3:user/release-keys'
Revision: 'pvt'
ABI: 'arm64'
Timestamp: 2025-02-12 11:42:43+0100
pid: 8549, tid: 8603, name: 1.ui  >>> eu.prologic.flutter.fentools <<<
uid: 10533
signal 5 (SIGTRAP), code 1 (TRAP_BRKPT), fault addr 0x789da11fe4
    x0  b400007a0b769b60  x1  0000000000000029  x2  b4000079eae640b0  x3  00000078a0d7a5b0
    x4  000000789da140e0  x5  0000000000000005  x6  00000078a0d7a7f0  x7  000000000000001b
    x8  0000000000000029  x9  0000000000000026  x10 0000000000000026  x11 0000000000000003
    x12 0000000094b23018  x13 0000000000000019  x14 bacff0e21ca2f0d7  x15 00000078a0d7aa60
    x16 000000789df4b740  x17 0000007b9d38cb8c  x18 0000007899426000  x19 b40000793ae90810
    x20 b400007a0b2ae2b0  x21 b400007a0b769b60  x22 0000000000000000  x23 0000000000000001
    x24 0000000000000029  x25 b400007a2ae5e960  x26 0000000000000000  x27 b400007a0b769b60
    x28 0000000000000000  x29 0000000000000001
    lr  000000789da1423c  sp  00000078a0d7a470  pc  000000789da11fe4  pst 0000000060000000
backtrace:
      #00 pc 0000000002047fe4  /data/app/~~8fvf0QOvz0q-EWAFooG9FA==/eu.prologic.flutter.fentools-eckGlM5TNsn5ofhxuvy8VQ==/base.apk!libflutter.so (offset 0x7254000) (BuildId: dd028ed52473eaf33cfedfebf17e6f82b3e82de6)
      #01 pc 000000000204a238  /data/app/~~8fvf0QOvz0q-EWAFooG9FA==/eu.prologic.flutter.fentools-eckGlM5TNsn5ofhxuvy8VQ==/base.apk!libflutter.so (offset 0x7254000) (BuildId: dd028ed52473eaf33cfedfebf17e6f82b3e82de6)
      #02 pc 0000000002047dc0  /data/app/~~8fvf0QOvz0q-EWAFooG9FA==/eu.prologic.flutter.fentools-eckGlM5TNsn5ofhxuvy8VQ==/base.apk!libflutter.so (offset 0x7254000) (BuildId: dd028ed52473eaf33cfedfebf17e6f82b3e82de6)
      #03 pc 0000000002047bc8  /data/app/~~8fvf0QOvz0q-EWAFooG9FA==/eu.prologic.flutter.fentools-eckGlM5TNsn5ofhxuvy8VQ==/base.apk!libflutter.so (offset 0x7254000) (BuildId: dd028ed52473eaf33cfedfebf17e6f82b3e82de6)
      #04 pc 000000000204a070  /data/app/~~8fvf0QOvz0q-EWAFooG9FA==/eu.prologic.flutter.fentools-eckGlM5TNsn5ofhxuvy8VQ==/base.apk!libflutter.so (offset 0x7254000) (BuildId: dd028ed52473eaf33cfedfebf17e6f82b3e82de6)
      #05 pc 0000000002047df8  /data/app/~~8fvf0QOvz0q-EWAFooG9FA==/eu.prologic.flutter.fentools-eckGlM5TNsn5ofhxuvy8VQ==/base.apk!libflutter.so (offset 0x7254000) (BuildId: dd028ed52473eaf33cfedfebf17e6f82b3e82de6)
      #06 pc 0000000002046178  /data/app/~~8fvf0QOvz0q-EWAFooG9FA==/eu.prologic.flutter.fentools-eckGlM5TNsn5ofhxuvy8VQ==/base.apk!libflutter.so (offset 0x7254000) (BuildId: dd028ed52473eaf33cfedfebf17e6f82b3e82de6)
      #07 pc 00000000020481dc  /data/app/~~8fvf0QOvz0q-EWAFooG9FA==/eu.prologic.flutter.fentools-eckGlM5TNsn5ofhxuvy8VQ==/base.apk!libflutter.so (offset 0x7254000) (BuildId: dd028ed52473eaf33cfedfebf17e6f82b3e82de6)
      #08 pc 0000000002042124  /data/app/~~8fvf0QOvz0q-EWAFooG9FA==/eu.prologic.flutter.fentools-eckGlM5TNsn5ofhxuvy8VQ==/base.apk!libflutter.so (offset 0x7254000) (BuildId: dd028ed52473eaf33cfedfebf17e6f82b3e82de6)
      #09 pc 0000000001fdaa20  /data/app/~~8fvf0QOvz0q-EWAFooG9FA==/eu.prologic.flutter.fentools-eckGlM5TNsn5ofhxuvy8VQ==/base.apk!libflutter.so (offset 0x7254000) (BuildId: dd028ed52473eaf33cfedfebf17e6f82b3e82de6)
      #10 pc 0000000002111dd0  /data/app/~~8fvf0QOvz0q-EWAFooG9FA==/eu.prologic.flutter.fentools-eckGlM5TNsn5ofhxuvy8VQ==/base.apk!libflutter.so (offset 0x7254000) (BuildId: dd028ed52473eaf33cfedfebf17e6f82b3e82de6)
      #11 pc 0000000000008264  [anon:dart-code]
Lost connection to device.

Exited.

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.27.3, on Microsoft Windows [Version 10.0.19045.5371], locale de-DE)
    • Flutter version 3.27.3 on channel stable at D:\lib\flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision c519ee916e (3 weeks ago), 2025-01-21 10:32:23 -0800
    • Engine revision e672b006cb
    • Dart version 3.6.1
    • DevTools version 2.40.2

[✓] Windows Version (Installed version of Windows is version 10 or higher)

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at D:\lib\android\android-sdk
    • Platform android-35, build-tools 34.0.0
    • ANDROID_HOME = D:\lib\android\android-sdk
    • Java binary at: D:\Program Files\Android\Android Studio\jbr\bin\java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-b2043.56-10027231)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • Chrome at C:\Program Files (x86)\Google\Chrome\Application\chrome.exe

[✓] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.12.4)
    • Visual Studio at D:\Program Files\Microsoft Visual Studio\2022\Community
    • Visual Studio Community 2022 version 17.12.35707.178
    • Windows 10 SDK version 10.0.22000.0

[✓] Android Studio (version 2022.3)
    • Android Studio at D:\Program Files\Android\Android Studio
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-b2043.56-10027231)

[✓] VS Code (version 1.97.0)
    • VS Code at C:\Users\m.bullmann\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.104.0

[✓] Connected device (4 available)
    • moto g 9 plus (mobile) • ZY2282T9DM • android-arm64  • Android 11 (API 30)
    • Windows (desktop)      • windows    • windows-x64    • Microsoft Windows [Version 10.0.19045.5371]
    • Chrome (web)           • chrome     • web-javascript • Google Chrome 132.0.6834.196
    • Edge (web)             • edge       • web-javascript • Microsoft Edge 132.0.2957.140

[✓] Network resources
    • All expected network resources are available.

• No issues found!

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work lista: text inputEntering text in a text field or keyboard related problemsc: fatal crashCrashes that terminate the processdependency: skiaSkia team may need to help usfound in release: 3.29Found to occur in 3.29found in release: 3.30Found to occur in 3.30has reproducible stepsThe issue has been confirmed reproducible and is ready to work onteam-text-inputOwned by Text Input teamtriaged-text-inputTriaged by Text Input team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions