bug: onConsoleMessage OOMs on low-RAM Android — String.format runs on unbounded console message before any log-level/config gate
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 72/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Tranquilla
- Stack tecnologico
- android, java, javascript
- Ambito
- mobile-dev, observability
Direzione di ricerca
Inizia in android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java e segui onConsoleMessage attraverso isValidMsg, il comportamento del logging e la distribuzione per livello. Riproduci il problema con console.log('x'.repeat(100_000_000)) su un dispositivo o emulatore Android con risorse limitate; il lavoro è completato quando i messaggi sovradimensionati non causano più arresti anomali e il logging disabilitato evita il costo della formattazione.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Bug Report
Capacitor Version
@capacitor/cli: 6.2.1
@capacitor/core: 6.2.1
@capacitor/android: 6.2.1
The offending code is unchanged on main, so this affects v7 as well.
Platform(s)
Android (native WebView console bridge). Reproduces on low-RAM devices (e.g. TECNO Camon, ~192 MB WebView heap growth limit).
Current Behavior
BridgeWebChromeClient.onConsoleMessage calls String.format(...) on the entire JS console message unconditionally, before the log-level dispatch (and before any loggingBehavior gate). If a console.log/console.error argument is large — a serialized IndexedDB row, an axios error/response object, etc. — the JS string can be tens or hundreds of MB. Materializing it into a Java String blows the WebView heap on low-RAM devices → java.lang.OutOfMemoryError → hard crash.
Critically, setting loggingBehavior: 'none' / 'production' does not prevent it, because the String.format cost is paid before logging is gated.
Current code — android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java:
@Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
String tag = Logger.tags("Console");
if (consoleMessage.message() != null && isValidMsg(consoleMessage.message())) {
String msg = String.format( // runs on full, unbounded message
"File: %s - Line %d - Msg: %s",
consoleMessage.sourceId(),
consoleMessage.lineNumber(),
consoleMessage.message() // can be hundreds of MB
);
String level = consoleMessage.messageLevel().name();
// ... level dispatch happens AFTER the format ...
}
return true;
}
isValidMsg only filters specific string patterns, not size.
In our production app this was the #2 fatal crash (~5,300 events over 7 days from our Crashlytics). One affected device attempted a single ~266 MB (266,032,112-byte) allocation on every occurrence.
Note: this is a distinct code path from the OOM in #7158 (that one is in Cordova NativeToJsMessageQueue / PluginResult JSON encoding).
Expected Behavior
An oversized console message must never crash the app. The bridge should skip formatting when logging is disabled and/or bound the message length before String.format.
Code Reproduction
Minimal — in any Capacitor Android app, run in the WebView on a low-RAM device (or an emulator with a small WebView heap cap):
console.log('x'.repeat(100_000_000)); // ~100M chars
App crashes with java.lang.OutOfMemoryError. loggingBehavior: 'none' in capacitor.config does not prevent it.
Suggested Fix
Two complementary guards in onConsoleMessage:
private static final int MAX_CONSOLE_MESSAGE_LENGTH = 8 * 1024; // tunable
@Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
String tag = Logger.tags("Console");
if (consoleMessage.message() != null && isValidMsg(consoleMessage.message())) {
// 1) don't pay the format cost if logging is disabled
if (!Logger.shouldLog()) { // or the equivalent loggingBehavior check
return true;
}
// 2) bound the message so an oversized log can never OOM the bridge
String message = consoleMessage.message();
if (message.length() > MAX_CONSOLE_MESSAGE_LENGTH) {
message = message.substring(0, MAX_CONSOLE_MESSAGE_LENGTH) + "… [truncated]";
}
String msg = String.format(
"File: %s - Line %d - Msg: %s",
consoleMessage.sourceId(), consoleMessage.lineNumber(), message);
// ... existing level dispatch ...
}
return true;
}
Happy to open a PR with whatever threshold / config approach the team prefers.
- Lingua principale
- TypeScript
- Stelle
- 16.7k
- Fork
- 1.3k
- Merge medio
- 3g 10h
- PR unite (30g)
- 10
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di ionic-team/capacitor
-
triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
ionic-team/capacitor#8616 ·
-
triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
ionic-team/capacitor#8601 ·
-
triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
ionic-team/capacitor#8574 ·
-
SystemBars: safe area CSS injection throws "Cannot read properties of null" on startup (Android 16) Apertatriage
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
ionic-team/capacitor#8530 · 2 commenti ·
-
triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
ionic-team/capacitor#8529 ·
Tutte le issue di ionic-team/capacitor
Issue simili
-
calcite-components needs triage refactor
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
Esri/calcite-design-system#15203 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 91/100
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 95/100
-
Daemon passes --experimental-wasm-jspi unconditionally on Node >= 24; Node 26 rejects the flag Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
Automattic/studio#4908 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 90/100