Hacktoberfest 2026: die Issues, die Maintainer für den Oktober markiert haben – offen und einsteigerfreundlich. Hacktoberfest-Issues durchsuchen

[java-firestore] UserDataConverter throws IndexOutOfBoundsException on an empty __binary__ value

Offen Anfängerfreundlich
#14,634 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
2/5
Geschätzter Aufwand
1-3 Stunden
Anfängerfreundlichkeit
74/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Aktiv
Tech-Stack
google-cloud, java
Bereich
backend

Rechercherichtung

Lies java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UserDataConverter.java im Bereich von decodeBsonBinary in den Zeilen 414–425, wo der Issue-Aufruf bytes.byteAt(0) als ungeprüft bezeichnet. Füge einen Regressionstest für einen leeren __binary__-Wert hinzu und führe die relevanten Firestore-Unit-Tests aus. Die Aufgabe ist abgeschlossen, wenn das Decodieren einen feldspezifischen Decodierungsfehler statt IndexOutOfBoundsException meldet.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

Issue Details

UserDataConverter.decodeBsonBinary reads the subtype byte with bytes.byteAt(0) without checking that the __binary__ bytes are non-empty, so an empty __binary__ value throws ArrayIndexOutOfBoundsException (an IndexOutOfBoundsException) from DocumentSnapshot.get(...) instead of a decode error naming the field:

https://github.com/googleapis/google-cloud-java/blob/9de611fe5633e9f43c6081754c834cabcd0317bb/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UserDataConverter.java#L414-L425

Reachability. Writing these forms through the Firestore API is refused with INVALID_ARGUMENT by the emulator (587.0.0-emulators) and by both a Standard-edition and an Enterprise-edition database, so a document written through that API should never carry them (measured 2026-10-03). Writes through the Enterprise edition's MongoDB-compatible API were not tried. Even if the input is unreachable today, the decoder assumes something it does not check, and the consequence is an unchecked runtime exception from a getter, where a FirestoreException naming the malformed value would be expected. A length check before byteAt(0) would fix it.

Found while building an Apache Flink source on google-cloud-firestore (flink-gcp/flink-connector-gcp).

Environment

  • OS Type and Version: macOS 26 (arm64)
  • Java Version and JDK Vendor: Eclipse Temurin 17.0.20

The reproducer is offline: it builds the snapshot from a Document proto with com.google.cloud.firestore.Internal, the way the client does for a server response, and sends nothing.

Dependencies

  • Libraries-Bom: 26.90.0
    • google-cloud-firestore 3.49.0
  • Gax: 2.87.0
  • Auth: 1.54.0

The affected code is identical in 3.49.0 and on main.

Reproducer

package repro;

import com.google.cloud.NoCredentials;
import com.google.cloud.Timestamp;
import com.google.cloud.firestore.DocumentSnapshot;
import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.FirestoreOptions;
import com.google.cloud.firestore.Internal;
import com.google.cloud.firestore.Query;
import com.google.cloud.firestore.spi.v1.GrpcFirestoreRpc;
import com.google.firestore.v1.Document;
import com.google.firestore.v1.MapValue;
import com.google.firestore.v1.Value;
import com.google.protobuf.ByteString;

/** Offline: builds snapshots from protos as the client would receive them; nothing is sent. */
public class DecodeDefects {
  public static void main(String[] args) throws Exception {
    FirestoreOptions options =
        FirestoreOptions.newBuilder()
            .setProjectId("demo")
            .setCredentials(NoCredentials.getInstance())
            .build();
    Firestore db = options.getService();

    // 1. An __int__ beyond 32 bits is narrowed silently.
    long stored = (1L << 40) + 5;
    DocumentSnapshot wide = snapshot(options, reserved("__int__", Value.newBuilder().setIntegerValue(stored).build()));
    System.out.println("stored __int__: " + stored);
    System.out.println("decoded value:  " + wide.get("k"));
    Query query = db.collection("c").orderBy("k").startAfter(wide);
    System.out.println("cursor value:   " + query.toProto().getStructuredQuery().getStartAt().getValues(0).getMapValue());

    // 2. An empty __binary__ throws instead of failing with a decode error.
    DocumentSnapshot empty = snapshot(options, reserved("__binary__", Value.newBuilder().setBytesValue(ByteString.EMPTY).build()));
    try {
      System.out.println("decoded value:  " + empty.get("k"));
    } catch (RuntimeException e) {
      System.out.println("empty __binary__ threw: " + e);
    }
    System.exit(0);
  }

  static Value reserved(String key, Value value) {
    return Value.newBuilder().setMapValue(MapValue.newBuilder().putFields(key, value)).build();
  }

  static DocumentSnapshot snapshot(FirestoreOptions options, Value value) throws Exception {
    Timestamp now = Timestamp.now();
    Document document =
        Document.newBuilder()
            .setName("projects/demo/databases/(default)/documents/c/x")
            .setCreateTime(now.toProto())
            .setUpdateTime(now.toProto())
            .putFields("k", value)
            .build();
    try (GrpcFirestoreRpc rpc = new GrpcFirestoreRpc(options)) {
      return new Internal(options, rpc).snapshotFromProto(now, document);
    }
  }
}

Only the second case concerns this issue; the first is reported in #14633.

Logs and Stack Trace

stored __int__: 1099511627781
decoded value:  Int32Value{value=5}
cursor value:   fields {
  key: "__int__"
  value {
    integer_value: 5
  }
}

empty __binary__ threw: java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0

Behavior

Deterministic: any __binary__ whose bytes are empty.

Vorherrschende Sprache
Java
Sterne
2.1k
Forks
1.2k
Ø Merge
2 T. 21 Std.
Gemergte PRs (30 T.)
139

Entwicklungsumgebung

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus googleapis/google-cloud-java

Alle Issues in googleapis/google-cloud-java

Ähnliche Issues

Weitere Issues zu Java

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.