Class: Bundler::Spinel::Localizer

Inherits:
Object
  • Object
show all
Defined in:
lib/bundler/spinel/localizer.rb

Overview

Upgrades a bare ‘miscompile` verdict (CRuby and Spinel agree to run but disagree on stdout) into a located one: the (file, line, variable) where a scalar local first diverges — via the value-bisection harness that lives in the spinel-dev repo (tools/value-bisect/bisect.sh).

Why: a miscompile reason of ‘diff:L2 cruby=“42” spinel=“0”` says two outputs differ but not why. The bisector traces every scalar local under both CRuby and a Spinel –debug build and reports the first to part ways, turning that into `localized:foo.rb:12 total cruby=42 spinel=0` — a line to look at.

Strictly best-effort and non-fatal. If the harness can’t be found (it’s a separate repo), can’t run (the engine dir is a bare binary with no compiler sources / no lldb), or can’t pin a scalar (the divergence is in output formatting, not a traced local), verify still returns the miscompile verdict unchanged — this only ever adds a ‘localized:` reason when it has one.

Instance Method Summary collapse

Constructor Details

#initialize(engine) ⇒ Localizer

Returns a new instance of Localizer.



22
23
24
# File 'lib/bundler/spinel/localizer.rb', line 22

def initialize(engine)
  @engine = engine
end

Instance Method Details

#localize(harness) ⇒ Object

Run the bisector on ‘harness` (a self-contained .rb; require_relative’d files are traced too) and return a short reason string, or nil when localization isn’t possible or didn’t pin a value.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/bundler/spinel/localizer.rb', line 29

def localize(harness)
  script = bisect_script or return nil
  # SPINEL_DIR points the bisector at the same compiler the engine uses;
  # it shells out to that checkout's spinel_analyze.rb / spinel_codegen.rb.
  # bisect.sh exits 1 *on divergence* (the case we want), so the exit code
  # is not a success signal — parse stdout regardless. stdout carries only
  # the single JSON object in --json mode; progress goes to stderr.
  out, _err, _st = Open3.capture3(
    { "SPINEL_DIR" => @engine.dir }, "sh", script, "--json", harness
  )
  line = out.lines.map(&:strip).reject(&:empty?).last or return nil
  verdict = begin
    JSON.parse(line)
  rescue JSON::ParserError
    return nil
  end
  format_verdict(verdict)
rescue StandardError
  nil
end