{"record":{"id":"1206225b31af4885","repo":"NationalSecurityAgency/ghidra","slug":"cannot-commit-self-score-with-the-matrix-scorer","errorCode":null,"errorMessage":"Cannot commit self-score with the matrix scorer","messagePattern":"Cannot commit self-score with the matrix scorer","errorType":"exception","errorClass":"LSHException","httpStatus":null,"severity":"error","filePath":"Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/client/ExecutableScorer.java","lineNumber":284,"sourceCode":"\t\treturn score[a - 1][b - 1];\n\t}\n\n\t/**\n\t * Retrieve the similarity score of an executable with itself\n\t * @param a is the index of the executable\n\t * @return its self-similarity score\n\t * @throws LSHException if the score is not accessible\n\t */\n\tpublic float getSelfScore(int a) throws LSHException {\n\t\treturn score[a - 1][a - 1];\n\t}\n\n\t/**\n\t * Commit the singled out executables self-significance score to permanent storage\n\t * @throws LSHException if there's a problem writing, or the operation isn't supported\n\t */\n\tpublic void commitSelfScore() throws LSHException {\n\t\tthrow new LSHException(\"Cannot commit self-score with the matrix scorer\");\n\t}\n\n\t/**\n\t * Commit a self-significance score for a specific executable to permanent storage\n\t * @param md5 is the 32-character md5 hash of the executable\n\t * @param selfScore is the self-significance score\n\t * @throws LSHException if there's a problem writing, or the operation isn't supported\n\t */\n\tprotected void commitSelfScore(String md5, float selfScore) throws LSHException {\n\t\tthrow new LSHException(\"Cannot commit self-score with the matrix scorer\");\n\t}\n\n\t/**\n\t * Get score of executable (as compared to our singled out executable)\n\t * @param a is the index of the executable\n\t * @return the score\n\t */\n\tpublic float getScore(int a) {","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/client/ExecutableScorer.java#L266-L302","documentation":"Thrown by the no-arg commitSelfScore() on the base ExecutableScorer class, which implements many-to-many matrix scoring. The matrix scorer holds scores only in an in-memory float[][] array and has no ScoreCaching backing store, so persisting a self-score is architecturally unsupported. Only the subclass ExecutableScorerSingle overrides this method to delegate to a ScoreCaching implementation (e.g. FileScoreCaching).","triggerScenarios":"Calling scorer.commitSelfScore() (the no-arg overload) on an ExecutableScorer instance whose runtime type is the base ExecutableScorer rather than ExecutableScorerSingle. This happens when code instantiates ExecutableScorer directly for many-to-many comparison and then attempts to persist the singled-out executable's self-significance score.","commonSituations":"A developer copies code from a one-to-many (ExecutableScorerSingle) workflow into a many-to-many (ExecutableScorer) workflow and forgets that persistence is only available on the single scorer. Also seen when a generic method accepts an ExecutableScorer reference and calls commitSelfScore() without checking the concrete subclass.","solutions":["If you need to persist self-scores, construct an ExecutableScorerSingle (passing a ScoreCaching such as FileScoreCaching) instead of the base ExecutableScorer.","If you intentionally use the matrix scorer, remove the commitSelfScore() call — the matrix stores all scores in memory and does not need persistence for its own operation.","If you must persist from a matrix context, extract the self-score via getSelfScore(int) and write it to your own ScoreCaching implementation manually."],"exampleFix":"// before\nExecutableScorer scorer = new ExecutableScorer();\nscorer.setSingleExecutable(md5);\nscorer.commitSelfScore(); // throws LSHException\n\n// after\nExecutableScorerSingle scorer =\n    new ExecutableScorerSingle(new FileScoreCaching(cachePath));\nscorer.setSingleExecutable(md5);\nscorer.commitSelfScore(); // delegates to FileScoreCaching","handlingStrategy":"type-guard","validationCode":"if (scorer instanceof ExecutableScorerSingle) {\n    ((ExecutableScorerSingle) scorer).commitSelfScore();\n} else {\n    // matrix scorer: no persistence; read scores in-memory only\n    float selfScore = scorer.getSelfScore(scorer.getSingleExeXref());\n}","typeGuard":"public static boolean canCommitSelfScore(ExecutableScorer scorer) {\n    return scorer instanceof ExecutableScorerSingle;\n}","tryCatchPattern":"try {\n    scorer.commitSelfScore();\n} catch (LSHException e) {\n    if (e.getMessage().contains(\"matrix scorer\")) {\n        // expected for base ExecutableScorer; no action needed\n    } else {\n        throw e;\n    }\n}","preventionTips":["Check the concrete scorer type before calling commitSelfScore.","Use ExecutableScorerSingle whenever you need persistent self-scores.","Design generic methods to accept ExecutableScorerSingle if they rely on commitSelfScore."],"tags":["bsim","ghidra","scorer","architecture","unsupported-operation"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}