xref: /aosp_15_r20/external/angle/build/config/sanitizers/BUILD.gn (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1# Copyright 2014 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import("//build/config/cast.gni")
6import("//build/config/chrome_build.gni")
7import("//build/config/clang/clang.gni")
8import("//build/config/rust.gni")
9import("//build/config/sanitizers/sanitizers.gni")
10import("//build/toolchain/toolchain.gni")
11import("//build_overrides/build.gni")
12
13if (is_ios) {
14  import("//build/config/apple/mobile_config.gni")
15}
16
17# libfuzzer can't cope with shared objects being unloaded, which sometimes
18# occurs for large fuzzers that involve our graphics stack. Shim out dlclose
19# so that this doesn't occur.
20#
21# dlclose() is defined by POSIX, making `is_posix` a tempting condition to use.
22# However the linker does not necessarily support `-wrap` on all POSIX
23# platforms, hence the restriction to Linux and ChromeOS. We might eventually
24# want to disable shared library unloading on all platforms, but we have not
25# noticed a need for it as the known-affected large fuzzers only run on Linux.
26use_dlcloseshim = use_libfuzzer && (is_linux || is_chromeos)
27
28# Contains the dependencies needed for sanitizers to link into executables and
29# shared_libraries.
30group("deps") {
31  deps = []
32  data = []
33  if (using_sanitizer) {
34    public_configs = [
35      # Even when a target removes default_sanitizer_flags, it may be depending
36      # on a library that did not remove default_sanitizer_flags. Thus, we need
37      # to add the ldflags here as well as in default_sanitizer_flags.
38      ":default_sanitizer_ldflags",
39    ]
40    if (!is_fuchsia) {
41      if (is_win) {
42        exe = ".exe"
43      } else {
44        exe = ""
45      }
46      data += [
47        "//tools/valgrind/asan/",
48        "$clang_base_path/bin/llvm-symbolizer${exe}",
49      ]
50    }
51    if (is_asan || is_lsan || is_msan || is_tsan || is_ubsan_any) {
52      public_configs += [ ":sanitizer_options_link_helper" ]
53      deps += [ ":options_sources" ]
54    }
55    if (use_prebuilt_instrumented_libraries ||
56        use_locally_built_instrumented_libraries) {
57      deps += [ "//third_party/instrumented_libs:deps" ]
58    }
59  }
60  if (fail_on_san_warnings) {
61    data += [ "//tools/memory/sanitizer/escalate_sanitizer_warnings.py" ]
62  }
63  if (is_asan || is_ubsan_any) {
64    if (is_win || is_apple) {
65      data_deps = [ ":copy_sanitizer_runtime" ]
66    }
67    if (is_apple) {
68      public_deps = [ ":sanitizer_runtime_bundle_data" ]
69    }
70  }
71  if (use_centipede || enable_fuzztest_fuzz) {
72    # For executables which aren't actual fuzzers, we need stubs for
73    # the sanitizer coverage symbols, because we'll still be generating
74    # .o files which depend on them.
75    deps += [ "//third_party/fuzztest:centipede_weak_sancov_stubs" ]
76  }
77}
78
79assert(!(is_win && is_asan && current_cpu == "x86"),
80       "ASan is only supported in 64-bit builds on Windows.")
81
82if ((is_apple || is_win) && (is_asan || is_ubsan_any)) {
83  if (is_mac || (is_ios && target_environment == "catalyst")) {
84    if (is_asan) {
85      _clang_rt_dso_path = "darwin/libclang_rt.asan_osx_dynamic.dylib"
86    } else {
87      assert(is_ubsan_any)
88      _clang_rt_dso_path = "darwin/libclang_rt.ubsan_osx_dynamic.dylib"
89    }
90  } else if (is_ios) {
91    if (is_asan) {
92      if (target_environment == "simulator") {
93        _clang_rt_dso_path = "darwin/libclang_rt.asan_iossim_dynamic.dylib"
94      } else {
95        _clang_rt_dso_path = "darwin/libclang_rt.asan_ios_dynamic.dylib"
96      }
97    } else {
98      assert(is_ubsan_any)
99      _clang_rt_dso_path = "darwin/libclang_rt.ubsan_iossim_dynamic.dylib"
100    }
101  } else if (is_win && current_cpu == "x64") {
102    if (is_asan) {
103      _clang_rt_dso_path = "windows/clang_rt.asan_dynamic-x86_64.dll"
104    } else {
105      assert(is_ubsan_any)
106      _clang_rt_dso_path = "windows/clang_rt.ubsan_dynamic-x86_64.dll"
107    }
108  }
109
110  _clang_rt_dso_full_path =
111      "$clang_base_path/lib/clang/$clang_version/lib/$_clang_rt_dso_path"
112
113  if (!is_ios) {
114    copy("copy_sanitizer_runtime") {
115      sources = [ _clang_rt_dso_full_path ]
116      outputs = [ "$root_out_dir/{{source_file_part}}" ]
117    }
118  } else {
119    # On iOS, the runtime library need to be code signed (adhoc signature)
120    # starting with Xcode 8, so use an action instead of a copy on iOS.
121    action("copy_sanitizer_runtime") {
122      script = "//build/config/apple/codesign.py"
123      sources = [ _clang_rt_dso_full_path ]
124      outputs = [ "$root_out_dir/" + get_path_info(sources[0], "file") ]
125      args = [
126        "code-sign-file",
127        "--identity=" + ios_code_signing_identity,
128        "--output=" + rebase_path(outputs[0], root_build_dir),
129        rebase_path(sources[0], root_build_dir),
130      ]
131    }
132  }
133
134  if (is_apple) {
135    bundle_data("sanitizer_runtime_bundle_data") {
136      sources = get_target_outputs(":copy_sanitizer_runtime")
137      outputs = [ "{{bundle_executable_dir}}/{{source_file_part}}" ]
138      public_deps = [ ":copy_sanitizer_runtime" ]
139    }
140  }
141}
142
143config("sanitizer_options_link_helper") {
144  if (is_apple) {
145    ldflags = [ "-Wl,-u,__sanitizer_options_link_helper" ]
146  } else if (!is_win) {
147    ldflags = [ "-Wl,-u_sanitizer_options_link_helper" ]
148  }
149}
150
151static_library("options_sources") {
152  # This is a static_library instead of a source_set, as it shouldn't be
153  # unconditionally linked into targets.
154  visibility = [
155    ":deps",
156    "//:gn_all",
157  ]
158  sources = [ "//build/sanitizers/sanitizer_options.cc" ]
159
160  # Don't compile this target with any sanitizer code. It can be called from
161  # the sanitizer runtimes, so instrumenting these functions could cause
162  # recursive calls into the runtime if there is an error.
163  configs -= [ "//build/config/sanitizers:default_sanitizer_flags" ]
164
165  if (is_asan) {
166    if (!defined(asan_suppressions_file)) {
167      asan_suppressions_file = "//build/sanitizers/asan_suppressions.cc"
168    }
169    sources += [ asan_suppressions_file ]
170  }
171
172  if (is_lsan) {
173    if (!defined(lsan_suppressions_file)) {
174      lsan_suppressions_file = "//build/sanitizers/lsan_suppressions.cc"
175    }
176    sources += [ lsan_suppressions_file ]
177  }
178
179  if (is_tsan) {
180    if (!defined(tsan_suppressions_file)) {
181      tsan_suppressions_file = "//build/sanitizers/tsan_suppressions.cc"
182    }
183    sources += [ tsan_suppressions_file ]
184  }
185}
186
187if (use_dlcloseshim) {
188  source_set("dlclose_shim") {
189    sources = [ "//build/sanitizers/dlcloseshim.c" ]
190  }
191} else {
192  group("dlclose_shim") {
193    deps = []
194  }
195}
196
197# Applies linker flags necessary when either :deps or :default_sanitizer_flags
198# are used.
199config("default_sanitizer_ldflags") {
200  visibility = [
201    ":default_sanitizer_flags",
202    ":deps",
203
204    # https://crbug.com/360158.
205    "//tools/ipc_fuzzer/fuzzer:ipc_fuzzer",
206  ]
207
208  if (is_posix || is_fuchsia) {
209    sanitizers = []  # sanitizers applicable to both clang and rustc
210    ldflags = []
211    rustflags = []
212    if (is_asan) {
213      sanitizers += [ "address" ]
214    }
215    if (is_hwasan) {
216      sanitizers += [ "hwaddress" ]
217    }
218    if (is_lsan) {
219      # In Chromium, is_lsan always implies is_asan. ASAN includes LSAN.
220      # It seems harmless to pass both options to clang, but it doesn't
221      # work on rustc, so apply this option to clang only.
222      ldflags += [ "-fsanitize=leak" ]
223    }
224    if (is_tsan) {
225      sanitizers += [ "thread" ]
226    }
227    if (is_msan) {
228      sanitizers += [ "memory" ]
229    }
230    if (is_ubsan || is_ubsan_security) {
231      ldflags += [ "-fsanitize=undefined" ]
232    }
233    if (is_ubsan_vptr) {
234      ldflags += [ "-fsanitize=vptr" ]
235    }
236    foreach(sanitizer, sanitizers) {
237      ldflags += [ "-fsanitize=$sanitizer" ]
238      rustflags += [ "-Zsanitizer=$sanitizer" ]
239    }
240
241    if (use_sanitizer_coverage) {
242      if (use_libfuzzer) {
243        ldflags += [ "-fsanitize=fuzzer-no-link" ]
244        if (is_mac) {
245          # TODO(crbug.com/40611636): on macOS, dead code stripping does not work
246          # well with `pc-table` instrumentation enabled by `fuzzer-no-link`.
247          ldflags += [ "-fno-sanitize-coverage=pc-table" ]
248        }
249      } else {
250        ldflags += [ "-fsanitize-coverage=$sanitizer_coverage_flags" ]
251      }
252      if (is_mac && use_centipede) {
253        # OS X linking doesn't allow undefined symbols at link time
254        # and in a component build, component shared objects will
255        # need to use this symbol to report control flow coverage
256        # to the main binary
257        ldflags += [ "-Wl,-undefined,dynamic_lookup" ]
258      }
259    }
260
261    if (is_cfi && current_toolchain == default_toolchain) {
262      ldflags += [ "-fsanitize=cfi-vcall" ]
263      if (use_cfi_cast) {
264        ldflags += [
265          "-fsanitize=cfi-derived-cast",
266          "-fsanitize=cfi-unrelated-cast",
267        ]
268      }
269      if (use_cfi_icall) {
270        ldflags += [ "-fsanitize=cfi-icall" ]
271      }
272      if (use_cfi_diag) {
273        ldflags += [ "-fno-sanitize-trap=cfi" ]
274        if (use_cfi_recover) {
275          ldflags += [ "-fsanitize-recover=cfi" ]
276        }
277      }
278    }
279  } else if (is_win) {
280    # Windows directly calls link.exe instead of the compiler driver when
281    # linking.  Hence, pass the runtime libraries instead of -fsanitize=address
282    # or -fsanitize=fuzzer.
283    ldflags = []
284    if (is_asan) {
285      assert(current_cpu == "x64", "WinASan unsupported architecture")
286      libs = [ "clang_rt.asan_dynamic-x86_64.lib" ]
287      if (is_component_build) {
288        ldflags +=
289            [ "-wholearchive:clang_rt.asan_dynamic_runtime_thunk-x86_64.lib" ]
290      } else {
291        ldflags +=
292            [ "-wholearchive:clang_rt.asan_static_runtime_thunk-x86_64.lib" ]
293      }
294    }
295    if (use_libfuzzer) {
296      assert(current_cpu == "x64", "LibFuzzer unsupported architecture")
297      assert(!is_component_build,
298             "LibFuzzer only supports non-component builds on Windows")
299
300      # Incremental linking causes padding that messes up SanitizerCoverage.
301      # Don't do it.
302      ldflags += [ "/INCREMENTAL:NO" ]
303    }
304  }
305  if (use_dlcloseshim) {
306    ldflags += [ "-Wl,-wrap,dlclose" ]
307  }
308}
309
310config("common_sanitizer_flags") {
311  cflags = []
312
313  if (using_sanitizer) {
314    assert(is_clang, "sanitizers only supported with clang")
315
316    # Allow non-default toolchains to enable sanitizers in toolchain_args even
317    # in official builds.
318    assert(current_toolchain != default_toolchain || !is_official_build,
319           "sanitizers not supported in official builds")
320
321    cflags += [
322      # Column info in debug data confuses Visual Studio's debugger, so don't
323      # use this by default.  However, clusterfuzz needs it for good
324      # attribution of reports to CLs, so turn it on there.
325      "-gcolumn-info",
326    ]
327
328    # Frame pointers are controlled in //build/config/compiler:default_stack_frames
329  }
330}
331
332config("asan_flags") {
333  cflags = []
334  rustflags = []
335  if (is_asan) {
336    cflags += [ "-fsanitize=address" ]
337    rustflags += [ "-Zsanitizer=address" ]
338    if (!is_win && !is_apple && !is_fuchsia) {
339      # TODO(crbug.com/1459233, crbug.com/1462248): This causes asan
340      # odr-violation errors in rust code, and link failures for cros/asan.
341      # Clang recently turned it on by default for all ELF targets (it was
342      # already on for Fuchsia). Pass the flag to turn it back off.
343      cflags += [ "-fno-sanitize-address-globals-dead-stripping" ]
344    }
345    if (is_win) {
346      if (!defined(asan_win_blocklist_path)) {
347        asan_win_blocklist_path =
348            rebase_path("//tools/memory/asan/blocklist_win.txt", root_build_dir)
349      }
350      cflags += [ "-fsanitize-ignorelist=$asan_win_blocklist_path" ]
351    }
352  }
353}
354
355config("cfi_flags") {
356  cflags = []
357  rustflags = []
358  if (is_cfi && current_toolchain == default_toolchain) {
359    if (!defined(cfi_ignorelist_path)) {
360      cfi_ignorelist_path =
361          rebase_path("//tools/cfi/ignores.txt", root_build_dir)
362    }
363    cflags += [
364      "-fsanitize=cfi-vcall",
365      "-fsanitize-ignorelist=$cfi_ignorelist_path",
366    ]
367
368    if (toolchain_supports_rust_thin_lto) {
369      # sanitize=cfi implies -fsplit-lto-unit, and Rust needs to match
370      # behaviour.  Rust needs to know the linker will be doing LTO in this case
371      # or it rejects the Zsplit-lto-unit flag.
372      # TODO(crbug.com/40266913): Add -Zsanitize=cfi instead.
373      rustflags += [
374        "-Zsplit-lto-unit",
375        "-Clinker-plugin-lto=yes",
376      ]
377    } else {
378      # Don't include bitcode if it won't be used.
379      rustflags += [ "-Cembed-bitcode=no" ]
380    }
381
382    if (use_cfi_cast) {
383      cflags += [
384        "-fsanitize=cfi-derived-cast",
385        "-fsanitize=cfi-unrelated-cast",
386      ]
387    }
388
389    if (use_cfi_icall) {
390      cflags += [ "-fsanitize=cfi-icall" ]
391      # TODO(crbug.com/40266913): Add cflags += [
392      # "-fsanitize-cfi-icall-experimental-normalize-integers" ]
393      # TODO(crbug.com/40266913): Add rustflags += [
394      # "-Zsanitizer-cfi-normalize-integers" ].
395    }
396
397    if (use_cfi_diag) {
398      cflags += [ "-fno-sanitize-trap=cfi" ]
399      if (is_win) {
400        cflags += [
401          "/Oy-",
402          "/Ob0",
403        ]
404      } else {
405        cflags += [
406          "-fno-inline-functions",
407          "-fno-inline",
408          "-fno-omit-frame-pointer",
409          "-O1",
410        ]
411      }
412      if (use_cfi_recover) {
413        cflags += [ "-fsanitize-recover=cfi" ]
414      }
415    }
416  }
417}
418
419# crbug.com/785442: Fix cfi-icall failures for code that casts pointer argument
420# types in function pointer type signatures.
421config("cfi_icall_generalize_pointers") {
422  if (is_clang && is_cfi && use_cfi_icall) {
423    cflags = [ "-fsanitize-cfi-icall-generalize-pointers" ]
424  }
425}
426
427config("cfi_icall_disable") {
428  if (is_clang && is_cfi && use_cfi_icall) {
429    cflags = [ "-fno-sanitize=cfi-icall" ]
430  }
431}
432
433config("coverage_flags") {
434  cflags = []
435  if (use_sanitizer_coverage) {
436    # Used by sandboxing code to allow coverage dump to be written on the disk.
437    defines = [ "SANITIZER_COVERAGE" ]
438
439    if (use_libfuzzer) {
440      cflags += [ "-fsanitize=fuzzer-no-link" ]
441      if (is_mac) {
442        # TODO(crbug.com/40611636): on macOS, dead code stripping does not work
443        # well with `pc-table` instrumentation enabled by `fuzzer-no-link`.
444        cflags += [ "-fno-sanitize-coverage=pc-table" ]
445      }
446    } else {
447      cflags += [
448        "-fsanitize-coverage=$sanitizer_coverage_flags",
449        "-mllvm",
450        "-sanitizer-coverage-prune-blocks=1",
451      ]
452      if (current_cpu == "arm") {
453        # http://crbug.com/517105
454        cflags += [
455          "-mllvm",
456          "-sanitizer-coverage-block-threshold=0",
457        ]
458      }
459    }
460    if (sanitizer_coverage_allowlist != "") {
461      cflags += [ "-fsanitize-coverage-allowlist=" +
462                  rebase_path(sanitizer_coverage_allowlist, root_build_dir) ]
463    }
464  }
465  if (use_centipede) {
466    # Centipede intercepts calls such as memcmp and memcpy in order to improve
467    # its testcase generation.
468    cflags += [ "-fno-builtin" ]
469  }
470}
471
472config("hwasan_flags") {
473  if (is_hwasan) {
474    asmflags = [ "-fsanitize=hwaddress" ]
475    cflags = [ "-fsanitize=hwaddress" ]
476  }
477}
478
479config("lsan_flags") {
480  if (is_lsan) {
481    cflags = [ "-fsanitize=leak" ]
482  }
483}
484
485config("msan_flags") {
486  if (is_msan) {
487    assert(is_linux || is_chromeos,
488           "msan only supported on linux x86_64/ChromeOS")
489    if (!defined(msan_ignorelist_path)) {
490      msan_ignorelist_path =
491          rebase_path("//tools/msan/ignorelist.txt", root_build_dir)
492    }
493    cflags = [
494      "-fsanitize=memory",
495      "-fsanitize-memory-track-origins=$msan_track_origins",
496      "-fsanitize-ignorelist=$msan_ignorelist_path",
497    ]
498
499    if (!msan_check_use_after_dtor) {
500      # TODO(crbug.com/40222690): evaluate and possibly enable
501      cflags += [ "-fno-sanitize-memory-use-after-dtor" ]
502    }
503
504    if (!msan_eager_checks) {
505      cflags += [ "-fno-sanitize-memory-param-retval" ]
506    }
507  }
508}
509
510config("tsan_flags") {
511  if (is_tsan) {
512    assert(is_linux || is_chromeos, "tsan only supported on linux x86_64")
513    if (!defined(tsan_ignorelist_path)) {
514      tsan_ignorelist_path =
515          rebase_path("//tools/memory/tsan_v2/ignores.txt", root_build_dir)
516    }
517    cflags = [
518      "-fsanitize=thread",
519      "-fsanitize-ignorelist=$tsan_ignorelist_path",
520    ]
521  }
522}
523
524config("ubsan_flags") {
525  cflags = []
526  if (is_ubsan) {
527    if (!defined(ubsan_ignorelist_path)) {
528      ubsan_ignorelist_path =
529          rebase_path("//tools/ubsan/ignorelist.txt", root_build_dir)
530    }
531
532    # TODO(crbug.com/40942951): Enable all of -fsanitize=undefined. Note that
533    # both this list and Clang's defaults omit -fsanitize=float-divide-by-zero.
534    # C and C++ leave it undefined to accommodate non-IEEE floating point, but
535    # we assume the compiler implements IEEE floating point, which does define
536    # division by zero.
537    cflags += [
538      "-fsanitize=alignment",
539      "-fsanitize=bool",
540      "-fsanitize=bounds",
541      "-fsanitize=builtin",
542      "-fsanitize=integer-divide-by-zero",
543      "-fsanitize=null",
544      "-fsanitize=nonnull-attribute",
545      "-fsanitize=object-size",
546      "-fsanitize=return",
547      "-fsanitize=returns-nonnull-attribute",
548      "-fsanitize=shift",
549      "-fsanitize=signed-integer-overflow",
550      "-fsanitize=unreachable",
551      "-fsanitize=vla-bound",
552      "-fsanitize-ignorelist=$ubsan_ignorelist_path",
553    ]
554  }
555}
556
557config("ubsan_no_recover") {
558  if (is_ubsan_no_recover) {
559    cflags = [ "-fno-sanitize-recover=undefined" ]
560  }
561}
562
563config("ubsan_security_flags") {
564  if (is_ubsan_security) {
565    if (!defined(ubsan_security_ignorelist_path)) {
566      ubsan_security_ignorelist_path =
567          rebase_path("//tools/ubsan/security_ignorelist.txt", root_build_dir)
568    }
569    cflags = [
570      "-fsanitize=function",
571      "-fsanitize=shift",
572      "-fsanitize=signed-integer-overflow",
573      "-fsanitize=vla-bound",
574      "-fsanitize-ignorelist=$ubsan_security_ignorelist_path",
575    ]
576  }
577}
578
579config("ubsan_vptr_flags") {
580  if (is_ubsan_vptr) {
581    if (!defined(ubsan_vptr_ignorelist_path)) {
582      ubsan_vptr_ignorelist_path =
583          rebase_path("//tools/ubsan/vptr_ignorelist.txt", root_build_dir)
584    }
585    cflags = [
586      "-fsanitize=vptr",
587      "-fsanitize-ignorelist=$ubsan_vptr_ignorelist_path",
588    ]
589  }
590}
591
592config("fuzzing_build_mode") {
593  if (use_fuzzing_engine) {
594    defines = [ "FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION" ]
595  }
596}
597
598all_sanitizer_configs = [
599  ":common_sanitizer_flags",
600  ":coverage_flags",
601  ":default_sanitizer_ldflags",
602  ":asan_flags",
603  ":cfi_flags",
604  ":hwasan_flags",
605  ":lsan_flags",
606  ":msan_flags",
607  ":tsan_flags",
608  ":ubsan_flags",
609  ":ubsan_no_recover",
610  ":ubsan_security_flags",
611  ":ubsan_vptr_flags",
612  ":fuzzing_build_mode",
613]
614
615# This config is applied by default to all targets. It sets the compiler flags
616# for sanitizer usage, or, if no sanitizer is set, does nothing.
617#
618# This needs to be in a separate config so that targets can opt out of
619# sanitizers (by removing the config) if they desire. Even if a target
620# removes this config, executables & shared libraries should still depend on
621# :deps if any of their dependencies have not opted out of sanitizers.
622# Keep this list in sync with default_sanitizer_flags_but_ubsan_vptr.
623config("default_sanitizer_flags") {
624  configs = all_sanitizer_configs
625
626  if (use_sanitizer_configs_without_instrumentation) {
627    configs = []
628  }
629}
630
631# This config is equivalent to default_sanitizer_flags, but excludes ubsan_vptr.
632# This allows to selectively disable ubsan_vptr, when needed. In particular,
633# if some third_party code is required to be compiled without rtti, which
634# is a requirement for ubsan_vptr.
635config("default_sanitizer_flags_but_ubsan_vptr") {
636  configs = all_sanitizer_configs - [ ":ubsan_vptr_flags" ]
637
638  if (use_sanitizer_configs_without_instrumentation) {
639    configs = []
640  }
641}
642
643config("default_sanitizer_flags_but_coverage") {
644  configs = all_sanitizer_configs - [ ":coverage_flags" ]
645
646  if (use_sanitizer_configs_without_instrumentation) {
647    configs = []
648  }
649}
650
651# This config is used by parts of code that aren't targeted in fuzzers and
652# therefore don't need coverage instrumentation and possibly wont need
653# sanitizer instrumentation either. The config also tells the compiler to
654# perform additional optimizations on the configured code and ensures that
655# linking it to the rest of the binary which is instrumented with sanitizers
656# works. The config only does anything if the build is a fuzzing build.
657config("not_fuzzed") {
658  if (use_fuzzing_engine) {
659    # Since we aren't instrumenting with coverage, code size is less of a
660    # concern, so use a more aggressive optimization level than
661    # optimize_for_fuzzing (-O1). When given multiple optimization flags, clang
662    # obeys the last one, so as long as this flag comes after -O1, it should work.
663    # Since this config will always be depended on after
664    # "//build/config/compiler:default_optimization" (which adds -O1 when
665    # optimize_for_fuzzing is true), -O2 should always be the second flag. Even
666    # though this sounds fragile, it isn't a big deal if it breaks, since proto
667    # fuzzers will still work, they will just be slightly slower.
668    cflags = [ "-O2" ]
669
670    # We need to include this config when we remove default_sanitizer_flags or
671    # else there will be linking errors. We would remove default_sanitizer_flags
672    # here as well, but gn doesn't permit this.
673    if (!is_msan) {
674      # We don't actually remove sanitization when MSan is being used so there
675      # is no need to add default_sanitizer_ldflags in that case
676      configs = [ ":default_sanitizer_ldflags" ]
677    }
678  }
679}
680