Skip to content

Commit

Permalink
[inferhack] add cycle detection to type constant expansion in check_a…
Browse files Browse the repository at this point in the history
…gainst_type_structure

Reviewed By: jvillard

Differential Revision: D61140300

fbshipit-source-id: 99a5b93cab46ccfc7d834b5551c3bab0ba378f29
  • Loading branch information
Nick Benton authored and facebook-github-bot committed Aug 13, 2024
1 parent 826fd3f commit bcdb703
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 14 deletions.
34 changes: 20 additions & 14 deletions infer/src/pulse/PulseModelsHack.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,7 @@ let read_access_from_ts tdict =
let check_against_type_struct v tdict : DSL.aval DSL.model_monad =
let open DSL.Syntax in
let* inner_val = mk_fresh ~model_desc:"check against type struct" () in
let rec find_name tdict nullable_already =
let rec find_name tdict nullable_already visited_set =
let kind_field = TextualSil.wildcard_sil_fieldname Textual.Lang.Hack "kind" in
let* kind_boxed_int = eval_deref_access Read tdict (FieldAccess kind_field) in
let* kind_int_val = eval_deref_access Read kind_boxed_int (FieldAccess int_val_field) in
Expand Down Expand Up @@ -1521,23 +1521,29 @@ let check_against_type_struct v tdict : DSL.aval DSL.model_monad =
| Some rootname, Some type_prop_name ->
let rootname = replace_backslash_with_colon rootname in
L.d_printfln "got root_name = %s, type_prop_name = %s" rootname type_prop_name ;
let type_prop_field = TextualSil.wildcard_sil_fieldname Hack type_prop_name in
let* companion =
get_initialized_class_object (HackClass (HackClassName.make rootname))
in
L.d_printfln "companion object is %a" AbstractValue.pp (fst companion) ;
let* type_constant_ts =
eval_deref_access Read companion (FieldAccess type_prop_field)
in
(* We've got another type structure in our hands now, so recurse *)
L.d_printfln "type structure for projection=%a" AbstractValue.pp
(fst type_constant_ts) ;
find_name type_constant_ts nullable
let concatenated_name = Printf.sprintf "%s$$%s" rootname type_prop_name in
if String.Set.mem visited_set concatenated_name then (
L.d_printfln "Cyclic type constant detected!" ;
ret None )
else
let type_prop_field = TextualSil.wildcard_sil_fieldname Hack type_prop_name in
let* companion =
get_initialized_class_object (HackClass (HackClassName.make rootname))
in
L.d_printfln "companion object is %a" AbstractValue.pp (fst companion) ;
let* type_constant_ts =
eval_deref_access Read companion (FieldAccess type_prop_field)
in
(* We've got another type structure in our hands now, so recurse *)
L.d_printfln "type structure for projection=%a" AbstractValue.pp
(fst type_constant_ts) ;
find_name type_constant_ts nullable
(String.Set.add visited_set concatenated_name)
| _, _ ->
ret None )
else ret None )
in
let* name_opt = find_name tdict false in
let* name_opt = find_name tdict false String.Set.empty in
match name_opt with
| Some (name, nullable) ->
L.d_printfln "type structure test against type name %a" Typ.Name.pp name ;
Expand Down
24 changes: 24 additions & 0 deletions infer/tests/codetoanalyze/hack/pulse/cyclicconstants.badhack
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.

// this file doesn't typecheck so can't be checked in as part of our normal test suite
// but running it manually allows testing the "should never happen" loop detection code
// so we give it the extension .badhack
namespace Cyclic;

class C {
const type T = D::T;
}

class D {
const type T = C::T;

public static function looper(mixed $m): int {
if ($m is C::T) {
return 42;
}
return 0;
}
}

0 comments on commit bcdb703

Please sign in to comment.