2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/util/type-scan.h"
24 #include <folly/container/F14Set.h>
25 #include <folly/Format.h>
27 #include "hphp/util/build-info.h"
28 #include "hphp/util/embedded-data.h"
32 ////////////////////////////////////////////////////////////////////////////////
34 // List of types which should be ignored (including any bases) by the generated
35 // scanners. Add as needed.
36 const folly::F14FastSet
<std::string
> ignored
= {
38 "std::condition_variable",
42 // List of templates which should not be used to store request heap allocated
43 // values (because scanner aware variants exist).
44 const folly::F14FastSet
<std::string
> forbidden_template
= {
45 "boost::container::flat_map",
46 "boost::container::flat_multimap",
47 "boost::container::flat_multiset",
48 "boost::container::flat_set",
58 "std::priority_queue",
65 "std::unordered_multimap",
66 "std::unordered_multiset",
71 const folly::F14FastSet
<std::string
> forced_conservative
= {
78 std::string
stripTemplateArgs(std::string name
) {
79 std::size_t open_count
= 0;
80 std::size_t open_begin
;
81 for (std::size_t i
= 0; i
< name
.size();) {
83 if (!open_count
) open_begin
= i
;
86 } else if (name
[i
] == '>' && open_count
> 0) {
88 name
= name
.erase(open_begin
, i
- open_begin
+ 1);
100 ////////////////////////////////////////////////////////////////////////////////
104 namespace HPHP::type_scan
{ namespace detail
{
106 ////////////////////////////////////////////////////////////////////////////////
108 void conservative_stub(type_scan::Scanner
& scanner
,
111 scanner
.conservative(ptr
, size
);
114 void noptrs_stub(type_scan::Scanner
& /*scanner*/, const void* /*ptr*/,
115 std::size_t /*size*/) {}
117 // Initialize metadata table, used before init() is called. Since before this,
118 // the only type-indices that can be present are "kIndexUnknown" and
119 // "kIndexUnknownNoPtrs".
120 const Metadata stub_metadata_table
[] = {
121 {"(UNKNOWN)", conservative_stub
},
122 {"(UNKNOWN NO-PTRS)", noptrs_stub
}
124 const Metadata
* g_metadata_table
= stub_metadata_table
;
125 std::size_t g_metadata_table_size
= 2;
127 bool isIgnoredType(const std::string
& name
) {
128 return ignored
.count(stripTemplateArgs(name
));
131 bool isForbiddenTemplate(const std::string
& name
) {
132 return forbidden_template
.count(stripTemplateArgs(name
));
135 bool isForcedConservativeTemplate(const std::string
& name
) {
136 return forced_conservative
.count(stripTemplateArgs(name
));
139 ////////////////////////////////////////////////////////////////////////////////
143 using namespace detail
;
145 void init(const std::string
& extractPath
,
146 const std::string
& fallbackPath
,
148 #if defined(__clang__) && !defined(CLANG_STANDALONE_DEBUG)
149 // Older versions of clang don't emit uncalled member functions in a
150 // template class, even when using ATTRIBUTE_USED. This prevents the custom
151 // scanners from being emitted (silently), which causes all sorts of
152 // problems. Fixed in https://reviews.llvm.org/D56928. Clang builds also
153 // need -fstandalone-debug to emit full types in DWARF.
155 #elif defined(__linux__) || defined(__FreeBSD__)
157 using init_func_t
= const Metadata
*(*)(std::size_t&);
159 auto const scanner_init
= [&] () -> init_func_t
{
160 auto const result
= dlsym(RTLD_DEFAULT
, kInitFuncName
);
161 if (result
!= nullptr) return reinterpret_cast<init_func_t
>(result
);
163 // Find the shared object embedded within a custom section.
165 if (!get_embedded_data("type_scanners", &data
)) {
166 // no embedded data was built; fall back to conservative scan.
170 // Link in the embedded object.
171 auto const handle
= dlopen_embedded_data(
175 buildId().toString(),
179 throw InitException
{"Failed to dlopen embedded data"};
182 // Find the initialization function.
183 auto const init
= dlsym(handle
, kInitFuncName
);
185 throw InitException
{ folly::sformat("dlsym() fails: {}", dlerror()) };
187 return reinterpret_cast<init_func_t
>(init
);
190 if (!scanner_init
) return;
192 // And call it. The return value is a pointer to the new metadata table, and
193 // the size of the table will be updated by passing by ref.
194 if (auto const table
= scanner_init(g_metadata_table_size
)) {
195 g_metadata_table
= table
;
197 throw InitException
{"Failed to load scanner table"};
201 // Some other platform... do nothing and continue to conservative scan for
205 ////////////////////////////////////////////////////////////////////////////////