summaryrefslogtreecommitdiff
path: root/lib/dfsan
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dfsan')
-rw-r--r--lib/dfsan/dfsan.cc14
1 files changed, 13 insertions, 1 deletions
diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc
index 11ab77e2e..a9673d5c5 100644
--- a/lib/dfsan/dfsan.cc
+++ b/lib/dfsan/dfsan.cc
@@ -169,8 +169,20 @@ dfsan_label dfsan_create_label(const char *desc, void *userdata) {
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __dfsan_set_label(dfsan_label label, void *addr, uptr size) {
- for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)
+ for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) {
+ // Don't write the label if it is already the value we need it to be.
+ // In a program where most addresses are not labeled, it is common that
+ // a page of shadow memory is entirely zeroed. The Linux copy-on-write
+ // implementation will share all of the zeroed pages, making a copy of a
+ // page when any value is written. The un-sharing will happen even if
+ // the value written does not change the value in memory. Avoiding the
+ // write when both |label| and |*labelp| are zero dramatically reduces
+ // the amount of real memory used by large programs.
+ if (label == *labelp)
+ continue;
+
*labelp = label;
+ }
}
SANITIZER_INTERFACE_ATTRIBUTE