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/Format.h>
26 #include "hphp/util/embedded-data.h"
30 ////////////////////////////////////////////////////////////////////////////////
32 // List of types which should be ignored (including any bases) by the generated
33 // scanners. Add as needed.
34 const std::unordered_set
<std::string
> ignored
= {
36 "std::condition_variable",
40 // List of templates which should not be used to store request heap allocated
41 // values (because scanner aware variants exist).
42 const std::unordered_set
<std::string
> forbidden_template
= {
43 "boost::container::flat_map",
44 "boost::container::flat_multimap",
45 "boost::container::flat_multiset",
46 "boost::container::flat_set",
55 "std::priority_queue",
62 "std::unordered_multimap",
63 "std::unordered_multiset",
68 const std::unordered_set
<std::string
> forced_conservative
= {
75 std::string
stripTemplateArgs(std::string name
) {
76 std::size_t open_count
= 0;
77 std::size_t open_begin
;
78 for (std::size_t i
= 0; i
< name
.size();) {
80 if (!open_count
) open_begin
= i
;
83 } else if (name
[i
] == '>' && open_count
> 0) {
85 name
= name
.erase(open_begin
, i
- open_begin
+ 1);
97 ////////////////////////////////////////////////////////////////////////////////
101 namespace HPHP
{ namespace type_scan
{ namespace detail
{
103 ////////////////////////////////////////////////////////////////////////////////
105 void conservative_stub(type_scan::Scanner
& scanner
,
108 scanner
.conservative(ptr
, size
);
111 void noptrs_stub(type_scan::Scanner
& /*scanner*/, const void* /*ptr*/,
112 std::size_t /*size*/) {}
114 // Initialize metadata table, used before init() is called. Since before this,
115 // the only type-indices that can be present are "kIndexUnknown" and
116 // "kIndexUnknownNoPtrs".
117 const Metadata stub_metadata_table
[] = {
118 {"(UNKNOWN)", conservative_stub
},
119 {"(UNKNOWN NO-PTRS)", noptrs_stub
}
121 const Metadata
* g_metadata_table
= stub_metadata_table
;
122 std::size_t g_metadata_table_size
= 2;
124 bool isIgnoredType(const std::string
& name
) {
125 return ignored
.count(stripTemplateArgs(name
));
128 bool isForbiddenTemplate(const std::string
& name
) {
129 return forbidden_template
.count(stripTemplateArgs(name
));
132 bool isForcedConservativeTemplate(const std::string
& name
) {
133 return forced_conservative
.count(stripTemplateArgs(name
));
136 ////////////////////////////////////////////////////////////////////////////////
140 using namespace detail
;
143 #if defined(__clang__)
144 // Clang is currently broken... It doesn't emit uncalled member functions in a
145 // template class, even when using ATTRIBUTE_USED. This prevents the custom
146 // scanners from being emitted (silently), which causes all sorts of
147 // problems. Punt for now until we can figure out a fix. This means that we'll
148 // continue to just conservative scan everything. See t10336705.
150 #elif defined(__linux__) || defined(__FreeBSD__)
152 using init_func_t
= const Metadata
*(*)(std::size_t&);
154 auto const scanner_init
= [] () -> init_func_t
{
155 auto const result
= dlsym(RTLD_DEFAULT
, kInitFuncName
);
156 if (result
!= nullptr) return reinterpret_cast<init_func_t
>(result
);
158 // Find the shared object embedded within a custom section.
160 if (!get_embedded_data("type_scanners", &data
)) {
161 // no embedded data was built; fall back to conservative scan.
165 // Link in the embedded object.
166 char tmp_filename
[] = "/tmp/hhvm_type_scanner_XXXXXX";
167 auto const handle
= dlopen_embedded_data(data
, tmp_filename
);
169 throw InitException
{"Failed to dlopen embedded data"};
172 // Find the initialization function.
173 auto const init
= dlsym(handle
, kInitFuncName
);
175 throw InitException
{ folly::sformat("dlsym() fails: {}", dlerror()) };
177 return reinterpret_cast<init_func_t
>(init
);
180 if (!scanner_init
) return;
182 // And call it. The return value is a pointer to the new metadata table, and
183 // the size of the table will be updated by passing by ref.
184 if (auto const table
= scanner_init(g_metadata_table_size
)) {
185 g_metadata_table
= table
;
187 throw InitException
{"Failed to load scanner table"};
191 // Some other platform... do nothing and continue to conservative scan for
195 ////////////////////////////////////////////////////////////////////////////////