[dfsan] Wrap strcat

Reviewed-by: morehouse

Differential Revision: https://reviews.llvm.org/D95923

GitOrigin-RevId: 15f26c5f5191fd4cfdece0e9621efd395ba57bc8
diff --git a/lib/dfsan/dfsan_custom.cpp b/lib/dfsan/dfsan_custom.cpp
index f90c8e8..e30e2a7 100644
--- a/lib/dfsan/dfsan_custom.cpp
+++ b/lib/dfsan/dfsan_custom.cpp
@@ -353,6 +353,20 @@
   return s;
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strcat(char *dest, const char *src,
+                                                  dfsan_label dest_label,
+                                                  dfsan_label src_label,
+                                                  dfsan_label *ret_label) {
+  size_t dest_len = strlen(dest);
+  char *ret = strcat(dest, src);
+  dfsan_label *sdest = shadow_for(dest + dest_len);
+  const dfsan_label *ssrc = shadow_for(src);
+  internal_memcpy((void *)sdest, (const void *)ssrc,
+                  strlen(src) * sizeof(dfsan_label));
+  *ret_label = dest_label;
+  return ret;
+}
+
 SANITIZER_INTERFACE_ATTRIBUTE char *
 __dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
   size_t len = strlen(s);
diff --git a/lib/dfsan/done_abilist.txt b/lib/dfsan/done_abilist.txt
index 1ceabf1..c6297aa 100644
--- a/lib/dfsan/done_abilist.txt
+++ b/lib/dfsan/done_abilist.txt
@@ -224,6 +224,7 @@
 fun:strtoll=custom
 fun:strtoul=custom
 fun:strtoull=custom
+fun:strcat=custom
 
 # Functions that produce an output that is computed from the input, but is not
 # necessarily data dependent.
diff --git a/test/dfsan/custom.cpp b/test/dfsan/custom.cpp
index 9129eff..4676c91 100644
--- a/test/dfsan/custom.cpp
+++ b/test/dfsan/custom.cpp
@@ -155,6 +155,27 @@
 #endif
 }
 
+void test_strcat() {
+  char src[] = "world";
+  char dst[] = "hello \0    ";
+  char *p = dst;
+  dfsan_set_label(k_label, &p, sizeof(p));
+  dfsan_set_label(i_label, src, sizeof(src));
+  dfsan_set_label(j_label, dst, sizeof(dst));
+  char *ret = strcat(p, src);
+  ASSERT_LABEL(ret, k_label);
+  assert(ret == dst);
+  assert(strcmp(src, dst + 6) == 0);
+  for (int i = 0; i < 6; ++i) {
+    ASSERT_LABEL(dst[i], j_label);
+  }
+  for (int i = 6; i < strlen(dst); ++i) {
+    ASSERT_LABEL(dst[i], i_label);
+    assert(dfsan_get_label(dst[i]) == dfsan_get_label(src[i - 6]));
+  }
+  ASSERT_LABEL(dst[11], j_label);
+}
+
 void test_strlen() {
   char str1[] = "str1";
   dfsan_set_label(i_label, &str1[3], 1);
@@ -1360,6 +1381,7 @@
   test_strcasecmp();
   test_strchr();
   test_strcmp();
+  test_strcat();
   test_strcpy();
   test_strdup();
   test_strlen();