Skip to content

Inconsistent behavior and segfaults on Android Release build #129496

Description

@h0lg

Description

I'm running into some strange behavior and segfaults when using AngleSharp on Android Release builds to select elements via their ClassList from a HTML document.
I'm not sure whether this is an .NET Android runtime bug or an AngleSharp incompatibility with it, so I'm filing an issue in both repos. Here's the AngleSharp issue for reference.

Reproduction Steps

Find attached a .Net MAUI app with a reproduction for two cases:

  1. Selecting the .a nodes from a HTML snippet
<div>
    <div class='a b c'>oh</div>
    <div class='a b c'>hai</div>
    <div class='d e f'>maui</div>
</div>
  1. Selecting nodes from a complete, remote HTML document

Expected behavior

  1. Like in builds other than Android Release, 2 nodes should be found.
Image
  1. Nodes in a full, remote HTML document should be selected without the app crashing.
Image

Actual behavior

On Android Release build I notice that for case 1

  • only directly checking IElement.GetAttribute("class") yields the expected nodes
  • when using QuerySelectorAll or IElement.ClassList.Contains()
    • the selected nodes are duplicated for some reason
    • nodes that don't match the selector in the result set
    • the selected nodes on the first click are different from those on following selections - even though we select from the same snippet

Image Image

Selecting nodes from a complete, remote HTML document (case 2) works fine on other builds - but causes the app to crash with a segfault on Android Release:

Time	Device Name	Type	PID	Tag	Message
06-17 01:48:49.598	Google Pixel 8a	Info	1838	DropBoxManagerService	add tag=data_app_native_crash isTagEnabled=true flags=0x2
  Force finishing activity com.companyname.mauiapp1/crc64e632a077a20c694c.MainActivity
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	backtrace:
      #00 pc 000000000000bbac  <anonymous:7c649b9000>
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	1 total frames
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0067006e00690064 (read)
    x0  b400007a8c996b18  x1  0000000000000000  x2  0067006e00690064  x3  b400007a8ca425d0
    x4  0000000000000007  x5  b400007a8c9e5168  x6  b400007a9ca37f50  x7  b400007a9ca37f50
    x8  0000000000000000  x9  0000000000000000  x10 0000000000000008  x11 0000000000000004
    x12 0000000000000029  x13 0000007c41df0274  x14 0000000000000008  x15 b400007a8d760f98
    x16 0000007c649c4b48  x17 0000007c649c4b84  x18 0000007c6dbe4000  x19 0000000000000000
    x20 0000007864beb8b0  x21 0000007900bbb0f0  x22 0000000000000000  x23 0000000000000000
    x24 0000007900bbb190  x25 0000007900bbb1b0  x26 0067006e00690064  x27 0000000000000000
    x28 0000007fd9ef3310  x29 0000007fd9ef2c40
    lr  00000078793ac730  sp  0000007fd9ef2c40  pc  0000007c649c4bac  pst 0000000020001000
    esr 0000000092000004  vg  0000000000000002
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	esr: 0000000092000004 (Data Abort Exception 0x24)
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	pac_enabled_keys: 000000000000000f (PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY)
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	uid: 10364
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	pid: 10705, tid: 10705, name: nyname.mauiapp1  >>> com.companyname.mauiapp1 <<<
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	Cmdline: com.companyname.mauiapp1
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	Executable: /system/bin/app_process64
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	Process uptime: 8s
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	Timestamp: 2026-06-17 01:48:49.426520014+0200
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	ABI: 'arm64'
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	Revision: 'MP1.0'
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	Kernel Release: '6.1.145-android14-11-gfa1d6308d1fe-ab14691759'
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	Build fingerprint: 'google/akita/akita:16/CP1A.260505.005/15081906:user/release-keys'
06-17 01:48:49.582	Google Pixel 8a	Error	10768	DEBUG	*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
06-17 01:48:49.403	Google Pixel 8a	Info	10768	crash_dump64	performing dump of process 10705 (target tid = 10705)
06-17 01:48:49.401	Google Pixel 8a	Info	828	tombstoned	received crash request for pid 10705
06-17 01:48:49.401	Google Pixel 8a	Info	10768	crash_dump64	obtaining output fd from tombstoned, type: kDebuggerdTombstoneProto
06-17 01:48:49.378	Google Pixel 8a	Info	650	keystore2	system/security/keystore2/watchdog/src/lib.rs:371 - Watchdog thread idle -> terminating. Have a great day.
06-17 01:48:49.202	Google Pixel 8a	Error	10705	libc	Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x67006e00690064 in tid 10705 (nyname.mauiapp1), pid 10705 (nyname.mauiapp1)

Regression?

Haven't tried with earlier Fw versions.

Known Workarounds

No response

Configuration

.Net 10, Android, ARM64, Release build

Other information

Not sure whether this is related to the segfault - but on the original app, I was (on occasion, not reliably) able to catch a managed exception with the following stacktrace after something somewhere seemingly warmed up enough:

System.ArrayTypeMismatchException: Arg_ArrayTypeMismatchException
   at AngleSharp.Dom.TokenList.Add(String[] tokens)
   at AngleSharp.Css.Dom.ClassSelector.Match(IElement element, IElement scope)
   at AngleSharp.Css.Dom.CompoundSelector.Match(IElement element, IElement scope)
   at AngleSharp.Css.Dom.SelectorExtensions.<>c.<MatchAll>b__3_0(INode node, SelectorState state)
   at AngleSharp.Dom.NodeExtensions.<GetDescendantsAndSelf>d__8`1[[AngleSharp.Css.Dom.SelectorExtensions.SelectorState, AngleSharp, Version=1.4.0.0, Culture=neutral, PublicKeyToken=e83494dcdc6d31ea]].MoveNext()
   at AngleSharp.Css.Dom.SelectorExtensions.MatchAll(ISelector selector, IEnumerable`1 elements, IElement scope, List`1 result)
   at AngleSharp.Css.Dom.SelectorExtensions.MatchAll(ISelector selector, IEnumerable`1 elements, IElement scope)
   at AngleSharp.Dom.QueryExtensions.QuerySelectorAll[NodeList](NodeList nodes, String selectorText, INode scopeNode)
   at AngleSharp.Dom.Document.QuerySelectorAll(String selectors)

No clue what triggers the ArrayTypeMismatchException or why TokenList.Add appears. I don't see where it could be called from.
Maybe the managed stacktrace is mangled due to a prior segfault?
Looking into the AngleSharp source, I notice the following:

  • ClassSelector.Match() accesses Element.ClassList, which is a lazy-initialized TokenList. That lazy-initialization is not locked to be thread-safe - but without parallelized tasks initializing the ClassList on the same element, this shouldn't be an issue I guess.
  • the TokenList ctor calls via TokenList.Update into the SplitSpaces extension, implemented using ArrayPool<char>. Borrowed, uncleared arrays sound like something that could cause values to pop up in unexpected places.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions