summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Chang <ochang@chromium.org>2018-04-27 10:42:12 +0900
committerQijiang Fan <fqj@google.com>2020-06-05 09:11:57 +0900
commit69300be5b4e1491b05e1a925087d7e5d2538acd8 (patch)
tree1d51eba930bdaa4c02bf32136ece59362d41d010
parentf80e945bfb6470ae787dbf6258d7dc2bee263139 (diff)
downloadlibchrome-69300be5b4e1491b05e1a925087d7e5d2538acd8.tar.gz
Mojo JS bindings: Generate additional methods to aid fuzzing.
This generates additional methods on each struct/union to allow mutation/generation, and to get/set any handles and interfaces that are part of the struct/union. These are only generated when |enable_ipc_fuzzer| is set. When this is set, |cpp_only| is also ignored. Bug: 607649 Change-Id: I2097610ced9de186c098232207afff11ff0a3745 Reviewed-on: https://chromium-review.googlesource.com/1011882 Reviewed-by: Ken Rockot <rockot@chromium.org> Commit-Queue: Oliver Chang <ochang@chromium.org> Cr-Commit-Position: refs/heads/master@{#554258} CrOS-Libchrome-Original-Commit: bc38c9eab0eb99690a2926b9f943b6dcc17740de
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/fuzzing.tmpl125
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl12
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl2
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl53
-rw-r--r--mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl67
-rw-r--r--mojo/public/tools/bindings/generators/mojom_js_generator.py68
-rw-r--r--mojo/public/tools/bindings/mojom.gni7
-rwxr-xr-xmojo/public/tools/bindings/mojom_bindings_generator.py7
-rw-r--r--mojo/public/tools/bindings/pylib/mojom/generate/generator.py4
9 files changed, 340 insertions, 5 deletions
diff --git a/mojo/public/tools/bindings/generators/js_templates/fuzzing.tmpl b/mojo/public/tools/bindings/generators/js_templates/fuzzing.tmpl
new file mode 100644
index 0000000000..fb535fe03a
--- /dev/null
+++ b/mojo/public/tools/bindings/generators/js_templates/fuzzing.tmpl
@@ -0,0 +1,125 @@
+{%- macro get_handle_deps(kind, name) -%}
+{%- if kind|is_struct_kind or kind|is_union_kind -%}
+{{name}}.getHandleDeps()
+{%- elif kind|is_array_kind -%}
+[].concat.apply([], {{name}}.map(function(val) {
+ if (val) {
+ return {{get_handle_deps(kind.kind, 'val')|indent(4)}};
+ }
+ return [];
+}))
+{%- elif kind|is_map_kind -%}
+[].concat.apply([], Array.from({{name}}.values()).map(function(val) {
+ if (val) {
+ return {{get_handle_deps(kind.value_kind, 'val')|indent(4)}};
+ }
+ return [];
+}))
+{%- elif kind|is_any_handle_or_interface_kind -%}
+ ["{{kind|fuzz_handle_name}}"]
+{%- else -%}
+ []
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro set_handles(kind, name) -%}
+{%- if kind|is_struct_kind or kind|is_union_kind -%}
+idx = {{name}}.setHandlesInternal_(handles, idx)
+{%- elif kind|is_array_kind -%}
+{{name}}.forEach(function(val) {
+ {{set_handles(kind.kind, 'val')|indent(2)}};
+})
+{%- elif kind|is_map_kind -%}
+{{name}}.forEach(function(val) {
+ {{set_handles(kind.value_kind, 'val')|indent(2)}};
+})
+{%- elif kind|is_any_handle_or_interface_kind -%}
+{{name}} = handles[idx++];
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro build_call(obj, operation, type, name) -%}
+{%- if name -%}
+{{obj}}.{{operation}}{{type}}({{((name,) + varargs)|join(', ')}})
+{%- else -%}
+{{obj}}.{{operation}}{{type}}({{varargs|join(', ')}})
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro generate_or_mutate_enum(obj, operation, kind, name) -%}
+{%- if kind.max_value is not none -%}
+{{build_call(obj, operation, 'Enum', name, '0', kind.max_value)}}
+{%- else -%}
+{{build_call(obj, operation, 'Enum', name)}}
+{%- endif %}
+{%- endmacro -%}
+
+{%- macro generate_or_mutate_array(obj, operation, kind, name) -%}
+{%- if operation == 'mutate' -%}
+{{obj}}.{{operation}}Array({{name}}, function(val) {
+ return {{generate_or_mutate(obj, operation, kind.kind, 'val')|indent(2)}};
+})
+{%- else -%}
+{{obj}}.{{operation}}Array(function() {
+ return {{generate_or_mutate(obj, operation, kind.kind)|indent(2)}};
+})
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro generate_or_mutate_map(obj, operation, kind, name) -%}
+{%- if operation == 'mutate' -%}
+{{obj}}.{{operation}}Map({{name}},
+ function(val) {
+ return {{generate_or_mutate(obj, operation, kind.key_kind, 'val')|indent(4)}};
+ },
+ function(val) {
+ return {{generate_or_mutate(obj, operation, kind.value_kind, 'val')|indent(4)}};
+ })
+{%- else -%}
+{{obj}}.{{operation}}Map(
+ function() {
+ return {{generate_or_mutate(obj, operation, kind.key_kind)|indent(4)}};
+ },
+ function() {
+ return {{generate_or_mutate(obj, operation, kind.value_kind)|indent(4)}};
+ })
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro generate_or_mutate_primitive(obj, operation, kind, name) -%}
+{%- if kind|is_reference_kind -%}
+{{build_call(obj, operation, kind|primitive_to_fuzz_type, name, kind.is_nullable|to_js_boolean)}}
+{%- else -%}
+{{build_call(obj, operation, kind|primitive_to_fuzz_type, name)}}
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro generate_or_mutate_interface(obj, operation, kind, name) -%}
+{%- if kind|is_interface_request_kind -%}
+{{build_call(obj, operation, 'InterfaceRequest', name, '"' ~ kind.kind.module.namespace ~ '.' ~ kind.kind.name ~ '"', kind.is_nullable|to_js_boolean)}}
+{%- elif kind|is_interface_kind -%}
+{{build_call(obj, operation, 'Interface', name, '"' ~ kind.module.namespace ~ '.' ~ kind.name ~ '"', kind.is_nullable|to_js_boolean)}}
+{%- elif kind|is_associated_interface_request_kind -%}
+{{build_call(obj, operation, 'AssociatedInterfaceRequest', name, '"' ~ kind.kind.module.namespace ~ '.' ~ kind.kind.name ~ '"', kind.is_nullable|to_js_boolean)}}
+{%- elif kind|is_associated_interface_kind -%}
+{{build_call(obj, operation, 'AssociatedInterface', name, '"' ~ kind.kind.module.namespace ~ '.' ~ kind.kind.name ~ '"', kind.is_nullable|to_js_boolean)}}
+{%- endif -%}
+{%- endmacro -%}
+
+{%- macro generate_or_mutate(obj, operation, kind, name='') -%}
+{%- if kind|is_primitive_kind -%}
+{{generate_or_mutate_primitive(obj, operation, kind, name)}}
+{%- elif kind|is_any_interface_kind -%}
+{{generate_or_mutate_interface(obj, operation, kind, name)}}
+{%- elif kind|is_enum_kind -%}
+{{generate_or_mutate_enum(obj, operation, kind, name)}}
+{%- elif kind|is_struct_kind -%}
+{{build_call(obj, operation, 'Struct', kind.module.namespace ~ '.' ~ kind.name, kind.is_nullable|to_js_boolean)}}
+{%- elif kind|is_union_kind -%}
+{{build_call(obj, operation, 'Union', kind.module.namespace ~ '.' ~ kind.name, kind.is_nullable|to_js_boolean)}}
+{%- elif kind|is_array_kind -%}
+{{generate_or_mutate_array(obj, operation, kind, name)}}
+{%- elif kind|is_map_kind -%}
+{{generate_or_mutate_map(obj, operation, kind, name)}}
+{%- endif -%}
+{%- endmacro -%}
diff --git a/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl
index 988ca0af4d..356fc5bb12 100644
--- a/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl
@@ -226,6 +226,18 @@ params.{{parameter.name}}{% if not loop.last %}, {% endif -%}
{%- else %}
validateResponse: null,
{%- endif %}
+{%- if generate_fuzzing %}
+ mojomId: '{{module.path}}',
+ fuzzMethods: {
+ {%- for method in interface.methods %}
+ {%- set interface_method_id =
+ interface.mojom_name ~ "_" ~ method.mojom_name %}
+ {{ method.name }}: {
+ params: {{interface_method_id}}_Params,
+ },
+ {%- endfor %}
+ },
+{%- endif %}
};
{#--- Interface Constants #}
{%- for constant in interface.constants %}
diff --git a/mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl
index 21165ddcad..a6736b5658 100644
--- a/mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/module_definition.tmpl
@@ -17,7 +17,7 @@
{#--- Union definitions #}
{%- from "union_definition.tmpl" import union_def %}
{%- for union in unions %}
-{{union_def(union)|indent(2)}}
+{{union_def(union, generate_fuzzing)|indent(2)}}
{%- endfor %}
{#--- Interface definitions #}
diff --git a/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl
index 7bffe60885..176f1b8909 100644
--- a/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl
@@ -30,6 +30,59 @@
}
};
+{#--- Fuzzing #}
+{%- if generate_fuzzing %}
+ {{struct.name}}.generate = function(generator_) {
+ var generated = new {{struct.name}};
+{%- for field in struct.fields %}
+{%- if not field.kind|is_any_handle_or_interface_kind %}
+{%- from "fuzzing.tmpl" import generate_or_mutate %}
+ generated.{{field.name}} = {{generate_or_mutate('generator_', 'generate', field.kind)|indent(4)}};
+{%- endif %}
+{%- endfor %}
+ return generated;
+ };
+
+ {{struct.name}}.prototype.mutate = function(mutator_) {
+{%- for field in struct.fields %}
+{%- if not field.kind|is_any_handle_or_interface_kind %}
+ if (mutator_.chooseMutateField()) {
+{%- from "fuzzing.tmpl" import generate_or_mutate %}
+ this.{{field.name}} = {{generate_or_mutate('mutator_', 'mutate', field.kind, 'this.' ~ field.name)|indent(6)}};
+ }
+{%- endif %}
+{%- endfor %}
+ return this;
+ };
+
+ {{struct.name}}.prototype.getHandleDeps = function() {
+ var handles = [];
+{%- for field in struct.fields %}
+{%- if field.kind|contains_handles_or_interfaces %}
+ if (this.{{field.name}} !== null) {
+{%- from "fuzzing.tmpl" import get_handle_deps %}
+ Array.prototype.push.apply(handles, {{get_handle_deps(field.kind, 'this.' ~ field.name)|indent(6)}});
+ }
+{%- endif %}
+{%- endfor %}
+ return handles;
+ };
+
+ {{struct.name}}.prototype.setHandles = function() {
+ this.setHandlesInternal_(arguments, 0);
+ };
+
+ {{struct.name}}.prototype.setHandlesInternal_ = function(handles, idx) {
+{%- for field in struct.fields %}
+{%- if field.kind|contains_handles_or_interfaces %}
+{%- from "fuzzing.tmpl" import set_handles %}
+ {{set_handles(field.kind, 'this.' ~ field.name)|indent(4)}};
+{%- endif %}
+{%- endfor %}
+ return idx;
+ };
+{%- endif %}
+
{#--- Validation #}
{{struct.name}}.validate = function(messageValidator, offset) {
diff --git a/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl b/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl
index dde69aeffd..d00e641db6 100644
--- a/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl
@@ -1,4 +1,4 @@
-{%- macro union_def(union) %}
+{%- macro union_def(union, generate_fuzzing=false) %}
function {{union.name}}(value) {
this.initDefault_();
this.initValue_(value);
@@ -39,6 +39,71 @@ function {{union.name}}(value) {
this[keys[0]] = value[keys[0]];
}
+{% if generate_fuzzing %}
+{{union.name}}.generate = function(generator_) {
+ var generated = new {{union.name}};
+ var generators = [
+{%- for field in union.fields %}
+ {
+ field: "{{field.name}}",
+
+{%- if not field.kind|is_any_handle_or_interface_kind %}
+{%- from "fuzzing.tmpl" import generate_or_mutate %}
+ generator: function() { return {{generate_or_mutate('generator_', 'generate', field.kind)|indent(6)}}; },
+{%- endif %}
+ },
+{%- endfor %}
+ ];
+
+ var result = generator_.generateUnionField(generators);
+ generated[result.field] = result.value;
+ return generated;
+}
+
+{{union.name}}.prototype.mutate = function(mutator_) {
+ var mutators = [
+{%- for field in union.fields %}
+ {
+ field: "{{field.name}}",
+
+{%- if not field.kind|is_any_handle_or_interface_kind %}
+{%- from "fuzzing.tmpl" import generate_or_mutate %}
+ mutator: function() { return {{generate_or_mutate('mutator_', 'mutate', field.kind, 'this.' ~ field.name)|indent(6)}}; },
+{%- endif %}
+ },
+{%- endfor %}
+ ];
+
+ var result = mutator_.mutateUnionField(this, mutators);
+ generated[result.field] = result.value;
+ return this;
+}
+
+{{union.name}}.prototype.getHandleDeps = function() {
+{%- for field in union.fields %}
+{%- if field.kind|contains_handles_or_interfaces %}
+ if (this.$tag == {{union.name}}.Tags.{{field.name}}) {
+{%- from "fuzzing.tmpl" import get_handle_deps %}
+ return {{get_handle_deps(field.kind, 'this.' ~ field.name)}};
+ }
+{%- endif %}
+{%- endfor %}
+ return [];
+}
+
+{{union.name}}.prototype.setHandles = function() {
+{%- for field in union.fields %}
+{%- if field.kind|contains_handles_or_interfaces %}
+ if (this.$tag == {{union.name}}.Tags.{{field.name}}) {
+{%- from "fuzzing.tmpl" import set_handles %}
+ return {{set_handles(field.kind, 'this.' ~ field.name)}};
+ }
+{%- endif %}
+{%- endfor %}
+ return [];
+}
+{%- endif %}
+
{%- for field in union.fields %}
Object.defineProperty({{union.name}}.prototype, "{{field.name}}", {
get: function() {
diff --git a/mojo/public/tools/bindings/generators/mojom_js_generator.py b/mojo/public/tools/bindings/generators/mojom_js_generator.py
index 5a4de762ec..724268d665 100644
--- a/mojo/public/tools/bindings/generators/mojom_js_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_js_generator.py
@@ -136,6 +136,32 @@ _js_reserved_keywords = [
'yield',
]
+_primitive_kind_to_fuzz_type = {
+ mojom.BOOL: "Bool",
+ mojom.INT8: "Int8",
+ mojom.UINT8: "Uint8",
+ mojom.INT16: "Int16",
+ mojom.UINT16: "Uint16",
+ mojom.INT32: "Int32",
+ mojom.UINT32: "Uint32",
+ mojom.FLOAT: "Float",
+ mojom.INT64: "Int64",
+ mojom.UINT64: "Uint64",
+ mojom.DOUBLE: "Double",
+ mojom.STRING: "String",
+ mojom.NULLABLE_STRING: "String",
+ mojom.HANDLE: "Handle",
+ mojom.DCPIPE: "DataPipeConsumer",
+ mojom.DPPIPE: "DataPipeProducer",
+ mojom.MSGPIPE: "MessagePipe",
+ mojom.SHAREDBUFFER: "SharedBuffer",
+ mojom.NULLABLE_HANDLE: "Handle",
+ mojom.NULLABLE_DCPIPE: "DataPipeConsumer",
+ mojom.NULLABLE_DPPIPE: "DataPipeProducer",
+ mojom.NULLABLE_MSGPIPE: "MessagePipe",
+ mojom.NULLABLE_SHAREDBUFFER: "SharedBuffer",
+}
+
def JavaScriptPayloadSize(packed):
packed_fields = packed.packed_fields
@@ -207,6 +233,7 @@ class Generator(generator.Generator):
"module": self.module,
"structs": self.module.structs + self._GetStructsFromMethods(),
"unions": self.module.unions,
+ "generate_fuzzing": self.generate_fuzzing,
}
@staticmethod
@@ -231,10 +258,12 @@ class Generator(generator.Generator):
"is_bool_kind": mojom.IsBoolKind,
"is_enum_kind": mojom.IsEnumKind,
"is_any_handle_kind": mojom.IsAnyHandleKind,
+ "is_any_interface_kind": mojom.IsAnyInterfaceKind,
"is_interface_kind": mojom.IsInterfaceKind,
"is_interface_request_kind": mojom.IsInterfaceRequestKind,
"is_map_kind": mojom.IsMapKind,
"is_object_kind": mojom.IsObjectKind,
+ "is_reference_kind": mojom.IsReferenceKind,
"is_string_kind": mojom.IsStringKind,
"is_struct_kind": mojom.IsStructKind,
"is_union_kind": mojom.IsUnionKind,
@@ -253,6 +282,11 @@ class Generator(generator.Generator):
"validate_struct_params": self._JavaScriptValidateStructParams,
"validate_union_params": self._JavaScriptValidateUnionParams,
"sanitize_identifier": self._JavaScriptSanitizeIdentifier,
+ "contains_handles_or_interfaces": mojom.ContainsHandlesOrInterfaces,
+ "fuzz_handle_name": self._FuzzHandleName,
+ "is_primitive_kind": self._IsPrimitiveKind,
+ "primitive_to_fuzz_type": self._PrimitiveToFuzzType,
+ "to_js_boolean": self._ToJsBoolean,
}
return js_filters
@@ -540,3 +574,37 @@ class Generator(generator.Generator):
if method.response_param_struct is not None:
result.append(method.response_param_struct)
return result
+
+ def _FuzzHandleName(self, kind):
+ if mojom.IsInterfaceRequestKind(kind):
+ return '{0}.{1}Request'.format(kind.kind.module.namespace,
+ kind.kind.name)
+ elif mojom.IsInterfaceKind(kind):
+ return '{0}.{1}Ptr'.format(kind.module.namespace,
+ kind.name)
+ elif mojom.IsAssociatedInterfaceRequestKind(kind):
+ return '{0}.{1}AssociatedRequest'.format(kind.kind.module.namespace,
+ kind.kind.name)
+ elif mojom.IsAssociatedInterfaceKind(kind):
+ return '{0}.{1}AssociatedPtr'.format(kind.kind.module.namespace,
+ kind.kind.name)
+ elif mojom.IsSharedBufferKind(kind):
+ return 'handle<shared_buffer>'
+ elif mojom.IsDataPipeConsumerKind(kind):
+ return 'handle<data_pipe_consumer>'
+ elif mojom.IsDataPipeProducerKind(kind):
+ return 'handle<data_pipe_producer>'
+ elif mojom.IsMessagePipeKind(kind):
+ return 'handle<message_pipe>'
+
+ def _ToJsBoolean(self, value):
+ if value:
+ return 'true'
+
+ return 'false'
+
+ def _IsPrimitiveKind(self, kind):
+ return kind in mojom.PRIMITIVES
+
+ def _PrimitiveToFuzzType(self, kind):
+ return _primitive_kind_to_fuzz_type[kind]
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni
index 317d8c0fd3..11f6395591 100644
--- a/mojo/public/tools/bindings/mojom.gni
+++ b/mojo/public/tools/bindings/mojom.gni
@@ -13,6 +13,7 @@ import("//build/config/chrome_build.gni")
import("//build/config/nacl/config.gni")
import("//components/nacl/features.gni")
import("//third_party/jinja2/jinja2.gni")
+import("//tools/ipc_fuzzer/ipc_fuzzer.gni")
declare_args() {
# Indicates whether typemapping should be supported in this build
@@ -1128,7 +1129,7 @@ template("mojom") {
}
}
- if (!defined(invoker.cpp_only) || !invoker.cpp_only) {
+ if (enable_ipc_fuzzer || !defined(invoker.cpp_only) || !invoker.cpp_only) {
if (defined(invoker.sources)) {
generator_js_target_name = "${target_name}_js__generator"
generator_js_outputs = [
@@ -1170,6 +1171,10 @@ template("mojom") {
inputs += message_scrambling_inputs
args += message_scrambling_args
}
+
+ if (enable_ipc_fuzzer) {
+ args += [ "--generate_fuzzing" ]
+ }
}
}
diff --git a/mojo/public/tools/bindings/mojom_bindings_generator.py b/mojo/public/tools/bindings/mojom_bindings_generator.py
index 4117629e99..affbe79d91 100755
--- a/mojo/public/tools/bindings/mojom_bindings_generator.py
+++ b/mojo/public/tools/bindings/mojom_bindings_generator.py
@@ -214,7 +214,8 @@ class MojomProcessor(object):
support_lazy_serialization=args.support_lazy_serialization,
disallow_native_types=args.disallow_native_types,
disallow_interfaces=args.disallow_interfaces,
- generate_message_ids=args.generate_message_ids)
+ generate_message_ids=args.generate_message_ids,
+ generate_fuzzing=args.generate_fuzzing)
filtered_args = []
if hasattr(generator_module, 'GENERATOR_PREFIX'):
prefix = '--' + generator_module.GENERATOR_PREFIX + '_'
@@ -466,6 +467,10 @@ def main():
help="Generates only the message IDs header for C++ bindings. Note that "
"this flag only matters if --generate_non_variant_code is also "
"specified.", action="store_true")
+ generate_parser.add_argument(
+ "--generate_fuzzing",
+ action="store_true",
+ help="Generates additional bindings for fuzzing in JS.")
generate_parser.set_defaults(func=_Generate)
precompile_parser = subparsers.add_parser("precompile",
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/generator.py b/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
index c7acbb791b..acf029f6a1 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
@@ -164,7 +164,8 @@ class Generator(object):
js_bindings_mode="new", export_attribute=None,
export_header=None, generate_non_variant_code=False,
support_lazy_serialization=False, disallow_native_types=False,
- disallow_interfaces=False, generate_message_ids=False):
+ disallow_interfaces=False, generate_message_ids=False,
+ generate_fuzzing=False):
self.module = module
self.output_dir = output_dir
self.typemap = typemap or {}
@@ -180,6 +181,7 @@ class Generator(object):
self.disallow_native_types = disallow_native_types
self.disallow_interfaces = disallow_interfaces
self.generate_message_ids = generate_message_ids
+ self.generate_fuzzing = generate_fuzzing
def Write(self, contents, filename):
if self.output_dir is None: