Skip to content

Commit 85fb0bd

Browse files
dulmarodmeta-codesync[bot]
authored andcommitted
[infer][llvm][swift] log DISubprogram-vs-instruction source-file mismatches (observability)
Summary: Detection-only scuba probe for the Swift wrong-source-attribution reports (synthesized accessors and real procedures anchored in the wrong file -- T273760556 / T273770363). Under cross-module optimization, swiftc can stamp a function's `DISubprogram` with a source file its body never references, while the body's per-instruction `DILocation`s keep the real file(s). `Llair2Textual.should_translate` routes each function to a per-source-file Textual module by its `DISubprogram` file, so a mis-stamped function lands in the wrong file's module and its reports anchor at unactionable lines. The misattribution has not reproduced locally even with the production toolchain, so this lands a zero-behaviour-change probe. For each translated Swift function whose `DISubprogram` file is a real source file that appears on *none* of the body's instruction `DILocation`s, it emits both a `swift_disubprogram_file_mismatch` count and a `StatsLogging.log_message_with_location` event carrying: - `proc` -- the (mangled) function name; - `flavor` -- `accessor` (`.get`/`.set`/`.modify`, the T273760556 shape) vs `function` (the T273770363 shape); - `subprogram=<file>:<line>` -- the file `should_translate` routed by; - `instr_files=[...]` -- the distinct real source files on the body's instructions (one file => routing by an instruction loc would be safe; several => CMO inlined across sources). That payload lets a production run answer, from scuba alone, how widespread the issue is, which flavour, and whether routing by instruction loc is a viable fix. Reviewed By: thomasorton Differential Revision: D107270071 fbshipit-source-id: 445c6532867b6fd3160db653c32cf491248c274e
1 parent 8b1c1ac commit 85fb0bd

1 file changed

Lines changed: 51 additions & 0 deletions

File tree

infer/src/llvm/Llair2Textual.ml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,6 +1767,55 @@ let update_formals_list formals_list formals_map =
17671767
List.map ~f:update_formal formals_list
17681768

17691769

1770+
let loc_file lang (loc : Llair.Loc.t) =
1771+
if Textual.Lang.is_c lang then loc.Llair.Loc.dir ^ "/" ^ loc.Llair.Loc.file
1772+
else loc.Llair.Loc.file
1773+
1774+
1775+
(* A real source file, i.e. not empty and not the [<compiler-generated>] DI marker. *)
1776+
let is_real_di_file f =
1777+
(not (String.is_empty f)) && not (String.equal f compiler_generated_di_marker)
1778+
1779+
1780+
(* Distinct real source files on the function body's instruction [DILocation]s (whole CFG). *)
1781+
let func_instr_files lang (func : Llair.func) =
1782+
Llair.Func.fold_cfg func IString.Set.empty ~f:(fun block acc ->
1783+
StdUtils.iarray_to_list block.Llair.cmnd
1784+
|> List.fold ~init:acc ~f:(fun acc inst ->
1785+
let f = loc_file lang (Inst.loc inst) in
1786+
if is_real_di_file f then IString.Set.add f acc else acc ) )
1787+
1788+
1789+
(* [accessor] for [.get]/[.set]/[.modify] property accessors, [function] otherwise. *)
1790+
let func_flavor func_name =
1791+
match FuncName.unmangled_name func_name with
1792+
| Some n
1793+
when String.is_substring n ~substring:Field.get_suffix
1794+
|| String.is_substring n ~substring:Field.set_suffix
1795+
|| String.is_substring n ~substring:Field.modify_suffix ->
1796+
"accessor"
1797+
| _ ->
1798+
"function"
1799+
1800+
1801+
(* Scuba probe (T273760556 / T273770363): the DISubprogram file [should_translate] routes by can be
1802+
one the body never references, anchoring reports in the wrong file. Fire when it's on no body
1803+
instruction. *)
1804+
let log_disubprogram_file_mismatch lang func_name (func : Llair.func) =
1805+
let func_file = loc_file lang func.Llair.loc in
1806+
if is_real_di_file func_file then
1807+
let instr_files = func_instr_files lang func in
1808+
if (not (IString.Set.is_empty instr_files)) && not (IString.Set.mem func_file instr_files) then (
1809+
StatsLogging.log_count ~label:"swift_disubprogram_file_mismatch" ~value:1 ;
1810+
StatsLogging.log_message_with_location ~label:"swift_disubprogram_file_mismatch"
1811+
~loc:(Format.asprintf "%s:%d" func_file func.Llair.loc.Llair.Loc.line)
1812+
~message:
1813+
(Format.asprintf "proc=%s flavor=%s subprogram=%s:%d instr_files=[%s]"
1814+
(FuncName.name func_name) (func_flavor func_name) func_file
1815+
func.Llair.loc.Llair.Loc.line
1816+
(String.concat ~sep:"," (IString.Set.elements instr_files)) ) )
1817+
1818+
17701819
let translate_code ~mode ~sourcefile_for_proc_state ~module_state proc_descs
17711820
(procdecl : Textual.ProcDecl.t) (func_name, func) =
17721821
let ModuleState.{lang; method_class_index; class_files_map} = module_state in
@@ -1775,6 +1824,8 @@ let translate_code ~mode ~sourcefile_for_proc_state ~module_state proc_descs
17751824
(FuncName.unmangled_name func_name)
17761825
(FuncName.name func_name) lang method_class_index class_files_map func.Llair.loc
17771826
in
1827+
if should_translate && Textual.Lang.is_swift lang then
1828+
log_disubprogram_file_mismatch lang func_name func ;
17781829
let formals_list = List.map ~f:Var.reg_to_var_name (StdUtils.iarray_to_list func.Llair.formals) in
17791830
let formals_map =
17801831
match procdecl.Textual.ProcDecl.formals_types with

0 commit comments

Comments
 (0)