{"record":{"id":"2aa2ba79a9fec803","repo":"iBotPeaches/Apktool","slug":"mark-not-set","errorCode":null,"errorMessage":"Mark not set","messagePattern":"Mark not set","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"brut.j.util/src/main/java/brut/util/BinaryDataInputStream.java","lineNumber":345,"sourceCode":"    @Override\n    public int available() throws IOException {\n        return (int) Math.min(in.available(), remaining());\n    }\n\n    @Override\n    public synchronized void mark(int readlimit) {\n        // We can't throw an exception here, so mark even if mark isn't supported, since reset won't work anyway.\n        in.mark(readlimit);\n        mMark = mPosition;\n    }\n\n    @Override\n    public synchronized void reset() throws IOException {\n        if (!markSupported()) {\n            throw new IOException(\"Mark not supported\");\n        }\n        if (mMark == -1) {\n            throw new IOException(\"Mark not set\");\n        }\n        in.reset();\n        mPosition = mMark;\n    }\n}\n","sourceCodeStart":327,"sourceCodeEnd":351,"githubUrl":"https://github.com/iBotPeaches/Apktool/blob/79b63384d7d7e22917e6ea8b453272da7012515b/brut.j.util/src/main/java/brut/util/BinaryDataInputStream.java#L327-L351","documentation":"BinaryDataInputStream.reset() throws when reset() is called without a preceding mark(): the internal mark field still holds its -1 sentinel. The underlying stream may support marks, but this wrapper has no recorded position to rewind to.","triggerScenarios":"Calling reset() before any mark() on the same stream instance, or after logic paths where mark() was skipped (conditional parsing branches that only mark sometimes).","commonSituations":"Parser control flow where one branch marks and rewinds while another reaches the same reset() call without marking; refactors that move mark() into a guard block; copy-paste of reset() into a second parse loop sharing the stream.","solutions":["Guarantee mark() is called on every path that can later reach reset() (mark at loop/function entry)","Track a boolean or check the mark state before reset()","Restructure so mark and reset stay in the same scope/try block","Add a unit test covering the branch that previously skipped mark()"],"exampleFix":"// before\nif (needsLookahead) { in.mark(64); peek(); }\nin.reset(); // Mark not set when needsLookahead was false\n\n// after\nin.mark(64);\nif (needsLookahead) { peek(); in.reset(); } else { /* no rewind needed */ }","handlingStrategy":"validation","validationCode":"// Pair every reachable reset() with a guaranteed mark()\nfinal boolean[] marked = { false };\nRunnable mark = () -> { in.mark(BUF); marked[0] = true; };\n// before reset:\nif (!marked[0]) throw new IllegalStateException(\"reset() without mark() on this path\");\nin.reset();","typeGuard":null,"tryCatchPattern":"try {\n    in.reset();\n} catch (IOException e) {\n    if (\"Mark not set\".equals(e.getMessage())) {\n        // control-flow bug: mark was skipped on this path — fix the caller, do not retry\n        throw new IllegalStateException(\"Parser bug: reset reached without mark\", e);\n    }\n    throw e;\n}","preventionTips":["Call mark() at function/loop entry so every path has a mark","Keep mark and reset in the same try block or scope","Unit-test all branches of conditional-lookahead parsing"],"tags":["java","stream","mark-reset","parser"],"backgroundTag":null,"analyzedSha":"79b63384d7d7e22917e6ea8b453272da7012515b","analyzedAt":"2026-08-14T10:43:28.812Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}