{"record":{"id":"87474c4b01af3505","repo":"diem/diem","slug":"unbound-local","errorCode":null,"errorMessage":"Unbound local {:?}","messagePattern":"Unbound local (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"language/move-prover/bytecode/src/read_write_set_analysis.rs","lineNumber":203,"sourceCode":"                self.locals.bind_local_node(*ret, node, caller_fun_env)\n            }\n        }\n        // (5) join caller and callee accesses\n        // TODO: can we do a strong update here in some cases?\n        self.accesses.join(&new_callee_accesses);\n    }\n\n    /// Copy the contents of `rhs_index` into `lhs_index`. Fails if `rhs_index` is not bound\n    pub fn copy_local(\n        &mut self,\n        lhs_index: TempIndex,\n        rhs_index: TempIndex,\n        fun_env: &FunctionEnv,\n    ) {\n        let rhs_value = self\n            .locals\n            .get_local(rhs_index, fun_env)\n            .unwrap_or_else(|| panic!(\"Unbound local {:?}\", rhs_index))\n            .clone();\n        self.locals.bind_local(lhs_index, rhs_value, fun_env)\n    }\n\n    pub fn assign_local(\n        &mut self,\n        lhs_index: TempIndex,\n        rhs_index: TempIndex,\n        func_env: &FunctionEnv,\n    ) {\n        if let Some(rhs_data) = self.locals.get_local(rhs_index, func_env).cloned() {\n            self.locals.bind_local(lhs_index, rhs_data, func_env);\n            self.record_access(rhs_index, Access::Read, func_env)\n        } else if let Some(rhs_node) = self.locals.get_local_node(rhs_index, func_env).cloned() {\n            self.locals.bind_local_node(lhs_index, rhs_node, func_env);\n        }\n    }\n","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/diem/diem/blob/fc4714a8ea273b6efe8b13dbce72ea60aad9a16c/language/move-prover/bytecode/src/read_write_set_analysis.rs#L185-L221","documentation":"`copy_local` reads the abstract value of a local from the analyzer's `locals` map; if the temp index has no bound value it panics with 'Unbound local'. The analysis tracks abstract addresses per TempIndex, and every read local must have been bound by a prior `assign_local`, `borrow_loc`, or parameter initialization. This panic means the instruction stream referenced a local before (or without) binding it in the abstract state.","triggerScenarios":"`copy_local(lhs_index, rhs_index, fun_env)` called with `rhs_index` never bound in the current abstract state — e.g. bytecode `CopyLoc` of a local whose abstract value was dropped/not initialized, or an out-of-sync temp index after bytecode transformation.","commonSituations":"Running the RWSet analysis over bytecode generated or rewritten by an external tool; stackless-bytecode passes that remove initialization of dead locals but leave later reads; mismatches between function signature temps and the analyzed body.","solutions":["Verify the offending bytecode instruction's temp index against the function's local/parameter list in fun_env","Ensure all locals are bound (via assign_local or parameter initialization) before `copy_local` reads them","Re-run bytecode verification/stackless transformation with a matched toolchain version so temp indices are consistent","If you added a bytecode pass, bind an abstract value for the local in the state before copying"],"exampleFix":"// before\nlet rhs_value = self.locals.get_local(rhs_index, fun_env)\n    .unwrap_or_else(|| panic!(\"Unbound local {:?}\", rhs_index)).clone();\n// after\nlet rhs_value = self.locals.get_local(rhs_index, fun_env)\n    .cloned()\n    .unwrap_or_else(|| AbsAddr::default()); // or skip/bail on unbound locals","handlingStrategy":"validation","validationCode":"// Before copy_local, check the source local is bound:\nfn local_bound(state: &TransferFunctionState, idx: TempIndex, fun_env: &FunctionEnv) -> bool {\n    idx < fun_env.get_local_count() && state.locals.get_local(idx, fun_env).is_some()\n}","typeGuard":"fn is_bound(state: &TransferFunctionState, idx: TempIndex, env: &FunctionEnv) -> bool {\n    state.locals.get_local(idx, env).is_some()\n}","tryCatchPattern":null,"preventionTips":["Bind all parameters/locals at function entry before interpretation","Avoid consuming (MoveLoc) locals that are later read","Run bytecode well-formedness verification before analysis"],"tags":["rust","move-prover","static-analysis","panic","unbound-local"],"backgroundTag":"unbound-local-temp-index","analyzedSha":"fc4714a8ea273b6efe8b13dbce72ea60aad9a16c","analyzedAt":"2026-09-04T21:07:05.890Z","contentChangedAt":"2026-09-04T21:07:05.890Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}