-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[TySan] Add initial user facing interfaces #169023
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
gbMattN
wants to merge
4
commits into
llvm:main
Choose a base branch
from
gbMattN:tysan-interfaces
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Member
|
@llvm/pr-subscribers-compiler-rt-sanitizer Author: Matthew Nagy (gbMattN) ChangesFull diff: https://github.com/llvm/llvm-project/pull/169023.diff 11 Files Affected:
diff --git a/compiler-rt/include/CMakeLists.txt b/compiler-rt/include/CMakeLists.txt
index 242d62b9b447b..8443e309d1e95 100644
--- a/compiler-rt/include/CMakeLists.txt
+++ b/compiler-rt/include/CMakeLists.txt
@@ -14,6 +14,7 @@ if (COMPILER_RT_BUILD_SANITIZERS)
sanitizer/scudo_interface.h
sanitizer/tsan_interface.h
sanitizer/tsan_interface_atomic.h
+ sanitizer/tysan_interface.h
sanitizer/ubsan_interface.h
)
set(FUZZER_HEADERS
diff --git a/compiler-rt/include/sanitizer/tysan_interface.h b/compiler-rt/include/sanitizer/tysan_interface.h
new file mode 100644
index 0000000000000..8cb35ae4b5c09
--- /dev/null
+++ b/compiler-rt/include/sanitizer/tysan_interface.h
@@ -0,0 +1,42 @@
+//===-- tsan_interface.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of TypeSanitizer.
+//
+// Public interface header for TySan.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_TYSAN_INTERFACE_H
+#define SANITIZER_TYSAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Copies the shadow memory for the source user memory into the shadow memory for the destination user memory
+void SANITIZER_CDECL __tysan_copy_shadow(const void *dst, const void *src, size_t type_size);
+
+// Copies the shadow memory for the source user memory into the shadow memory for each element in the
+// destination array in user memory
+void SANITIZER_CDECL __tysan_copy_shadow_array(const void *dst_array, const void *src, size_t type_size, size_t arraySize);
+
+// Clears the shadow memory for the given range of user memory.
+void SANITIZER_CDECL __tysan_reset_shadow(const void *addr, size_t size);
+
+// Writes the name of the type represented in the shadow memory for the given location in user memory
+// into the given buffer, up to the given size.
+// Returns the length written.
+int SANITIZER_CDECL __tysan_get_type_name(const void *addr, char *buffer, size_t buffer_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cpp
index 111e55ef36bfb..917ba847ad478 100644
--- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cpp
+++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_common_test.cpp
@@ -21,6 +21,7 @@
#include "../../../include/sanitizer/asan_interface.h"
#include "../../../include/sanitizer/msan_interface.h"
#include "../../../include/sanitizer/tsan_interface.h"
+#include "../../../include/sanitizer/tysan_interface.h"
#include "gtest/gtest.h"
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_common.h"
diff --git a/compiler-rt/lib/tysan/CMakeLists.txt b/compiler-rt/lib/tysan/CMakeLists.txt
index 7d13ae3963919..a878a46322bd2 100644
--- a/compiler-rt/lib/tysan/CMakeLists.txt
+++ b/compiler-rt/lib/tysan/CMakeLists.txt
@@ -4,11 +4,13 @@ include_directories(..)
set(TYSAN_SOURCES
tysan.cpp
tysan_interceptors.cpp
+ tysan_interface.cpp
)
SET(TYSAN_HEADERS
tysan.h
tysan_flags.inc
+ tysan_interface.h
tysan_platform.h
)
diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp
index 1c67adeba0fc5..fdffe784d0c74 100644
--- a/compiler-rt/lib/tysan/tysan.cpp
+++ b/compiler-rt/lib/tysan/tysan.cpp
@@ -56,29 +56,41 @@ static const char *getDisplayName(const char *Name) {
return DName;
}
-static void printTDName(tysan_type_descriptor *td) {
- if (((sptr)td) <= 0) {
- Printf("<unknown type>");
- return;
+int getTDName(void *_td, char *buffer, uptr buffer_size, bool asset_on_error){
+ tysan_type_descriptor* td = (tysan_type_descriptor*)_td;
+ if(((sptr)td) <= 0){
+ return internal_snprintf(buffer, buffer_size, "<unknown type>");
}
+ uptr written = 0;
switch (td->Tag) {
default:
- CHECK(false && "invalid enum value");
+ if (asset_on_error)
+ CHECK(false && "invalid enum value");
+ else
+ written = internal_snprintf(buffer, buffer_size, "<invalid shadow>");
break;
case TYSAN_MEMBER_TD:
- printTDName(td->Member.Access);
- if (td->Member.Access != td->Member.Base) {
- Printf(" (in ");
- printTDName(td->Member.Base);
- Printf(" at offset %zu)", td->Member.Offset);
+ written = getTDName(td->Member.Access, buffer, buffer_size, false);
+ if (td->Member.Access != td->Member.Base && written != buffer_size) {
+ written += internal_snprintf(&buffer[written], buffer_size - written, " (in ");
+ written += getTDName(td->Member.Base, &buffer[written], buffer_size - written, false);
+ written += internal_snprintf(&buffer[written], buffer_size - written, " at offset %zu)", td->Member.Offset);
}
break;
case TYSAN_STRUCT_TD:
- Printf("%s", getDisplayName(
- (char *)(td->Struct.Members + td->Struct.MemberCount)));
+ written = internal_snprintf(buffer, buffer_size, "%s",
+ getDisplayName((char *)(td->Struct.Members + td->Struct.MemberCount)));
break;
}
+ return written;
+}
+
+static void printTDName(tysan_type_descriptor *td) {
+ static const uptr nameBufferSize = 512;
+ static char nameBuffer[nameBufferSize];
+ getTDName(td, nameBuffer, nameBufferSize, true);
+ Printf("%s", nameBuffer);
}
static tysan_type_descriptor *getRootTD(tysan_type_descriptor *TD) {
diff --git a/compiler-rt/lib/tysan/tysan.h b/compiler-rt/lib/tysan/tysan.h
index 97df28037b0d2..b7b1306cf10bd 100644
--- a/compiler-rt/lib/tysan/tysan.h
+++ b/compiler-rt/lib/tysan/tysan.h
@@ -20,11 +20,13 @@ using __sanitizer::sptr;
using __sanitizer::u16;
using __sanitizer::uptr;
+#include "tysan_interface.h"
#include "tysan_platform.h"
extern "C" {
void tysan_set_type_unknown(const void *addr, uptr size);
void tysan_copy_types(const void *daddr, const void *saddr, uptr size);
+int getTDName(void *td, char *buffer, uptr buffer_size, bool assert_on_error);
}
namespace __tysan {
diff --git a/compiler-rt/lib/tysan/tysan_interface.cpp b/compiler-rt/lib/tysan/tysan_interface.cpp
new file mode 100644
index 0000000000000..c2da6246b0044
--- /dev/null
+++ b/compiler-rt/lib/tysan/tysan_interface.cpp
@@ -0,0 +1,34 @@
+//===-- tysan_interface.inc --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of TypeSanitizer.
+//
+//===----------------------------------------------------------------------===//
+#include "tysan.h"
+#include "tysan_interface.h"
+
+void __tysan_copy_shadow(const void *dst, const void *src, size_t type_size){
+ tysan_copy_types(dst, src, type_size);
+}
+
+void __tysan_copy_shadow_array(const void *dst_array, const void *src, size_t type_size, size_t arraySize){
+ const void* dst = dst_array;
+ for(size_t i = 0; i < arraySize; i++){
+ tysan_copy_types(dst, src, type_size);
+ dst = (void*)(((uptr)dst) + type_size);
+ }
+}
+
+void __tysan_reset_shadow(const void *addr, size_t size){
+ tysan_set_type_unknown(addr, size);
+}
+
+int __tysan_get_type_name(const void *addr, char *buffer, size_t buffer_size){
+ void** shadow = (void**)__tysan::shadow_for(addr);
+ return getTDName(*shadow, buffer, buffer_size, false);
+}
diff --git a/compiler-rt/lib/tysan/tysan_interface.h b/compiler-rt/lib/tysan/tysan_interface.h
new file mode 100644
index 0000000000000..5a5e5cc08d2b3
--- /dev/null
+++ b/compiler-rt/lib/tysan/tysan_interface.h
@@ -0,0 +1,42 @@
+//===-- tysan_interface.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of TypeSanitizer.
+//
+// The functions declared in this header will be inserted by the instrumentation
+// module.
+// This header can be included by the instrumented program or by TySan tests.
+//===----------------------------------------------------------------------===//
+
+#ifndef TYSAN_INTERFACE_H
+#define TYSAN_INTERFACE_H
+
+#include <sanitizer_common/sanitizer_internal_defs.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tysan_copy_shadow(const void *dst, const void *src, size_t type_size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tysan_copy_shadow_array(const void *dst_array, const void *src, size_t type_size, size_t arraySize);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tysan_reset_shadow(const void *addr, size_t size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tysan_get_type_name(const void *addr, char *buffer, size_t buffer_size);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/compiler-rt/test/tysan/interface-manipulate-shadow.c b/compiler-rt/test/tysan/interface-manipulate-shadow.c
new file mode 100644
index 0000000000000..504de2876cf26
--- /dev/null
+++ b/compiler-rt/test/tysan/interface-manipulate-shadow.c
@@ -0,0 +1,99 @@
+// REQUIRES: system-linux || system-darwin
+// RUN: %clang_tysan %s -g -shared -fpic -o %t.so -DBUILD_SO
+// RUN: %clang_tysan %s -g -o %t
+// RUN: %run %t %t.so 2>&1 | FileCheck %s
+
+// Compilers can't optimize using type aliasing across the bounds of dynamic librarys
+// When passing memory between instrumented executables and dlls, you may want to alter TySan's
+// shadow to prevent it from catching technically correct, yet harmless aliasing violations
+
+#ifdef BUILD_SO
+float useFloatArray(float* mem){
+ mem[0] = 2.f;
+ mem[1] = 3.f;
+ return mem[0] + mem[1];
+}
+
+int useIntArray(int* mem){
+ mem[0] = 2;
+ mem[1] = 3;
+ mem[2] = 5;
+ return mem[0] + mem[1] + mem[2];
+}
+#else
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <sanitizer/tysan_interface.h>
+#include <stdio.h>
+
+typedef float(*lib_func1_t)(float*);
+typedef int(*lib_func2_t)(int*);
+
+void print_flush(const char* message){
+ printf("%s\n", message);
+ fflush(stdout);
+}
+
+int main(int argc, char* argv[]){
+ assert(argc >=2);
+ void *libHandle = dlopen(argv[1], RTLD_LAZY);
+ assert(libHandle);
+
+ lib_func1_t useFloatArray = (lib_func1_t)dlsym(libHandle, "useFloatArray");
+ lib_func2_t useIntArray = (lib_func2_t)dlsym(libHandle, "useIntArray");
+
+ char memory[sizeof(int) * 3];
+ int iResult = 0;
+ float fResult = 0.f;
+ print_flush("Calling with omnipotent char memory");
+ fResult = useFloatArray((float*)memory);
+ print_flush("Shadow now has floats in");
+ iResult = useIntArray((int*)memory);
+
+// CHECK: Calling with omnipotent char memory
+// CHECK-NEXT: Shadow now has floats in
+// CHECK-NEXT: ERROR: TypeSanitizer: type-aliasing-violation on address
+// CHECK-NEXT: WRITE of size 4 at 0x{{.*}} with type int accesses an existing object of type float
+
+ __tysan_reset_shadow(memory, sizeof(memory));
+ print_flush("Shadow has been reset");
+ useIntArray((int*)memory);
+ print_flush("Completed int array");
+
+// CHECK: Shadow has been reset
+// CHECK-NEXT: Completed int array
+
+ // Set shadow type to float
+ __tysan_copy_shadow_array(memory, &fResult, sizeof(float), 3);
+ print_flush("Float array with float set shadow");
+ useFloatArray((float*)memory);
+ print_flush("Int array with float set shadow");
+ useIntArray((int*)memory);
+
+// CHECK: Float array with float set shadow
+// CHECK-NEXT: Int array with float set shadow
+// CHECK-NEXT: ERROR: TypeSanitizer: type-aliasing-violation on address
+// CHECK-NEXT: WRITE of size 4 at 0x{{.*}} with type int accesses an existing object of type float
+
+ // Set shadow type to int
+ for(size_t i = 0; i < 3; i++){
+ __tysan_copy_shadow(&memory[sizeof(int) * i], &iResult, sizeof(int));
+ }
+ print_flush("Float array with int set shadow");
+ useFloatArray((float*)memory);
+ print_flush("Int array with int set shadow");
+ useIntArray((int*)memory);
+ print_flush("Completed int array");
+
+// CHECK: Float array with int set shadow
+// CHECK-NEXT: ERROR: TypeSanitizer: type-aliasing-violation on address
+// CHECK-NEXT: WRITE of size 4 at 0x{{.*}} with type float accesses an existing object of type int
+// CHECK: Int array with int set shadow
+// CHECK-NEXT: Completed int array
+
+ dlclose(libHandle);
+ return 0;
+}
+
+#endif
diff --git a/compiler-rt/test/tysan/interface-print-type.c b/compiler-rt/test/tysan/interface-print-type.c
new file mode 100644
index 0000000000000..c61a7dc477353
--- /dev/null
+++ b/compiler-rt/test/tysan/interface-print-type.c
@@ -0,0 +1,33 @@
+// RUN: %clang_tysan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/tysan_interface.h>
+#include <stdio.h>
+
+struct S{
+ int i;
+ float f;
+};
+
+void printInt(int* i){
+ const int bufferSize = 512;
+ static char nameBuffer[bufferSize];
+ __tysan_get_type_name(i, nameBuffer, 512);
+ printf("%d, %s\n", *i, nameBuffer);
+ fflush(stdout);
+}
+
+int main(){
+ struct S s;
+ s.i = 4;
+ printInt((int*)&s);
+// CHECK: 4, int (in S at offset 0)
+
+ s.f = 5.0f;
+// CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+// CHECK: READ of size 4 at 0x{{.*}} with type int accesses an existing object of type float (in S at offset 4)
+// CHECK: {{.*}}, float (in S at offset 4)
+ printInt((int*)&s.f);
+
+ return 0;
+}
diff --git a/llvm/utils/gn/secondary/compiler-rt/include/BUILD.gn b/llvm/utils/gn/secondary/compiler-rt/include/BUILD.gn
index 273fd7172da62..8e8ce837ef21e 100644
--- a/llvm/utils/gn/secondary/compiler-rt/include/BUILD.gn
+++ b/llvm/utils/gn/secondary/compiler-rt/include/BUILD.gn
@@ -22,6 +22,7 @@ copy("include") {
"sanitizer/scudo_interface.h",
"sanitizer/tsan_interface.h",
"sanitizer/tsan_interface_atomic.h",
+ sanitizer/tysan_interface.h
"sanitizer/ubsan_interface.h",
]
outputs = [ "$clang_resource_dir/include/{{source_target_relative}}" ]
|
🐧 Linux x64 Test Results
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Users may sometimes have a use case which the sanitizer does not explicitly support, or where they know extra information which they want to provide to the sanitizer for improved diagnostics. I've added some user facing interface functions which can be called from instrumented code that lets users do this.
There are
This is also the first step to fixing some problems set out in issue #169024