Allow function pointer builtins in constant initializers
[hiphop-php.git] / hphp / hack / src / server / serverConfig.ml
blob5c1961d076578a60757686219aebf9c2eae0ebb1
1 (*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
10 (**
11 * Parses and gathers information from the .hhconfig in the repo.
14 open Core_kernel
15 open Config_file.Getters
16 open Reordered_argument_collections
18 type t = {
19 version: Config_file.version;
20 load_script_timeout: int;
21 (* in seconds *)
23 (* Configures only the workers. Workers can have more relaxed GC configs as
24 * they are short-lived processes *)
25 gc_control: Gc.control;
26 sharedmem_config: SharedMem.config;
27 tc_options: TypecheckerOptions.t;
28 parser_options: ParserOptions.t;
29 glean_options: GleanOptions.t;
30 formatter_override: Path.t option;
31 config_hash: string option;
32 (* A list of regexps for paths to ignore *)
33 ignored_paths: string list;
34 (* A list of extra paths to search for declarations *)
35 extra_paths: Path.t list;
36 (* A list of regexps for paths to ignore for typechecking coroutines *)
37 coroutine_whitelist_paths: string list;
38 warn_on_non_opt_build: bool;
41 let filename =
42 Relative_path.from_root Config_file.file_path_relative_to_repo_root
44 let is_compatible c1 c2 =
45 (* This comparison can eventually be made more complex; we may not always
46 * need to restart hh_server, e.g. changing the path to the load script
47 * is immaterial*)
48 c1 = c2
50 let make_gc_control config =
51 let { Gc.Control.minor_heap_size; space_overhead; _ } =
52 GlobalConfig.gc_control
54 let minor_heap_size =
55 int_ "gc_minor_heap_size" ~default:minor_heap_size config
57 let space_overhead =
58 int_ "gc_space_overhead" ~default:space_overhead config
60 { GlobalConfig.gc_control with Gc.Control.minor_heap_size; space_overhead }
62 let make_sharedmem_config config options local_config =
63 let { SharedMem.global_size; heap_size; shm_min_avail; _ } =
64 GlobalConfig.default_sharedmem_config
66 let shm_dirs = local_config.ServerLocalConfig.shm_dirs in
67 let global_size = int_ "sharedmem_global_size" ~default:global_size config in
68 let heap_size = int_ "sharedmem_heap_size" ~default:heap_size config in
69 let dep_table_pow = int_ "sharedmem_dep_table_pow" ~default:17 config in
70 let hash_table_pow = int_ "sharedmem_hash_table_pow" ~default:18 config in
71 let log_level = int_ "sharedmem_log_level" ~default:0 config in
72 let sample_rate = float_ "sharedmem_sample_rate" ~default:0.0 config in
73 let shm_dirs =
74 string_list
75 ~delim:(Str.regexp ",")
76 "sharedmem_dirs"
77 ~default:shm_dirs
78 config
80 let shm_min_avail =
81 int_ "sharedmem_minimum_available" ~default:shm_min_avail config
83 let (global_size, heap_size, dep_table_pow, hash_table_pow) =
84 match ServerArgs.ai_mode options with
85 | None -> (global_size, heap_size, dep_table_pow, hash_table_pow)
86 | Some ai_options ->
87 Ai.modify_shared_mem_sizes
88 global_size
89 heap_size
90 dep_table_pow
91 hash_table_pow
92 ai_options
95 SharedMem.global_size;
96 heap_size;
97 dep_table_pow;
98 hash_table_pow;
99 log_level;
100 sample_rate;
101 shm_dirs;
102 shm_min_avail;
105 let config_list_regexp = Str.regexp "[, \t]+"
107 let process_experimental sl =
108 match List.map sl String.lowercase with
109 | ["false"] -> SSet.empty
110 | ["true"] -> TypecheckerOptions.experimental_all
111 | features -> List.fold_left features ~f:SSet.add ~init:SSet.empty
113 let config_experimental_tc_features config =
114 match SMap.get config "enable_experimental_tc_features" with
115 | None -> SSet.empty
116 | Some s ->
117 let sl = Str.split config_list_regexp s in
118 process_experimental sl
120 let process_migration_flags sl =
121 match sl with
122 | ["false"] -> SSet.empty
123 | ["true"] -> TypecheckerOptions.migration_flags_all
124 | flags ->
125 List.iter flags ~f:(fun s ->
126 if not (SSet.mem TypecheckerOptions.migration_flags_all s) then
127 failwith ("invalid migration flag: " ^ s));
128 List.fold_left flags ~f:SSet.add ~init:SSet.empty
130 let config_tc_migration_flags config =
131 SMap.get config "enable_tc_migration_flags"
132 |> Option.value_map ~f:(Str.split config_list_regexp) ~default:[]
133 |> List.map ~f:String.lowercase
134 |> process_migration_flags
136 let convert_paths str =
137 let json = Hh_json.json_of_string ~strict:true str in
138 let l = Hh_json.get_array_exn json in
139 List.filter_map
140 ~f:(fun s ->
141 match s with
142 | Hh_json.JSON_String path -> Some path
143 | _ -> None)
146 let process_ignored_paths config =
147 SMap.get config "ignored_paths"
148 |> Option.value_map ~f:convert_paths ~default:[]
150 let maybe_relative_path fn =
151 (* Note: this is not the same as calling realpath; the cwd is not
152 * necessarily the same as hh_server's root!!! *)
153 Path.make
154 begin
155 if Filename.is_relative fn then
156 Relative_path.(to_absolute (from_root fn))
157 else fn
160 let process_extra_paths config =
161 match SMap.get config "extra_paths" with
162 | Some s -> Str.split config_list_regexp s |> List.map ~f:maybe_relative_path
163 | _ -> []
165 let process_coroutine_whitelist_paths config =
166 SMap.get config "coroutine_whitelist_paths"
167 |> Option.value_map ~f:convert_paths ~default:[]
169 let process_untrusted_mode config =
170 match SMap.get config "untrusted_mode" with
171 | Some s ->
172 if bool_of_string s then
173 let blacklist =
175 (* out of tree file access*)
176 "extra_paths";
177 (* potential resource abuse *)
178 "language_feature_logging";
181 let prefix_blacklist =
182 [(* potential resource abuse *) "gc_"; "sharedmem_"]
184 let invalid_keys =
185 SMap.filter
186 ~f:(fun ck _ ->
187 let ck = String.lowercase ck in
188 let exact_match = List.find ~f:(fun bli -> bli = ck) blacklist in
189 let prefix_match =
190 List.find
191 ~f:(fun blp -> String_utils.string_starts_with ck blp)
192 prefix_blacklist
194 match (exact_match, prefix_match) with
195 | (None, None) -> false
196 | _ -> true)
197 config
198 |> SMap.keys
200 if not (List.is_empty invalid_keys) then
201 failwith
202 ( "option not permitted in untrusted_mode: "
203 ^ String.concat ~sep:", " invalid_keys )
204 else
205 failwith "untrusted_mode can only be enabled, not disabled"
206 | _ -> ()
208 let extract_auto_namespace_element ns_map element =
209 match element with
210 | (source, Hh_json.JSON_String target) -> (source, target) :: ns_map
211 | _ ->
212 (* This means the JSON we received is incorrect *)
213 ns_map
215 let convert_auto_namespace_to_map map =
216 let json = Hh_json.json_of_string ~strict:true map in
217 let pairs = Hh_json.get_object_exn json in
218 (* We do a fold instead of a map to filter
219 * out the incorrect entrie as we look at each item *)
220 List.fold_left ~init:[] ~f:extract_auto_namespace_element pairs
222 let prepare_auto_namespace_map config =
223 Option.value_map
224 (SMap.get config "auto_namespace_map")
225 ~default:[]
226 ~f:convert_auto_namespace_to_map
228 let prepare_iset config config_name initial_values =
229 SMap.get config config_name
230 |> Option.value_map ~f:(Str.split config_list_regexp) ~default:[]
231 |> List.map ~f:int_of_string
232 |> List.fold_right ~init:initial_values ~f:ISet.add
234 let prepare_ignored_fixme_codes config =
235 prepare_iset config "ignored_fixme_codes" Errors.default_ignored_fixme_codes
237 let prepare_error_codes_treated_strictly config =
238 prepare_iset config "error_codes_treated_strictly" (ISet.of_list [])
240 let prepare_disallowed_decl_fixmes config =
241 prepare_iset config "disallowed_decl_fixmes" (ISet.of_list [])
243 let load config_filename options =
244 let config_overrides = SMap.of_list @@ ServerArgs.config options in
245 let (config_hash, config) =
246 Config_file.parse_hhconfig
247 ~silent:true
248 (Relative_path.to_absolute config_filename)
250 let config =
251 Config_file.apply_overrides
252 ~silent:true
253 ~config
254 ~overrides:config_overrides
256 process_untrusted_mode config;
257 let version = Config_file.parse_version (SMap.get config "version") in
258 let local_config =
259 ServerLocalConfig.load
260 ~silent:false
261 ~current_version:version
262 config_overrides
264 let local_config =
265 if ServerArgs.ai_mode options <> None then
266 ServerLocalConfig.
268 local_config with
269 use_watchman = false;
270 watchman_subscribe = false;
271 interrupt_on_watchman = false;
272 interrupt_on_client = false;
273 trace_parsing = false;
275 else
276 local_config
278 let ignored_paths = process_ignored_paths config in
279 let extra_paths = process_extra_paths config in
280 let coroutine_whitelist_paths = process_coroutine_whitelist_paths config in
281 (* Since we use the unix alarm() for our timeouts, a timeout value of 0 means
282 * to wait indefinitely *)
283 let load_script_timeout = int_ "load_script_timeout" ~default:0 config in
284 let warn_on_non_opt_build =
285 bool_ "warn_on_non_opt_build" ~default:false config
287 let formatter_override =
288 Option.map (SMap.get config "formatter_override") maybe_relative_path
290 let global_opts =
291 GlobalOptions.make
292 ?tco_safe_array:(bool_opt "safe_array" config)
293 ?tco_safe_vector_array:(bool_opt "safe_vector_array" config)
294 ?po_deregister_php_stdlib:(bool_opt "deregister_php_stdlib" config)
295 ?po_allow_goto:(Option.map ~f:not (bool_opt "disallow_goto" config))
296 ?po_disable_static_closures:(bool_opt "disable_static_closures" config)
297 ?po_disable_halt_compiler:(bool_opt "disable_halt_compiler" config)
298 ?tco_disallow_array_as_tuple:(bool_opt "disallow_array_as_tuple" config)
299 ?tco_disallow_ambiguous_lambda:
300 (bool_opt "disallow_ambiguous_lambda" config)
301 ?tco_disallow_array_typehint:(bool_opt "disallow_array_typehint" config)
302 ?tco_disallow_array_literal:(bool_opt "disallow_array_literal" config)
303 ?tco_defer_class_declaration_threshold:
304 local_config.ServerLocalConfig.defer_class_declaration_threshold
305 ?tco_max_times_to_defer_type_checking:
306 local_config.ServerLocalConfig.max_times_to_defer_type_checking
307 ?tco_prefetch_deferred_files:
308 (Some local_config.ServerLocalConfig.prefetch_deferred_files)
309 ?tco_remote_type_check_threshold:
310 local_config.ServerLocalConfig.remote_type_check_threshold
311 ?tco_remote_type_check:
312 (Some local_config.ServerLocalConfig.remote_type_check)
313 ?tco_remote_worker_key:local_config.ServerLocalConfig.remote_worker_key
314 ?tco_remote_check_id:local_config.ServerLocalConfig.remote_check_id
315 ?tco_num_remote_workers:
316 (Some local_config.ServerLocalConfig.num_remote_workers)
317 ?so_remote_version_specifier:
318 local_config.ServerLocalConfig.remote_version_specifier
319 ?so_remote_worker_eden_checkout_threshold:
320 (int_opt "remote_worker_eden_checkout_threshold" config)
321 ?so_naming_sqlite_path:local_config.ServerLocalConfig.naming_sqlite_path
322 ?tco_language_feature_logging:
323 (bool_opt "language_feature_logging" config)
324 ?tco_unsafe_rx:(bool_opt "unsafe_rx" config)
325 ?tco_disallow_unset_on_varray:
326 (bool_opt "disallow_unset_on_varray" config)
327 ?tco_disallow_scrutinee_case_value_type_mismatch:
328 (bool_opt "disallow_scrutinee_case_value_type_mismatch" config)
329 ?tco_new_inference_lambda:(bool_opt "new_inference_lambda" config)
330 ?tco_timeout:(int_opt "timeout" config)
331 ?tco_disallow_invalid_arraykey:
332 (bool_opt "disallow_invalid_arraykey" config)
333 ?tco_disallow_byref_dynamic_calls:
334 (bool_opt "disallow_byref_dynamic_calls" config)
335 ?tco_disallow_byref_calls:(bool_opt "disallow_byref_calls" config)
336 ?po_disable_lval_as_an_expression:
337 (bool_opt "disable_lval_as_an_expression" config)
338 ?tco_typecheck_xhp_cvars:(bool_opt "typecheck_xhp_cvars" config)
339 ?tco_ignore_collection_expr_type_arguments:
340 (bool_opt "ignore_collection_expr_type_arguments" config)
341 ~ignored_fixme_codes:(prepare_ignored_fixme_codes config)
342 ?ignored_fixme_regex:(string_opt "ignored_fixme_regex" config)
343 ~po_auto_namespace_map:(prepare_auto_namespace_map config)
344 ~tco_experimental_features:(config_experimental_tc_features config)
345 ~tco_log_inference_constraints:
346 (ServerArgs.log_inference_constraints options)
347 ~tco_migration_flags:(config_tc_migration_flags config)
348 ~tco_shallow_class_decl:local_config.ServerLocalConfig.shallow_class_decl
349 ~profile_type_check_duration_threshold:
350 local_config.ServerLocalConfig.profile_type_check_duration_threshold
351 ?tco_like_type_hints:(bool_opt "like_type_hints" config)
352 ?tco_like_casts:(bool_opt "like_casts" config)
353 ?tco_pessimize_types:(bool_opt "pessimize_types" config)
354 ?tco_simple_pessimize:(float_opt "simple_pessimize" config)
355 ?tco_coercion_from_dynamic:(bool_opt "coercion_from_dynamic" config)
356 ?tco_complex_coercion:(bool_opt "complex_coercion" config)
357 ?tco_coercion_from_union:(bool_opt "coercion_from_union" config)
358 ?tco_disable_partially_abstract_typeconsts:
359 (bool_opt "disable_partially_abstract_typeconsts" config)
360 ~error_codes_treated_strictly:
361 (prepare_error_codes_treated_strictly config)
362 ?tco_check_xhp_attribute:(bool_opt "check_xhp_attribute" config)
363 ?tco_disallow_unresolved_type_variables:
364 (bool_opt "disallow_unresolved_type_variables" config)
365 ?tco_disallow_invalid_arraykey_constraint:
366 (bool_opt "disallow_invalid_arraykey_constraint" config)
367 ?po_enable_class_level_where_clauses:
368 (bool_opt "class_level_where_clauses" config)
369 ?po_enable_constant_visibility_modifiers:
370 (bool_opt "enable_constant_visibility_modifiers" config)
371 ?po_disable_legacy_soft_typehints:
372 (bool_opt "disable_legacy_soft_typehints" config)
373 ?tco_use_lru_workers:
374 (Some local_config.ServerLocalConfig.use_lru_workers)
375 ?po_disallow_toplevel_requires:
376 (bool_opt "disallow_toplevel_requires" config)
377 ~po_disallowed_decl_fixmes:(prepare_disallowed_decl_fixmes config)
378 ?po_allow_new_attribute_syntax:
379 (bool_opt "allow_new_attribute_syntax" config)
380 ?po_disable_legacy_attribute_syntax:
381 (bool_opt "disable_legacy_attribute_syntax" config)
382 ?tco_const_attribute:(bool_opt "const_attribute" config)
383 ?po_const_default_func_args:(bool_opt "const_default_func_args" config)
384 ?po_disallow_silence:(bool_opt "disallow_silence" config)
385 ~tco_infer_missing:
386 ( GlobalOptions.InferMissing.from_string_opt
387 @@ string_opt "infer_missing" config )
388 ?tco_const_static_props:(bool_opt "const_static_props" config)
389 ?po_abstract_static_props:(bool_opt "abstract_static_props" config)
390 ?po_disable_unset_class_const:
391 (bool_opt "disable_unset_class_const" config)
392 ~po_parser_errors_only:(ServerArgs.ai_mode options <> None)
393 ?tco_check_attribute_locations:
394 (bool_opt "check_attribute_locations" config)
395 ?glean_service:(string_opt "glean_service" config)
396 ?glean_hostname:(string_opt "glean_hostname" config)
397 ?glean_port:(int_opt "glean_port" config)
398 ?glean_reponame:(string_opt "glean_reponame" config)
399 ?po_disallow_func_ptrs_in_constants:
400 (bool_opt "disallow_func_ptrs_in_constants" config)
403 Errors.ignored_fixme_codes := GlobalOptions.ignored_fixme_codes global_opts;
404 Errors.error_codes_treated_strictly :=
405 GlobalOptions.error_codes_treated_strictly global_opts;
407 version;
408 load_script_timeout;
409 gc_control = make_gc_control config;
410 sharedmem_config = make_sharedmem_config config options local_config;
411 tc_options = global_opts;
412 parser_options = global_opts;
413 glean_options = global_opts;
414 formatter_override;
415 config_hash = Some config_hash;
416 ignored_paths;
417 extra_paths;
418 coroutine_whitelist_paths;
419 warn_on_non_opt_build;
421 local_config )
423 (* useful in testing code *)
424 let default_config =
426 version = Config_file.Opaque_version None;
427 load_script_timeout = 0;
428 gc_control = GlobalConfig.gc_control;
429 sharedmem_config = GlobalConfig.default_sharedmem_config;
430 tc_options = TypecheckerOptions.default;
431 glean_options = GleanOptions.default;
432 parser_options = ParserOptions.default;
433 formatter_override = None;
434 config_hash = None;
435 ignored_paths = [];
436 extra_paths = [];
437 coroutine_whitelist_paths = [];
438 warn_on_non_opt_build = false;
441 let set_parser_options config popt = { config with parser_options = popt }
443 let set_tc_options config tcopt = { config with tc_options = tcopt }
445 let set_glean_options config gleanopt =
446 { config with glean_options = gleanopt }
448 let gc_control config = config.gc_control
450 let sharedmem_config config = config.sharedmem_config
452 let typechecker_options config = config.tc_options
454 let parser_options config = config.parser_options
456 let glean_options config = config.glean_options
458 let formatter_override config = config.formatter_override
460 let config_hash config = config.config_hash
462 let ignored_paths config = config.ignored_paths
464 let extra_paths config = config.extra_paths
466 let coroutine_whitelist_paths config = config.coroutine_whitelist_paths
468 let version config = config.version
470 let warn_on_non_opt_build config = config.warn_on_non_opt_build