Skip to content

[flutter_markdown] Invalid double parsing image URL in flutter_markdown #146739

Closed
flutter/packages
#6518
@collinjackson

Description

@collinjackson

Steps to reproduce

In the example project for flutter_markdown, go to minimal_markdown_demo.dart. Change the value of _data to '![Flutter logo](https://storage.googleapis.com/cms-storage-bucket/0dbfcc7a59cd1cf16282.png#100x)' (or replace the file with the code sample below). Then run the project (on any platform).

Related issue: FlutterFlow/flutterflow-issues#2581

Why this matters: Markdown is often dynamic, user provided content. A malicious user could render an app unusable in places where their content appears.

Expected results

It should render a square Flutter logo with a width of 100.

Actual results

Invalid double error, preventing the page from rendering. This is caused by parsing an empty string as a double. See stack trace below.

Code sample

Code sample

Overwrite minimal_markdown_demo.dart with the following:

import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import '../shared/markdown_demo_widget.dart';

// ignore_for_file: public_member_api_docs

const String _data = '''
![Flutter logo](https://storage.googleapis.com/cms-storage-bucket/0dbfcc7a59cd1cf16282.png#x200)''';

class MinimalMarkdownDemo extends StatelessWidget
    implements MarkdownDemoWidget {
  const MinimalMarkdownDemo({super.key});

  static const String _title = 'Double Parse Crash';

  @override
  String get title => MinimalMarkdownDemo._title;

  @override
  String get description => 'Double Parse Crash example.';

  @override
  Future<String> get data => Future<String>.value(_data);

  @override
  Future<String> get notes => Future<String>.value('');

  @override
  Widget build(BuildContext context) {
    return const Markdown(
      data: _data,
    );
  }
}

Screenshots or Video

Screenshots / Video demonstration Actual: ![Screenshot 2024-04-14 at 10 10 09 AM](https://github.com/flutter/flutter/assets/394889/649f32de-4344-491a-9fba-4acbde5cb116) Expected: ![Screenshot 2024-04-14 at 10 11 12 AM](https://github.com/flutter/flutter/assets/394889/d2318cb4-58fe-40b0-837a-b6266f3457c7)

Logs

Logs
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following FormatException was thrown building MinimalMarkdownDemo:
Invalid double

The relevant error-causing widget was:
  MinimalMarkdownDemo
  MinimalMarkdownDemo:file:///Users/jackson/repos/packages/packages/flutter_markdown/example/lib/screens/home_screen.dart:25:11

When the exception was thrown, this was the stack:
#0      double.parse (dart:core-patch/double_patch.dart:112:28)
#1      MarkdownBuilder._buildImage (package:flutter_markdown/src/builder.dart:572:25)
#2      MarkdownBuilder.visitElementAfter (package:flutter_markdown/src/builder.dart:494:11)
#3      Element.accept (package:markdown/src/ast.dart:53:15)
#4      Element.accept (package:markdown/src/ast.dart:50:17)
#5      MarkdownBuilder.build (package:flutter_markdown/src/builder.dart:203:12)
#6      _MarkdownWidgetState._parseMarkdown (package:flutter_markdown/src/widget.dart:382:25)
#7      _MarkdownWidgetState.didChangeDependencies (package:flutter_markdown/src/widget.dart:325:5)
#8      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5629:11)
#9      ComponentElement.mount (package:flutter/src/widgets/framework.dart:5456:5)
...     Normal element mounting (71 frames)
#80     Element.inflateWidget (package:flutter/src/widgets/framework.dart:4335:16)
#81     Element.updateChild (package:flutter/src/widgets/framework.dart:3846:18)
#82     SliverMultiBoxAdaptorElement.updateChild (package:flutter/src/widgets/sliver.dart:858:37)
#83     SliverMultiBoxAdaptorElement.createChild.<anonymous closure> (package:flutter/src/widgets/sliver.dart:843:20)
#84     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2844:19)
#85     SliverMultiBoxAdaptorElement.createChild (package:flutter/src/widgets/sliver.dart:835:12)
#86     RenderSliverMultiBoxAdaptor._createOrObtainChild.<anonymous closure> (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:349:23)
#87     RenderObject.invokeLayoutCallback.<anonymous closure> (package:flutter/src/rendering/object.dart:2686:59)
#88     PipelineOwner._enableMutationsToDirtySubtrees (package:flutter/src/rendering/object.dart:1097:15)
#89     RenderObject.invokeLayoutCallback (package:flutter/src/rendering/object.dart:2686:14)
#90     RenderSliverMultiBoxAdaptor._createOrObtainChild (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:338:5)
#91     RenderSliverMultiBoxAdaptor.addInitialChild (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:424:5)
#92     RenderSliverFixedExtentBoxAdaptor.performLayout (package:flutter/src/rendering/sliver_fixed_extent_list.dart:274:12)
#93     RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#94     RenderSliverEdgeInsetsPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:139:12)
#95     _RenderSliverFractionalPadding.performLayout (package:flutter/src/widgets/sliver_fill.dart:160:11)
#96     RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#97     RenderViewportBase.layoutChildSequence (package:flutter/src/rendering/viewport.dart:601:13)
#98     RenderViewport._attemptLayout (package:flutter/src/rendering/viewport.dart:1555:12)
#99     RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1464:20)
#100    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#101    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#102    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#103    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#104    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#105    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#106    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#107    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#108    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#109    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#110    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#111    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#112    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#113    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#114    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#115    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#116    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#117    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#118    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#119    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#120    MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:173:12)
#121    _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1063:7)
#122    MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:237:7)
#123    RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:404:14)
#124    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#125    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#126    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#127    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#128    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#129    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#130    _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1440:11)
#131    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#132    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#133    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#134    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#135    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#136    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#137    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#138    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#139    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#140    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#141    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#142    ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:52:11)
#143    RenderStack._computeSize (package:flutter/src/rendering/stack.dart:582:43)
#144    RenderStack.performLayout (package:flutter/src/rendering/stack.dart:609:12)
#145    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#146    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#147    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#148    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#149    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#150    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#151    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#152    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#153    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#154    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#155    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#156    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#157    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#158    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#159    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#160    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#161    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#162    RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3726:14)
#163    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#164    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#165    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:21)
#166    RenderObject.layout (package:flutter/src/rendering/object.dart:2575:7)
#167    RenderBox.layout (package:flutter/src/rendering/box.dart:2389:11)
#168    _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:968:13)
#169    _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1282:9)
#170    RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2414:7)
#171    PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1051:18)
#172    PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1064:15)
#173    RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:582:23)
#174    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:991:13)
#175    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:448:5)
#176    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1386:15)
#177    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1311:9)
#178    SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1169:5)
#179    _invoke (dart:ui/hooks.dart:312:13)
#180    PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:399:5)
#181    _drawFrame (dart:ui/hooks.dart:283:31)

════════════════════════════════════════════════════════════════════════════════════════════════════


Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.19.3, on macOS 14.4.1 23E224 darwin-arm64, locale en-US)
[!] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    ✗ cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.
[✓] Xcode - develop for iOS and macOS (Xcode 15.3)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2023.1)
[✓] IntelliJ IDEA Ultimate Edition (version 2023.3.4)
[✓] VS Code (version 1.88.0)
[✓] Connected device (4 available)
    ! Error: Browsing on the local area network for Collin’s iPhone. Ensure the device is unlocked and attached with a cable or associated with the same local area
      network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
[✓] Network resources

! Doctor found issues in 1 category.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions