Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

[cloud_firestore]: Apple pipeline parser passes an NSString where FIRExprBridge is expected for findNearest `distance_field` (incompatible pointer types warning; unrecognized selector crash if reached)

Chiusa
#18,829 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
20/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Ferma
Stack tecnologico
ios, macos, objective-c
Ambito
backend

Direzione di ricerca

Read the find_nearest branch in the iOS and macOS FLTPipelineParser.m files and compare its distance_field handling with the nearby unnest branch. The open related PR #18607 already replaces this parser and wraps the field name correctly; check that PR's status before choosing work here. Done means the Apple parser passes an expression bridge for distance_field without the incompatible pointer warning.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Needs Attention platform: ios platform: macos plugin: cloud_firestore type: bug
Is there an existing issue for this?
  • I have searched the existing issues.
Which plugins are affected?

Other (cloud_firestore)

Which platforms are affected?

iOS, macOS

Description

In the Apple pipeline parser, the find_nearest stage reads distance_field as an NSString and passes it straight to the SDK's distanceField: parameter. That parameter is typed as an expression bridge (FIRExprBridge * / __FIRExprBridge * on SDK 13).

Build time: every iOS/macOS build prints this warning:

cloud_firestore-6.10.0/ios/cloud_firestore/Sources/cloud_firestore/FLTPipelineParser.m:1570:66: warning: incompatible pointer types sending 'NSString *' to parameter of type 'FIRExprBridge * _Nullable' [-Wincompatible-pointer-types]
 1570 |                                                    distanceField:distanceField];
      |                                                                  ^~~~~~~~~~~~~

Run time: the SDK stores the value and later sends it cppExprWithReader:, a method that NSString does not have. So any find_nearest stage that carries distance_field throws an uncaught NSInvalidArgumentException (unrecognized selector), and the app terminates.

Where

The plugin code is the same in every release since pipelines shipped, including the latest one:

Version iOS file:line
6.3.0 – 6.4.1 FLTPipelineParser.m:1105 (read), :1137 (pass)
6.5.0 :1188 (read), :1220 (pass)
6.9.0 – 6.10.0 :1538 (read), :1570 (pass)
7.0.0 (latest on pub.dev) FLTPipelineParser.m:1578 (read), :1610 (pass)
main @ 9b821bc18500b9ae55a9cb74b0be949cb64bcd19 same as 7.0.0
  • The macOS copy (macos/cloud_firestore/Sources/cloud_firestore/FLTPipelineParser.m) is byte-identical to the iOS file on main, so it has the same bug.
  • The code was introduced in d734cf0885 (#18183, "feat: support for Firestore Pipelines").
  • The file was last changed in aca14eab53 (#18783, SDK 13 rename), which did not touch this branch.

Permalinks (main @ 9b821bc):

The plugin code (7.0.0 / main):

NSString *distanceField = [args[@"distance_field"] isKindOfClass:[NSString class]]
                              ? args[@"distance_field"]
                              : nil;
...
stage = [[__FIRFindNearestStageBridge alloc] initWithField:embeddingField
                                               vectorValue:queryVector
                                           distanceMeasure:distanceMeasure
                                                     limit:limit
                                             distanceField:distanceField];   // NSString *
Why it crashes
  1. The SDK declares the parameter as an expression. firebase-ios-sdk 13.0.0, Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h L179-L185 (12.19.0 has the same declaration, with FIR names instead of __FIR):

    @interface __FIRFindNearestStageBridge : __FIRStageBridge
    - (id)initWithField:(__FIRFieldBridge *)field
            vectorValue:(FIRVectorValue *)vectorValue
        distanceMeasure:(NSString *)distanceMeasure
                  limit:(NSNumber *_Nullable)limit
          distanceField:(__FIRExprBridge *_Nullable)distanceField;
    

    https://github.com/firebase/firebase-ios-sdk/blob/13.0.0/Firestore/Source/Public/FirebaseFirestore/FIRPipelineBridge.h#L179-L185

  2. The SDK treats the stored value as an expression. Firestore/Source/API/FIRPipelineBridge.mm L839-L842 (13.0.0; the same lines in 12.19.0):

    if (_distanceField) {
      std::shared_ptr<Expr> cpp_distance_field = [_distanceField cppExprWithReader:reader];
      optional_value.emplace(
          std::make_pair(std::string("distance_field"), cpp_distance_field->to_proto()));
    }
    

    https://github.com/firebase/firebase-ios-sdk/blob/13.0.0/Firestore/Source/API/FIRPipelineBridge.mm#L839-L842

  3. Nothing catches the exception. This runs synchronously from executeWithCompletion: → cppPipelineWithReader: → cppStageWithReader:. Neither the plugin's executePipelineWithFirestore:... nor the Pigeon handler wraps the call in @try.

  4. The SDK's own Swift API wraps the name. It never passes a plain string (Firestore/Swift/Source/Stages.swift L314 @ 13.0.0):

    distanceField: distanceField.map { Field($0).toBridge() } ?? nil
    
  5. The same parser already does this correctly elsewhere. The unnest branch a few lines above wraps its optional index_field correctly (FLTPipelineParser.m L1567-L1569 @ main):

    __FIRExprBridge *indexFieldExpr =
        (indexFieldStr.length > 0) ? [[__FIRFieldBridge alloc] initWithName:indexFieldStr]
                                   : nil;
    

A minimal Objective-C program confirms the runtime failure mode. When an NSString stands in for the expression object and receives cppExprWithReader:, it raises:

NSInvalidArgumentException: -[NSTaggedPointerString cppExprWithReader:]: unrecognized selector sent to instance 0x...
Reproducing the issue

Build-time warning: add cloud_firestore (6.3.0 – 7.0.0) to a Flutter app and build for iOS or macOS. The warning above appears for FLTPipelineParser.m.

Runtime: the public Pipeline.findNearest(...) in cloud_firestore has no distanceField parameter today (lib/src/pipeline.dart L418, lib/src/pipeline_stage.dart L177-L208). So the native branch is reached through the public platform interface, which sends the stage map to the native parser unchanged. Add cloud_firestore_platform_interface to pubspec.yaml and run on iOS:

import 'package:cloud_firestore_platform_interface/cloud_firestore_platform_interface.dart';
import 'package:firebase_core/firebase_core.dart';

Future<void> reproduce() async {
  final firestore = FirebaseFirestorePlatform.instanceFor(
    app: Firebase.app(),
    databaseId: '(default)',
  );
  await firestore
      .pipeline([
        {'stage': 'collection', 'args': {'path': 'items'}},
      ])
      .addStage({
        'stage': 'find_nearest',
        'args': {
          'vector_field': 'embedding',
          'vector_value': [0.1, 0.2, 0.3],
          'distance_measure': 'cosine',
          'distance_field': 'distance',
        },
      })
      .execute();
}
  • Expected: the stage runs, and each result carries the computed distance in distance, as it does on web.
  • Actual (from the code path above): an uncaught NSInvalidArgumentException (-[... cppExprWithReader:]: unrecognized selector) terminates the app.

I traced this by reading the code. The runtime crash has not been run end to end on a device.

Proposed fix

Wrap the field name in the SDK's field expression bridge before passing it, as the unnest branch and the SDK's Swift FindNearest stage already do. The patch below targets main @ 9b821bc, with SDK 13 names. It applies cleanly to both the iOS and macOS copies (checked with git apply --check). Type-checked against the 13.0.0 header with clang -fsyntax-only -Wincompatible-pointer-types, the current call reproduces the warning and the patched call compiles without it.

--- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTPipelineParser.m
+++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTPipelineParser.m
@@ -1603,11 +1603,14 @@
           return nil;
         }
         FIRVectorValue *queryVector = [[FIRVectorValue alloc] initWithArray:numbers];
+        __FIRExprBridge *distanceFieldExpr =
+            (distanceField.length > 0) ? [[__FIRFieldBridge alloc] initWithName:distanceField]
+                                       : nil;
         stage = [[__FIRFindNearestStageBridge alloc] initWithField:embeddingField
                                                        vectorValue:queryVector
                                                    distanceMeasure:distanceMeasure
                                                              limit:limit
-                                                     distanceField:distanceField];
+                                                     distanceField:distanceFieldExpr];
       } else {
         if (error)
           *error = parseError([NSString stringWithFormat:@"Unknown pipeline stage: %@", stageName]);
--- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTPipelineParser.m
+++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTPipelineParser.m
@@ -1603,11 +1603,14 @@
           return nil;
         }
         FIRVectorValue *queryVector = [[FIRVectorValue alloc] initWithArray:numbers];
+        __FIRExprBridge *distanceFieldExpr =
+            (distanceField.length > 0) ? [[__FIRFieldBridge alloc] initWithName:distanceField]
+                                       : nil;
         stage = [[__FIRFindNearestStageBridge alloc] initWithField:embeddingField
                                                        vectorValue:queryVector
                                                    distanceMeasure:distanceMeasure
                                                              limit:limit
-                                                     distanceField:distanceField];
+                                                     distanceField:distanceFieldExpr];
       } else {
         if (error)
           *error = parseError([NSString stringWithFormat:@"Unknown pipeline stage: %@", stageName]);

For a 6.x patch release, the change is the same with the SDK 12 names: FIRExprBridge / FIRFieldBridge / FIRFindNearestStageBridge, at 6.10.0 FLTPipelineParser.m L1565-L1570.

Firebase Core version

firebase_core 4.15.0 (Firebase Apple SDK 12.19.0) with cloud_firestore 6.10.0. The code is unchanged in cloud_firestore 7.0.0 with firebase_core 5.0.0 (Firebase Apple SDK 13.0.0 via Swift Package Manager).

Flutter Version

3.47.5 (stable), Xcode 27.1 (27A9275)

Relevant Log Output
FLTPipelineParser.m:1570:66: warning: incompatible pointer types sending 'NSString *' to parameter of type 'FIRExprBridge * _Nullable' [-Wincompatible-pointer-types]
Flutter dependencies

cloud_firestore: 6.10.0, firebase_core: 4.15.0. Also checked against cloud_firestore: 7.0.0 / firebase_core: 5.0.0 and main.

Additional context and comments

Impact

  • Build: every iOS/macOS build of cloud_firestore 6.3.0 – 7.0.0 shows this warning. Projects that build with warnings as errors fail.
  • Run time today: low. The crash needs distance_field to reach the Apple parser, and the public cloud_firestore Dart API does not send it yet. Only callers that go through the platform interface can hit it.
  • Run time after a Dart change: when Pipeline.findNearest gains a distanceField option, every Apple app that uses it will crash. Web already supports this option.

Platform parity (related)

The distance_field argument is handled differently on each platform:

Platform Handling of distance_field
Web supported: cloud_firestore_web/lib/src/pipeline_expression_parser_web.dart L755-L767
Apple read, but with the wrong type (this issue)
Android ignored: PipelineStageHandlers.java L308-L338
Dart Pipeline.findNearest does not expose it

Related PR

#18607 (open; migrates the Apple plugin to Swift) replaces this file. Its PipelineParser.swift wraps the name correctly (distanceField.map { FieldBridge(name: $0) }), so merging it would also fix this. It currently has merge conflicts and predates the SDK 13 __ renames from #18783. Until it lands, the three-line fix above removes both the warning and the crash path.

Lingua principale
Dart
Stelle
9.3k
Fork
4.1k
Merge medio
1g 22h
PR unite (30g)
79

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di firebase/flutterfire

Tutte le issue di firebase/flutterfire

Issue simili

Altre issue su Dart

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.