From 363780ee0b3c689127495789629924f26b6074a3 Mon Sep 17 00:00:00 2001 From: Joseph Griego Date: Wed, 2 Oct 2019 16:25:51 -0700 Subject: [PATCH] Fix hhbbc to attribute addelemc const-propp'd dicts correctly Summary: We weren't marking the empty array at the start of the chain, so do that. Also tweaks `provTagHere` to grab the _last_ line of the range instead of the first--we may want to revisit that if we decide we really want arrprov marked at the start of an array literal. Reviewed By: mxw Differential Revision: D17467778 fbshipit-source-id: 9bd6d672ac5a3a6c971fb77452d1fd1a55268dbb --- hphp/hhbbc/interp-internal.h | 2 +- hphp/hhbbc/interp.cpp | 3 +- hphp/hhbbc/type-system.cpp | 58 ++++++++++++++++++---- hphp/hhbbc/type-system.h | 17 ++++--- .../slow/array_provenance/dict_literal_bug.php | 15 ++++++ .../array_provenance/dict_literal_bug.php.expectf | 1 + .../dict_literal_bug.php.hphp_opts | 1 + .../array_provenance/dict_literal_bug.php.opts | 1 + 8 files changed, 79 insertions(+), 19 deletions(-) create mode 100644 hphp/test/slow/array_provenance/dict_literal_bug.php create mode 100644 hphp/test/slow/array_provenance/dict_literal_bug.php.expectf create mode 100644 hphp/test/slow/array_provenance/dict_literal_bug.php.hphp_opts create mode 100644 hphp/test/slow/array_provenance/dict_literal_bug.php.opts diff --git a/hphp/hhbbc/interp-internal.h b/hphp/hhbbc/interp-internal.h index 72b7d4cd5d4..18852f7a18b 100644 --- a/hphp/hhbbc/interp-internal.h +++ b/hphp/hhbbc/interp-internal.h @@ -1154,7 +1154,7 @@ folly::Optional provTagHere(ISS& env) { : env.ctx.unit; return arrprov::Tag{ unit->filename, - static_cast(unit->srcLocs[idx].start.line) + static_cast(unit->srcLocs[idx].past.line) }; } diff --git a/hphp/hhbbc/interp.cpp b/hphp/hhbbc/interp.cpp index 9dfff1ff8a2..cee89d2506c 100644 --- a/hphp/hhbbc/interp.cpp +++ b/hphp/hhbbc/interp.cpp @@ -908,7 +908,8 @@ void in(ISS& env, const bc::NewArray& op) { void in(ISS& env, const bc::NewDictArray& op) { effect_free(env); - push(env, op.arg1 == 0 ? dict_empty() : some_dict_empty()); + push(env, op.arg1 == 0 ? dict_empty(provTagHere(env)) + : some_dict_empty(provTagHere(env))); } void in(ISS& env, const bc::NewMixedArray& op) { diff --git a/hphp/hhbbc/type-system.cpp b/hphp/hhbbc/type-system.cpp index 9e2cb1080c9..5b6cd663f1e 100644 --- a/hphp/hhbbc/type-system.cpp +++ b/hphp/hhbbc/type-system.cpp @@ -2323,6 +2323,30 @@ bool Type::checkInvariants() const { return true; } +/* Retrieve the provenance tag from a type, if it has one */ +ProvTag Type::getProvTag() const { + if (!RuntimeOption::EvalArrayProvenance) return folly::none; + switch (m_dataTag) { + case DataTag::None: + case DataTag::Str: + case DataTag::Int: + case DataTag::Dbl: + case DataTag::Obj: + case DataTag::Cls: + case DataTag::RefInner: + case DataTag::ArrLikePackedN: + case DataTag::ArrLikeMapN: + return folly::none; + case DataTag::ArrLikeVal: + return arrprov::getTag(m_data.aval); + case DataTag::ArrLikePacked: + return m_data.packed->provenance; + case DataTag::ArrLikeMap: + return m_data.map->provenance; + } + always_assert(false); +} + ////////////////////////////////////////////////////////////////////// Type wait_handle(const Index& index, Type inner) { @@ -2418,16 +2442,20 @@ Type vec_val(SArray val) { return r; } -Type vec_empty() { +Type vec_empty(ProvTag pt /* = folly::none */) { auto r = Type { BSVecE }; - r.m_data.aval = staticEmptyVecArray(); + r.m_data.aval = RuntimeOption::EvalArrayProvenance && pt + ? arrprov::makeEmptyVec(pt) + : staticEmptyVecArray(); r.m_dataTag = DataTag::ArrLikeVal; return r; } -Type some_vec_empty() { +Type some_vec_empty(ProvTag pt /* = folly::none */) { auto r = Type { BVecE }; - r.m_data.aval = staticEmptyVecArray(); + r.m_data.aval = RuntimeOption::EvalArrayProvenance && pt + ? arrprov::makeEmptyVec(pt) + : staticEmptyVecArray(); r.m_dataTag = DataTag::ArrLikeVal; return r; } @@ -2474,16 +2502,20 @@ Type dict_val(SArray val) { return r; } -Type dict_empty() { +Type dict_empty(ProvTag pt /* = folly::none */) { auto r = Type { BSDictE }; - r.m_data.aval = staticEmptyDictArray(); + r.m_data.aval = RuntimeOption::EvalArrayProvenance && pt + ? arrprov::makeEmptyDict(pt) + : staticEmptyDictArray(); r.m_dataTag = DataTag::ArrLikeVal; return r; } -Type some_dict_empty() { +Type some_dict_empty(ProvTag pt /* = folly::none */) { auto r = Type { BDictE }; - r.m_data.aval = staticEmptyDictArray(); + r.m_data.aval = RuntimeOption::EvalArrayProvenance && pt + ? arrprov::makeEmptyDict(pt) + : staticEmptyDictArray(); r.m_dataTag = DataTag::ArrLikeVal; return r; } @@ -4948,7 +4980,7 @@ array_elem(const Type& arr, const Type& undisectedKey, const Type& defaultTy) { std::pair array_like_set(Type arr, const ArrKey& key, const Type& valIn, - ProvTag src) { + ProvTag loc) { const bool maybeEmpty = arr.couldBe(BArrLikeE); const bool isVector = arr.couldBe(BVec); const bool isPhpArray = arr.couldBe(BArr); @@ -4958,6 +4990,14 @@ std::pair array_like_set(Type arr, trep bits = combine_dv_arr_like_bits(arr.m_bits, BArrLikeN); if (validKey) bits &= ~BArrLikeE; + auto const src = [&] () -> ProvTag { + if (auto const tag = arr.getProvTag()) { + return tag; + } else { + return loc; + } + }(); + auto const fixRef = !isPhpArray && valIn.couldBe(BRef); auto const throwMode = !fixRef && validKey && !key.mayThrow ? ThrowMode::None : ThrowMode::BadOperation; diff --git a/hphp/hhbbc/type-system.h b/hphp/hhbbc/type-system.h index d64738816d0..c5ff067d6de 100644 --- a/hphp/hhbbc/type-system.h +++ b/hphp/hhbbc/type-system.h @@ -726,11 +726,11 @@ private: friend Type spec_array_like_union(Type&, Type&, trep, trep); friend Type vec_val(SArray); - friend Type vec_empty(); - friend Type some_vec_empty(); + friend Type vec_empty(ProvTag); + friend Type some_vec_empty(ProvTag); friend Type dict_val(SArray); - friend Type dict_empty(); - friend Type some_dict_empty(); + friend Type dict_empty(ProvTag); + friend Type some_dict_empty(ProvTag); friend Type keyset_val(SArray); friend bool could_contain_objects(const Type&); friend bool could_copy_on_write(const Type&); @@ -775,6 +775,7 @@ private: bool subtypeData(const Type&) const; bool couldBeData(const Type&) const; bool checkInvariants() const; + ProvTag getProvTag() const; private: trep m_bits; @@ -1060,8 +1061,8 @@ Type sempty(); Type aempty(); Type aempty_varray(); Type aempty_darray(); -Type vec_empty(); -Type dict_empty(); +Type vec_empty(ProvTag pt = folly::none); +Type dict_empty(ProvTag pt = folly::none); Type keyset_empty(); /* @@ -1069,8 +1070,8 @@ Type keyset_empty(); */ Type some_aempty(); Type some_aempty_darray(); -Type some_vec_empty(); -Type some_dict_empty(); +Type some_vec_empty(ProvTag pt = folly::none); +Type some_dict_empty(ProvTag pt = folly::none); Type some_keyset_empty(); /* diff --git a/hphp/test/slow/array_provenance/dict_literal_bug.php b/hphp/test/slow/array_provenance/dict_literal_bug.php new file mode 100644 index 00000000000..7212f2037e0 --- /dev/null +++ b/hphp/test/slow/array_provenance/dict_literal_bug.php @@ -0,0 +1,15 @@ +> +function main() { + $x = dict[ + 42 => "garbage", + Foo::GARBAGE => "more garbage" + ]; + + var_dump(HH\get_provenance($x)); +} diff --git a/hphp/test/slow/array_provenance/dict_literal_bug.php.expectf b/hphp/test/slow/array_provenance/dict_literal_bug.php.expectf new file mode 100644 index 00000000000..3d54b57f773 --- /dev/null +++ b/hphp/test/slow/array_provenance/dict_literal_bug.php.expectf @@ -0,0 +1 @@ +string(%d) "%s/dict_literal_bug.php:12" diff --git a/hphp/test/slow/array_provenance/dict_literal_bug.php.hphp_opts b/hphp/test/slow/array_provenance/dict_literal_bug.php.hphp_opts new file mode 100644 index 00000000000..1a1f163bad4 --- /dev/null +++ b/hphp/test/slow/array_provenance/dict_literal_bug.php.hphp_opts @@ -0,0 +1 @@ +-vRuntime.Eval.ArrayProvenance=1 \ No newline at end of file diff --git a/hphp/test/slow/array_provenance/dict_literal_bug.php.opts b/hphp/test/slow/array_provenance/dict_literal_bug.php.opts new file mode 100644 index 00000000000..fba232a377d --- /dev/null +++ b/hphp/test/slow/array_provenance/dict_literal_bug.php.opts @@ -0,0 +1 @@ +-vEval.ArrayProvenance=1 \ No newline at end of file -- 2.11.4.GIT