{"record":{"id":"4a693ef079b5652e","repo":"Tencent/matrix","slug":"statbuffer-cutime-num","errorCode":null,"errorMessage":"${statBuffer}\ncutime: ${num}","messagePattern":"(.+?)\ncutime: (.+?)","errorType":"exception","errorClass":"ParseException","httpStatus":null,"severity":"warning","filePath":"matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/ProcStatUtil.java","lineNumber":263,"sourceCode":"                        window++;\n                    }\n                    String num = safeBytesToString(statBuffer, readIdx, window);\n                    if (!isNumeric(num)) {\n                        throw new ParseException(safeBytesToString(statBuffer, 0, statBuffer.length) + \"\\nstime: \" + num);\n                    }\n                    stat.stime = MatrixUtil.parseLong(num, 0);\n                    break;\n                }\n                case 16: { // cutime\n                    int readIdx = i, window = 0;\n                    // seek next space\n                    while (i < statBytes && !Character.isSpaceChar(statBuffer[i])) {\n                        i++;\n                        window++;\n                    }\n                    String num = safeBytesToString(statBuffer, readIdx, window);\n                    if (!isNumeric(num)) {\n                        throw new ParseException(safeBytesToString(statBuffer, 0, statBuffer.length) + \"\\ncutime: \" + num);\n                    }\n                    stat.cutime = MatrixUtil.parseLong(num, 0);\n                    break;\n                }\n                case 17: { // cstime\n                    int readIdx = i, window = 0;\n                    // seek next space\n                    while (i < statBytes && !Character.isSpaceChar(statBuffer[i])) {\n                        i++;\n                        window++;\n                    }\n                    String num = safeBytesToString(statBuffer, readIdx, window);\n                    if (!isNumeric(num)) {\n                        throw new ParseException(safeBytesToString(statBuffer, 0, statBuffer.length) + \"\\ncstime: \" + num);\n                    }\n                    stat.cstime = MatrixUtil.parseLong(num, 0);\n                    break;\n                }","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/Tencent/matrix/blob/3b8293bd65d47eeea7caf1f32a3a5d4d5eab60e7/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/ProcStatUtil.java#L245-L281","documentation":"ProcStatUtil parses the kernel /proc/<pid>/stat format field-by-field; field 16 (cutime, waited-for children's user time) must be numeric. When the token read for field 16 fails isNumeric(), it throws java.text.ParseException carrying the full raw stat buffer plus the offending token, so callers can see exactly which field of the proc entry was malformed.","triggerScenarios":"Calling ProcStatUtil.parseWithBuffer (via parseWithBufferForPath) on a /proc stat byte buffer whose field 16 does not parse as a number — e.g. truncated/partial read of /proc/<tid>/stat, a process exiting mid-read leaving a torn line, or kernel/vendor formats that shift field positions (comm containing unexpected bytes breaking field indexing).","commonSituations":"Reading stat of a thread/process that dies between open and read on a heavily loaded device; OEM kernels with modified /proc formatting; parsing stale buffers captured at app start when the process table is churning.","solutions":["Wrap the parse call in try-catch (ParseException) and skip/retry the sample instead of crashing battery monitoring.","Check the raw stat string in the exception message: verify field 16 (cutime) is an integer; recount fields after the '(comm)' section since spaces in comm shift the index.","Re-read /proc/<pid>/stat fresh — a torn/truncated read is the usual cause; retry usually succeeds.","If it reproduces on one device, dump the kernel version and compare /proc/self/stat output; consider falling back to parseWithSplits or disabling the collector on that ROM."],"exampleFix":"// before\nProcStat stat = ProcStatUtil.parseWithBufferForPath(path);\n// after\nProcStat stat;\ntry {\n    stat = ProcStatUtil.parseWithBufferForPath(path);\n} catch (ParseException e) {\n    MatrixLog.w(TAG, \"bad stat: \" + e.getMessage());\n    stat = null; // skip this sample\n}","handlingStrategy":"try-catch","validationCode":"String raw = readProcStat(pid);\nif (raw != null && raw.contains(\")\") && raw.split(\"\\\\s+\").length >= 22) {\n    stat = ProcStatUtil.parseWithBufferForPath(path);\n}","typeGuard":"static boolean looksLikeValidStat(String raw) {\n    if (raw == null || raw.indexOf(')') < 0) return false;\n    String[] parts = raw.split(\"\\\\s+\");\n    return parts.length >= 22 && parts[16].matches(\"\\\\d+\") && parts[17].matches(\"\\\\d+\");\n}","tryCatchPattern":"try {\n    stat = ProcStatUtil.parseWithBufferForPath(path);\n} catch (ParseException e) {\n    Log.w(TAG, \"stat parse failed, skipping sample: \" + e.getMessage());\n    stat = null;\n}","preventionTips":["Always catch ParseException around /proc stat parsing — files can be torn when processes exit.","Re-read rather than fail on first error; transient truncation is common under process churn.","Log the raw stat line from the exception message for device-specific format debugging.","Field positions shift if comm contains spaces — count from after the ')' character."],"tags":["android","procfs","parse","battery-monitoring"],"backgroundTag":"invalid-argument-format","analyzedSha":"3b8293bd65d47eeea7caf1f32a3a5d4d5eab60e7","analyzedAt":"2026-09-08T08:01:39.722Z","contentChangedAt":"2026-09-08T08:01:39.722Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}