@@ -160,15 +160,24 @@ def verify_bug_with_full_context(
160160 # =====================================================================
161161 # LAYER 2: Synthesize barriers from preconditions
162162 # =====================================================================
163+ # CRITICAL FIX: Only mark safe if there is EVIDENCE that the barrier
164+ # condition holds (e.g., validated params, guard facts for this bug type).
165+ # Simply creating a barrier template is not proof — we need evidence
166+ # that the precondition (x != 0, len(x) > 0, x is not None) is enforced.
163167 if bug_variable :
164- synthesized = self ._synthesize_barrier_for_bug (
165- bug_type , bug_variable , crash_summary
168+ # Check if there's evidence the precondition is satisfied
169+ has_evidence = self ._has_precondition_evidence (
170+ bug_type , bug_variable , crash_summary , call_chain_summaries
166171 )
167- if synthesized :
168- result .synthesized_barriers .append (synthesized )
169- result .is_safe = True
170- result .verification_time_ms = (time .time () - start_time ) * 1000
171- return result
172+ if has_evidence :
173+ synthesized = self ._synthesize_barrier_for_bug (
174+ bug_type , bug_variable , crash_summary
175+ )
176+ if synthesized :
177+ result .synthesized_barriers .append (synthesized )
178+ result .is_safe = True
179+ result .verification_time_ms = (time .time () - start_time ) * 1000
180+ return result
172181
173182 # =====================================================================
174183 # LAYER 3: Learn invariants from codebase
@@ -187,7 +196,8 @@ def verify_bug_with_full_context(
187196 # LAYER 4: Interprocedural barrier propagation
188197 # =====================================================================
189198 interprocedural = self ._propagate_barriers_interprocedurally (
190- bug_type , bug_variable , call_chain_summaries
199+ bug_type , bug_variable , call_chain_summaries ,
200+ crash_summary = crash_summary
191201 )
192202 if interprocedural :
193203 result .synthesized_barriers .extend (interprocedural )
@@ -432,6 +442,66 @@ def _check_learned_protection(
432442 # For now, conservative: return False
433443 return False
434444
445+ # =========================================================================
446+ # LAYER 2 SUPPORT: Precondition Evidence Check
447+ # =========================================================================
448+
449+ def _has_precondition_evidence (
450+ self ,
451+ bug_type : str ,
452+ bug_variable : Optional [str ],
453+ crash_summary : CrashSummary ,
454+ call_chain_summaries : List [CrashSummary ],
455+ ) -> bool :
456+ """
457+ Check if there is concrete evidence that the barrier precondition holds.
458+
459+ A synthesized barrier is only trustworthy if there is evidence the code
460+ actually enforces the precondition. Without evidence, synthesizing a
461+ barrier template is meaningless — the code may not protect against the bug.
462+
463+ Evidence sources:
464+ - Guard facts that match the bug type (e.g., non-zero check for DIV_ZERO)
465+ - Validated params (caller checks value before passing)
466+ - Return guarantees from callees
467+
468+ Returns:
469+ True if there is concrete evidence the precondition is enforced
470+ """
471+ from .guard_to_barrier import get_protected_bugs
472+ from ..semantics .interprocedural_guards import BUG_TYPE_TO_GUARD_TYPES
473+
474+ # 1. Check if crash summary has guard facts for this bug type
475+ relevant_guard_types = BUG_TYPE_TO_GUARD_TYPES .get (bug_type , set ())
476+
477+ for block_id , guard_facts in crash_summary .intra_guard_facts .items ():
478+ for guard_type , variable , extra in guard_facts :
479+ if guard_type in relevant_guard_types :
480+ # Found a guard for the right bug type
481+ # Check if it protects the right variable
482+ if bug_variable is None or variable is None :
483+ return True
484+ if bug_variable in str (variable ) or str (variable ) in bug_variable :
485+ return True
486+
487+ # 2. Check if the bug type is in guarded_bugs
488+ if bug_type in crash_summary .guarded_bugs :
489+ return True
490+
491+ # 3. Check validated params from call chain
492+ for summary in call_chain_summaries :
493+ for param_idx , validations in summary .validated_params .items ():
494+ if validations and bug_variable and f'param_{ param_idx } ' == bug_variable :
495+ return True
496+
497+ # 4. Check return guarantees from callees
498+ for summary in call_chain_summaries :
499+ if bug_type in summary .guarded_bugs :
500+ return True
501+
502+ # No evidence found — the barrier can't be trusted
503+ return False
504+
435505 # =========================================================================
436506 # LAYER 4: Interprocedural Propagation
437507 # =========================================================================
@@ -440,18 +510,27 @@ def _propagate_barriers_interprocedurally(
440510 self ,
441511 bug_type : str ,
442512 bug_variable : Optional [str ],
443- call_chain_summaries : List [CrashSummary ]
513+ call_chain_summaries : List [CrashSummary ],
514+ crash_summary : Optional [CrashSummary ] = None
444515 ) -> List [BarrierCertificate ]:
445516 """
446517 Propagate barriers from callers to callees.
447518
448519 If caller validates parameter x, and callee uses x in a crash,
449520 the validation barrier protects the callee.
521+
522+ NOTE: A function's own return guarantees do NOT protect against its
523+ own internal bugs. E.g., if f() has return_guarantees={'nonnull'},
524+ that means f's *return value* is non-None, not that f is internally
525+ safe from NULL_PTR. Skip the crash function's own summary.
450526 """
451527 propagated = []
452528
453- # Check return guarantees from callees
529+ # Check return guarantees from callees (excluding crash function itself)
454530 for summary in call_chain_summaries :
531+ # A function's own return guarantee does not protect its internal ops
532+ if crash_summary is not None and summary is crash_summary :
533+ continue
455534 for guarantee_type in summary .return_guarantees :
456535 # Create barrier from guarantee
457536 if guarantee_type == 'nonempty' and bug_type == 'BOUNDS' :
0 commit comments