melver updated this revision to Diff 346577.
melver added a comment.
Herald added a subscriber: steven_wu.
Rest of long-tail of IR changes related to introducing a new attributes...
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D102772/new/
https://reviews.llvm.org/D102772
Files:
clang/docs/SanitizerCoverage.rst
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/lib/CodeGen/CodeGenFunction.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/CodeGen/sanitize-coverage.c
llvm/bindings/go/llvm/ir_test.go
llvm/docs/BitCodeFormat.rst
llvm/docs/LangRef.rst
llvm/include/llvm/AsmParser/LLToken.h
llvm/include/llvm/Bitcode/LLVMBitCodes.h
llvm/include/llvm/IR/Attributes.td
llvm/lib/AsmParser/LLLexer.cpp
llvm/lib/AsmParser/LLParser.cpp
llvm/lib/Bitcode/Reader/BitcodeReader.cpp
llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
llvm/lib/IR/Attributes.cpp
llvm/lib/IR/Verifier.cpp
llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp
llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
llvm/lib/Transforms/Utils/CodeExtractor.cpp
llvm/test/Bitcode/attributes.ll
llvm/test/Bitcode/compatibility.ll
llvm/utils/emacs/llvm-mode.el
llvm/utils/llvm.grm
llvm/utils/vim/syntax/llvm.vim
llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml
Index: llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml
===================================================================
--- llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml
+++ llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml
@@ -237,6 +237,7 @@
\\bnosync\\b|\
\\bnoundef\\b|\
\\bnounwind\\b|\
+ \\bno_sanitize_coverage\\b|\
\\bnull_pointer_is_valid\\b|\
\\boptforfuzzing\\b|\
\\boptnone\\b|\
Index: llvm/utils/vim/syntax/llvm.vim
===================================================================
--- llvm/utils/vim/syntax/llvm.vim
+++ llvm/utils/vim/syntax/llvm.vim
@@ -138,6 +138,7 @@
\ nosync
\ noundef
\ nounwind
+ \ no_sanitize_coverage
\ null_pointer_is_valid
\ optforfuzzing
\ optnone
Index: llvm/utils/llvm.grm
===================================================================
--- llvm/utils/llvm.grm
+++ llvm/utils/llvm.grm
@@ -176,6 +176,7 @@
| sanitize_thread
| sanitize_memory
| mustprogress
+ | no_sanitize_coverage
;
OptFuncAttrs ::= + _ | OptFuncAttrs FuncAttr ;
Index: llvm/utils/emacs/llvm-mode.el
===================================================================
--- llvm/utils/emacs/llvm-mode.el
+++ llvm/utils/emacs/llvm-mode.el
@@ -25,7 +25,7 @@
'("alwaysinline" "argmemonly" "allocsize" "builtin" "cold" "convergent" "dereferenceable" "dereferenceable_or_null" "hot" "inaccessiblememonly"
"inaccessiblemem_or_argmemonly" "inalloca" "inlinehint" "jumptable" "minsize" "mustprogress" "naked" "nobuiltin" "nonnull"
"nocallback" "nocf_check" "noduplicate" "nofree" "noimplicitfloat" "noinline" "nomerge" "nonlazybind" "noprofile" "noredzone" "noreturn"
- "norecurse" "nosync" "noundef" "nounwind" "null_pointer_is_valid" "optforfuzzing" "optnone" "optsize" "preallocated" "readnone" "readonly" "returned" "returns_twice"
+ "norecurse" "nosync" "noundef" "nounwind" "no_sanitize_coverage" "null_pointer_is_valid" "optforfuzzing" "optnone" "optsize" "preallocated" "readnone" "readonly" "returned" "returns_twice"
"shadowcallstack" "speculatable" "speculative_load_hardening" "ssp" "sspreq" "sspstrong" "safestack" "sanitize_address" "sanitize_hwaddress" "sanitize_memtag"
"sanitize_thread" "sanitize_memory" "strictfp" "swifterror" "uwtable" "vscale_range" "willreturn" "writeonly" "immarg") 'symbols) . font-lock-constant-face)
;; Variables
Index: llvm/test/Bitcode/compatibility.ll
===================================================================
--- llvm/test/Bitcode/compatibility.ll
+++ llvm/test/Bitcode/compatibility.ll
@@ -1510,7 +1510,7 @@
; CHECK: select <2 x i1> <i1 true, i1 false>, <2 x i8> <i8 2, i8 3>, <2 x i8> <i8 3, i8 2>
call void @f.nobuiltin() builtin
- ; CHECK: call void @f.nobuiltin() #44
+ ; CHECK: call void @f.nobuiltin() #45
call fastcc noalias i32* @f.noalias() noinline
; CHECK: call fastcc noalias i32* @f.noalias() #12
@@ -1904,6 +1904,9 @@
ret void
}
+declare void @f.no_sanitize_coverage() no_sanitize_coverage
+; CHECK: declare void @f.no_sanitize_coverage() #44
+
; immarg attribute
declare void @llvm.test.immarg.intrinsic(i32 immarg)
; CHECK: declare void @llvm.test.immarg.intrinsic(i32 immarg)
@@ -1961,7 +1964,8 @@
; CHECK: attributes #41 = { writeonly }
; CHECK: attributes #42 = { speculatable }
; CHECK: attributes #43 = { strictfp }
-; CHECK: attributes #44 = { builtin }
+; CHECK: attributes #44 = { no_sanitize_coverage }
+; CHECK: attributes #45 = { builtin }
;; Metadata
Index: llvm/test/Bitcode/attributes.ll
===================================================================
--- llvm/test/Bitcode/attributes.ll
+++ llvm/test/Bitcode/attributes.ll
@@ -453,6 +453,12 @@
ret void;
}
+; CHECK: define void @f77() #48
+define void @f77() no_sanitize_coverage
+{
+ ret void;
+}
+
; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { readnone }
@@ -501,4 +507,5 @@
; CHECK: attributes #45 = { vscale_range(8,8) }
; CHECK: attributes #46 = { vscale_range(1,8) }
; CHECK: attributes #47 = { vscale_range(1,0) }
+; CHECK: attributes #48 = { no_sanitize_coverage }
; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin }
Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp
===================================================================
--- llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -954,6 +954,7 @@
case Attribute::NonLazyBind:
case Attribute::NoRedZone:
case Attribute::NoUnwind:
+ case Attribute::NoSanitizeCoverage:
case Attribute::NullPointerIsValid:
case Attribute::OptForFuzzing:
case Attribute::OptimizeNone:
Index: llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
===================================================================
--- llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
+++ llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
@@ -621,6 +621,8 @@
return;
if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName()))
return;
+ if (F.hasFnAttribute(Attribute::NoSanitizeCoverage))
+ return;
if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
SplitAllCriticalEdges(F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests());
SmallVector<Instruction *, 8> IndirCalls;
Index: llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp
===================================================================
--- llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp
+++ llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp
@@ -53,6 +53,7 @@
.Case("nocf_check", Attribute::NoCfCheck)
.Case("norecurse", Attribute::NoRecurse)
.Case("nounwind", Attribute::NoUnwind)
+ .Case("no_sanitize_coverage", Attribute::NoSanitizeCoverage)
.Case("optforfuzzing", Attribute::OptForFuzzing)
.Case("optnone", Attribute::OptimizeNone)
.Case("optsize", Attribute::OptimizeForSize)
Index: llvm/lib/IR/Verifier.cpp
===================================================================
--- llvm/lib/IR/Verifier.cpp
+++ llvm/lib/IR/Verifier.cpp
@@ -1661,6 +1661,7 @@
case Attribute::NoCfCheck:
case Attribute::NoUnwind:
case Attribute::NoInline:
+ case Attribute::NoSanitizeCoverage:
case Attribute::AlwaysInline:
case Attribute::OptimizeForSize:
case Attribute::StackProtect:
Index: llvm/lib/IR/Attributes.cpp
===================================================================
--- llvm/lib/IR/Attributes.cpp
+++ llvm/lib/IR/Attributes.cpp
@@ -442,6 +442,8 @@
return "noprofile";
if (hasAttribute(Attribute::NoUnwind))
return "nounwind";
+ if (hasAttribute(Attribute::NoSanitizeCoverage))
+ return "no_sanitize_coverage";
if (hasAttribute(Attribute::OptForFuzzing))
return "optforfuzzing";
if (hasAttribute(Attribute::OptimizeNone))
Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
===================================================================
--- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -686,6 +686,8 @@
return bitc::ATTR_KIND_NO_PROFILE;
case Attribute::NoUnwind:
return bitc::ATTR_KIND_NO_UNWIND;
+ case Attribute::NoSanitizeCoverage:
+ return bitc::ATTR_KIND_NO_SANITIZE_COVERAGE;
case Attribute::NullPointerIsValid:
return bitc::ATTR_KIND_NULL_POINTER_IS_VALID;
case Attribute::OptForFuzzing:
Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp
===================================================================
--- llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -1474,6 +1474,8 @@
return Attribute::NoCfCheck;
case bitc::ATTR_KIND_NO_UNWIND:
return Attribute::NoUnwind;
+ case bitc::ATTR_KIND_NO_SANITIZE_COVERAGE:
+ return Attribute::NoSanitizeCoverage;
case bitc::ATTR_KIND_NULL_POINTER_IS_VALID:
return Attribute::NullPointerIsValid;
case bitc::ATTR_KIND_OPT_FOR_FUZZING:
Index: llvm/lib/AsmParser/LLParser.cpp
===================================================================
--- llvm/lib/AsmParser/LLParser.cpp
+++ llvm/lib/AsmParser/LLParser.cpp
@@ -1397,6 +1397,9 @@
case lltok::kw_noprofile: B.addAttribute(Attribute::NoProfile); break;
case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break;
case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break;
+ case lltok::kw_no_sanitize_coverage:
+ B.addAttribute(Attribute::NoSanitizeCoverage);
+ break;
case lltok::kw_null_pointer_is_valid:
B.addAttribute(Attribute::NullPointerIsValid); break;
case lltok::kw_optforfuzzing:
@@ -1824,6 +1827,7 @@
case lltok::kw_noreturn:
case lltok::kw_nocf_check:
case lltok::kw_nounwind:
+ case lltok::kw_no_sanitize_coverage:
case lltok::kw_optforfuzzing:
case lltok::kw_optnone:
case lltok::kw_optsize:
@@ -1935,6 +1939,7 @@
case lltok::kw_noreturn:
case lltok::kw_nocf_check:
case lltok::kw_nounwind:
+ case lltok::kw_no_sanitize_coverage:
case lltok::kw_optforfuzzing:
case lltok::kw_optnone:
case lltok::kw_optsize:
Index: llvm/lib/AsmParser/LLLexer.cpp
===================================================================
--- llvm/lib/AsmParser/LLLexer.cpp
+++ llvm/lib/AsmParser/LLLexer.cpp
@@ -671,6 +671,7 @@
KEYWORD(nocf_check);
KEYWORD(noundef);
KEYWORD(nounwind);
+ KEYWORD(no_sanitize_coverage);
KEYWORD(null_pointer_is_valid);
KEYWORD(optforfuzzing);
KEYWORD(optnone);
Index: llvm/include/llvm/IR/Attributes.td
===================================================================
--- llvm/include/llvm/IR/Attributes.td
+++ llvm/include/llvm/IR/Attributes.td
@@ -154,6 +154,9 @@
/// Function doesn't unwind stack.
def NoUnwind : EnumAttr<"nounwind">;
+/// No SanitizeCoverage instrumentation.
+def NoSanitizeCoverage : EnumAttr<"no_sanitize_coverage">;
+
/// Null pointer in address space zero is valid.
def NullPointerIsValid : EnumAttr<"null_pointer_is_valid">;
Index: llvm/include/llvm/Bitcode/LLVMBitCodes.h
===================================================================
--- llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -666,6 +666,7 @@
ATTR_KIND_NO_PROFILE = 73,
ATTR_KIND_VSCALE_RANGE = 74,
ATTR_KIND_SWIFT_ASYNC = 75,
+ ATTR_KIND_NO_SANITIZE_COVERAGE = 76,
};
enum ComdatSelectionKindCodes {
Index: llvm/include/llvm/AsmParser/LLToken.h
===================================================================
--- llvm/include/llvm/AsmParser/LLToken.h
+++ llvm/include/llvm/AsmParser/LLToken.h
@@ -217,6 +217,7 @@
kw_nosync,
kw_nocf_check,
kw_nounwind,
+ kw_no_sanitize_coverage,
kw_null_pointer_is_valid,
kw_optforfuzzing,
kw_optnone,
Index: llvm/docs/LangRef.rst
===================================================================
--- llvm/docs/LangRef.rst
+++ llvm/docs/LangRef.rst
@@ -1691,6 +1691,9 @@
trap or generate asynchronous exceptions. Exception handling schemes
that are recognized by LLVM to handle asynchronous exceptions, such
as SEH, will still provide their implementation defined semantics.
+``no_sanitize_coverage``
+ This attribute indicates that SanitizerCoverage instrumentation is disabled
+ for this function.
``null_pointer_is_valid``
If ``null_pointer_is_valid`` is set, then the ``null`` address
in address-space 0 is considered to be a valid address for memory loads and
Index: llvm/docs/BitCodeFormat.rst
===================================================================
--- llvm/docs/BitCodeFormat.rst
+++ llvm/docs/BitCodeFormat.rst
@@ -1073,6 +1073,8 @@
* code 69: ``byref``
* code 70: ``mustprogress``
* code 74: ``vscale_range(<Min>[, <Max>])``
+* code 75: ``swiftasync``
+* code 76: ``no_sanitize_coverage``
.. note::
The ``allocsize`` attribute has a special encoding for its arguments. Its two
Index: llvm/bindings/go/llvm/ir_test.go
===================================================================
--- llvm/bindings/go/llvm/ir_test.go
+++ llvm/bindings/go/llvm/ir_test.go
@@ -69,6 +69,7 @@
"noredzone",
"noreturn",
"nounwind",
+ "no_sanitize_coverage",
"optnone",
"optsize",
"readnone",
Index: clang/test/CodeGen/sanitize-coverage.c
===================================================================
--- clang/test/CodeGen/sanitize-coverage.c
+++ clang/test/CodeGen/sanitize-coverage.c
@@ -19,4 +19,71 @@
if (n)
x[n] = 42;
}
+
+static inline __attribute__((__always_inline__)) void always_inlined_fn(int n) {
+ if (n)
+ x[n] = 42;
+}
+// CHECK-LABEL: define dso_local void @test_always_inline(
+void test_always_inline(int n) {
+ // CHECK-DAG: call void @__sanitizer_cov_trace_pc
+ // CHECK-DAG: call void @__sanitizer_cov_trace_const_cmp
+ always_inlined_fn(n);
+}
+
+// CHECK-LABEL: define dso_local void @test_no_sanitize_coverage(
+__attribute__((no_sanitize("coverage"))) void test_no_sanitize_coverage(int n) {
+ // CHECK-NOT: call void @__sanitizer_cov_trace_pc
+ // CHECK-NOT: call void @__sanitizer_cov_trace_const_cmp
+ // ASAN-DAG: call void @__asan_report_store
+ // MSAN-DAG: call void @__msan_warning
+ // BOUNDS-DAG: call void @__ubsan_handle_out_of_bounds
+ // TSAN-DAG: call void @__tsan_func_entry
+ // UBSAN-DAG: call void @__ubsan_handle
+ if (n)
+ x[n] = 42;
+}
+
+
+// CHECK-LABEL: define dso_local void @test_no_sanitize_combined(
+__attribute__((no_sanitize("address", "memory", "thread", "bounds", "undefined", "coverage")))
+void test_no_sanitize_combined(int n) {
+ // CHECK-NOT: call void @__sanitizer_cov_trace_pc
+ // CHECK-NOT: call void @__sanitizer_cov_trace_const_cmp
+ // ASAN-NOT: call void @__asan_report_store
+ // MSAN-NOT: call void @__msan_warning
+ // BOUNDS-NOT: call void @__ubsan_handle_out_of_bounds
+ // TSAN-NOT: call void @__tsan_func_entry
+ // UBSAN-NOT: call void @__ubsan_handle
+ if (n)
+ x[n] = 42;
+}
+
+// CHECK-LABEL: define dso_local void @test_no_sanitize_separate(
+__attribute__((no_sanitize("address")))
+__attribute__((no_sanitize("memory")))
+__attribute__((no_sanitize("thread")))
+__attribute__((no_sanitize("bounds")))
+__attribute__((no_sanitize("undefined")))
+__attribute__((no_sanitize("coverage")))
+void test_no_sanitize_separate(int n) {
+ // CHECK-NOT: call void @__sanitizer_cov_trace_pc
+ // CHECK-NOT: call void @__sanitizer_cov_trace_const_cmp
+ // ASAN-NOT: call void @__asan_report_store
+ // MSAN-NOT: call void @__msan_warning
+ // BOUNDS-NOT: call void @__ubsan_handle_out_of_bounds
+ // TSAN-NOT: call void @__tsan_func_entry
+ // UBSAN-NOT: call void @__ubsan_handle
+ if (n)
+ x[n] = 42;
+}
+
+// CHECK-LABEL: define dso_local void @test_no_sanitize_always_inline(
+__attribute__((no_sanitize("coverage")))
+void test_no_sanitize_always_inline(int n) {
+ // CHECK-NOT: call void @__sanitizer_cov_trace_pc
+ // CHECK-NOT: call void @__sanitizer_cov_trace_const_cmp
+ always_inlined_fn(n);
+}
+
// CHECK-LABEL: declare void
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -7274,7 +7274,8 @@
return;
if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) ==
- SanitizerMask())
+ SanitizerMask() &&
+ SanitizerName != "coverage")
S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName;
else if (isGlobalVar(D) && SanitizerName != "address")
S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -734,8 +734,10 @@
} while (0);
if (D) {
- // Apply the no_sanitize* attributes to SanOpts.
+ bool NoSanitizeCoverage = false;
+
for (auto Attr : D->specific_attrs<NoSanitizeAttr>()) {
+ // Apply the no_sanitize* attributes to SanOpts.
SanitizerMask mask = Attr->getMask();
SanOpts.Mask &= ~mask;
if (mask & SanitizerKind::Address)
@@ -746,7 +748,18 @@
SanOpts.set(SanitizerKind::KernelHWAddress, false);
if (mask & SanitizerKind::KernelHWAddress)
SanOpts.set(SanitizerKind::HWAddress, false);
+
+ // SanitizeCoverage is not handled by SanOpts.
+ if (Attr->hasCoverage())
+ NoSanitizeCoverage = true;
}
+
+ bool HaveSanitizeCoverage =
+ CGM.getCodeGenOpts().SanitizeCoverageType ||
+ CGM.getCodeGenOpts().SanitizeCoverageIndirectCalls ||
+ CGM.getCodeGenOpts().SanitizeCoverageTraceCmp;
+ if (NoSanitizeCoverage && HaveSanitizeCoverage)
+ Fn->addFnAttr(llvm::Attribute::NoSanitizeCoverage);
}
// Apply sanitizer attributes to the function.
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -2564,12 +2564,17 @@
let Content = [{
Use the ``no_sanitize`` attribute on a function or a global variable
declaration to specify that a particular instrumentation or set of
-instrumentations should not be applied. The attribute takes a list of
-string literals, which have the same meaning as values accepted by the
-``-fno-sanitize=`` flag. For example,
-``__attribute__((no_sanitize("address", "thread")))`` specifies that
-AddressSanitizer and ThreadSanitizer should not be applied to the
-function or variable.
+instrumentations should not be applied.
+
+The attribute takes a list of string literals with the following accepted
+values:
+* all values accepted by ``-fno-sanitize=``;
+* ``coverage``, to disable SanitizerCoverage instrumentation.
+
+For example, ``__attribute__((no_sanitize("address", "thread")))`` specifies
+that AddressSanitizer and ThreadSanitizer should not be applied to the function
+or variable. Using ``__attribute__((no_sanitize("coverage")))`` specifies that
+SanitizerCoverage should not be applied to the function.
See :ref:`Controlling Code Generation <controlling-code-generation>` for a
full list of supported sanitizer flags.
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -2897,6 +2897,10 @@
}
return Mask;
}
+
+ bool hasCoverage() const {
+ return llvm::is_contained(sanitizers(), "coverage");
+ }
}];
}
Index: clang/docs/SanitizerCoverage.rst
===================================================================
--- clang/docs/SanitizerCoverage.rst
+++ clang/docs/SanitizerCoverage.rst
@@ -312,11 +312,17 @@
// for every non-constant array index.
void __sanitizer_cov_trace_gep(uintptr_t Idx);
-Partially disabling instrumentation
-===================================
+Disabling instrumentation with ``__attribute__((no_sanitize("coverage")))``
+===========================================================================
+
+It is possible to disable coverage instrumentation for select functions via the
+function attribute ``__attribute__((no_sanitize("coverage")))``.
+
+Disabling instrumentation without source modification
+=====================================================
It is sometimes useful to tell SanitizerCoverage to instrument only a subset of the
-functions in your target.
+functions in your target without modifying source files.
With ``-fsanitize-coverage-allowlist=allowlist.txt``
and ``-fsanitize-coverage-blocklist=blocklist.txt``,
you can specify such a subset through the combination of an allowlist and a blocklist.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits