Problem
The ProtobufTools.readRawVarint32 method throws IllegalStateException when encountering corrupted or incomplete data in disk-buffered files. Since IllegalStateException is an unchecked exception, it propagates up the call stack unhandled, causing the entire application to crash.
Stack Trace
io.opentelemetry.contrib.disk.buffering.internal.utils.ProtobufTools.readRawVarint32 (ProtobufTools.java:32)
io.opentelemetry.contrib.disk.buffering.internal.storage.files.reader.DelimitedProtoStreamReader.getNextItemSize (DelimitedProtoStreamReader.java:46)
io.opentelemetry.contrib.disk.buffering.internal.storage.files.reader.DelimitedProtoStreamReader.readNext (DelimitedProtoStreamReader.java:23)
io.opentelemetry.contrib.disk.buffering.internal.storage.files.ReadableFile.readNext (ReadableFile.java:77)
io.opentelemetry.contrib.disk.buffering.internal.storage.Storage.doReadNext (Storage.java:120)
io.opentelemetry.contrib.disk.buffering.internal.storage.Storage.readNext (Storage.java:94)
io.opentelemetry.contrib.disk.buffering.internal.storage.StorageIterator.findNext (StorageIterator.java:80)
io.opentelemetry.contrib.disk.buffering.internal.storage.StorageIterator.hasNext (StorageIterator.java:41)
io.opentelemetry.android.features.diskbuffering.SignalFromDiskExporter.export (SignalFromDiskExporter.kt:73)
io.opentelemetry.android.features.diskbuffering.SignalFromDiskExporter.exportBatchOfLogs (SignalFromDiskExporter.kt:65)
io.opentelemetry.android.features.diskbuffering.SignalFromDiskExporter.exportBatchOfEach (SignalFromDiskExporter.kt:96)
io.opentelemetry.android.features.diskbuffering.scheduler.DefaultExportScheduler.onRun (DefaultExportScheduler.kt:31)
io.opentelemetry.android.internal.services.periodicwork.PeriodicRunnable.run (PeriodicRunnable.kt:24)
java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1167)
java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:641)
java.lang.Thread.run (Thread.java:920)
Root Cause
The crash occurs when:
- A varint is partially written to disk (e.g., app killed during write operation)
- On next app start,
readRawVarint32 attempts to read the incomplete varint
- The first byte has continuation bit set (
0x80-0xFF), indicating more bytes follow
input.read() returns -1 (EOF) because the file is truncated
- The method throws
IllegalStateException, which is not caught anywhere
Current Code
public static int readRawVarint32(int firstByte, InputStream input) throws IOException {
// ...
for (; offset < 32; offset += 7) {
int b = input.read();
if (b == -1) {
throw new IllegalStateException(); // ❌ Unchecked - causes app crash
}
// ...
}
// ...
}
Proposed Solution
Replace IllegalStateException with EOFException (or StreamCorruptedException), which is a checked exception that extends IOException. This forces callers to handle the error gracefully.
Benefits
Graceful Degradation: Callers can catch EOFException and skip corrupted messages instead of crashing
Better Error Messages: Provides context about where corruption occurred
Semantic Correctness: EOFException accurately describes the problem (unexpected end of file)
Forced Error Handling: Checked exception ensures all callers handle the error appropriately
Environment
Library: io.opentelemetry.android:okhttp-3.0-agent:0.9.1-alpha
Platform: Android
Occurrence: When reading corrupted/incomplete disk-buffered telemetry data
Problem
The
ProtobufTools.readRawVarint32method throwsIllegalStateExceptionwhen encountering corrupted or incomplete data in disk-buffered files. SinceIllegalStateExceptionis an unchecked exception, it propagates up the call stack unhandled, causing the entire application to crash.Stack Trace
io.opentelemetry.contrib.disk.buffering.internal.utils.ProtobufTools.readRawVarint32 (ProtobufTools.java:32)
io.opentelemetry.contrib.disk.buffering.internal.storage.files.reader.DelimitedProtoStreamReader.getNextItemSize (DelimitedProtoStreamReader.java:46)
io.opentelemetry.contrib.disk.buffering.internal.storage.files.reader.DelimitedProtoStreamReader.readNext (DelimitedProtoStreamReader.java:23)
io.opentelemetry.contrib.disk.buffering.internal.storage.files.ReadableFile.readNext (ReadableFile.java:77)
io.opentelemetry.contrib.disk.buffering.internal.storage.Storage.doReadNext (Storage.java:120)
io.opentelemetry.contrib.disk.buffering.internal.storage.Storage.readNext (Storage.java:94)
io.opentelemetry.contrib.disk.buffering.internal.storage.StorageIterator.findNext (StorageIterator.java:80)
io.opentelemetry.contrib.disk.buffering.internal.storage.StorageIterator.hasNext (StorageIterator.java:41)
io.opentelemetry.android.features.diskbuffering.SignalFromDiskExporter.export (SignalFromDiskExporter.kt:73)
io.opentelemetry.android.features.diskbuffering.SignalFromDiskExporter.exportBatchOfLogs (SignalFromDiskExporter.kt:65)
io.opentelemetry.android.features.diskbuffering.SignalFromDiskExporter.exportBatchOfEach (SignalFromDiskExporter.kt:96)
io.opentelemetry.android.features.diskbuffering.scheduler.DefaultExportScheduler.onRun (DefaultExportScheduler.kt:31)
io.opentelemetry.android.internal.services.periodicwork.PeriodicRunnable.run (PeriodicRunnable.kt:24)
java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1167)
java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:641)
java.lang.Thread.run (Thread.java:920)
Root Cause
The crash occurs when:
readRawVarint32attempts to read the incomplete varint0x80-0xFF), indicating more bytes followinput.read()returns-1(EOF) because the file is truncatedIllegalStateException, which is not caught anywhereCurrent Code