about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
authorRamon de C Valle <rcvalle@users.noreply.github.com>2024-02-01 13:16:30 -0800
committerRamon de C Valle <rcvalle@users.noreply.github.com>2024-03-01 18:50:40 -0800
commitdee4e02102197adc29be9bf98083297dd3f5e2ed (patch)
tree510d1bc6652086782ea25e69a0a0b2a985f623aa /tests
parenteaee1e9453bfb4e1fb3753aa37450bb47cd7629d (diff)
downloadrust-dee4e02102197adc29be9bf98083297dd3f5e2ed.tar.gz
rust-dee4e02102197adc29be9bf98083297dd3f5e2ed.zip
Add initial support for DataFlowSanitizer
Adds initial support for DataFlowSanitizer to the Rust compiler. It
currently supports `-Zsanitizer-dataflow-abilist`. Additional options
for it can be passed to LLVM command line argument processor via LLVM
arguments using `llvm-args` codegen option (e.g.,
`-Cllvm-args=-dfsan-combine-pointer-labels-on-load=false`).
Diffstat (limited to 'tests')
-rw-r--r--tests/codegen/sanitizer/dataflow-instrument-functions.rs10
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr2
-rw-r--r--tests/ui/sanitizer/dataflow-abilist.txt505
-rw-r--r--tests/ui/sanitizer/dataflow.rs60
4 files changed, 576 insertions, 1 deletions
diff --git a/tests/codegen/sanitizer/dataflow-instrument-functions.rs b/tests/codegen/sanitizer/dataflow-instrument-functions.rs
new file mode 100644
index 00000000000..69c3560882c
--- /dev/null
+++ b/tests/codegen/sanitizer/dataflow-instrument-functions.rs
@@ -0,0 +1,10 @@
+// Verifies that functions are instrumented.
+//
+//@ needs-sanitizer-dataflow
+//@ compile-flags: -Copt-level=0 -Zsanitizer=dataflow
+
+#![crate_type="lib"]
+
+pub fn foo() {
+}
+// CHECK: define{{.*}}foo{{.*}}.dfsan
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 5dda4931d54..01fc3f83f16 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -100,7 +100,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     sanitize = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `sanitize` are: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`
+   = note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/sanitizer/dataflow-abilist.txt b/tests/ui/sanitizer/dataflow-abilist.txt
new file mode 100644
index 00000000000..fe04838f549
--- /dev/null
+++ b/tests/ui/sanitizer/dataflow-abilist.txt
@@ -0,0 +1,505 @@
+fun:main=uninstrumented
+fun:main=discard
+
+###############################################################################
+# DFSan interface functions
+###############################################################################
+fun:dfsan_union=uninstrumented
+fun:dfsan_union=discard
+fun:dfsan_create_label=uninstrumented
+fun:dfsan_create_label=discard
+fun:dfsan_set_label=uninstrumented
+fun:dfsan_set_label=discard
+fun:dfsan_add_label=uninstrumented
+fun:dfsan_add_label=discard
+fun:dfsan_get_label=uninstrumented
+fun:dfsan_get_label=custom
+fun:dfsan_read_label=uninstrumented
+fun:dfsan_read_label=discard
+fun:dfsan_get_label_count=uninstrumented
+fun:dfsan_get_label_count=discard
+fun:dfsan_get_label_info=uninstrumented
+fun:dfsan_get_label_info=discard
+fun:dfsan_has_label=uninstrumented
+fun:dfsan_has_label=discard
+fun:dfsan_has_label_with_desc=uninstrumented
+fun:dfsan_has_label_with_desc=discard
+fun:dfsan_set_write_callback=uninstrumented
+fun:dfsan_set_write_callback=custom
+fun:dfsan_flush=uninstrumented
+fun:dfsan_flush=discard
+fun:dfsan_print_origin_trace=uninstrumented
+fun:dfsan_print_origin_trace=discard
+fun:dfsan_print_origin_id_trace=uninstrumented
+fun:dfsan_print_origin_id_trace=discard
+fun:dfsan_sprint_origin_trace=uninstrumented
+fun:dfsan_sprint_origin_trace=discard
+fun:dfsan_sprint_origin_id_trace=uninstrumented
+fun:dfsan_sprint_origin_id_trace=discard
+fun:dfsan_sprint_stack_trace=uninstrumented
+fun:dfsan_sprint_stack_trace=discard
+fun:dfsan_get_origin=uninstrumented
+fun:dfsan_get_origin=custom
+fun:dfsan_read_origin_of_first_taint=uninstrumented
+fun:dfsan_read_origin_of_first_taint=discard
+fun:dfsan_get_init_origin=uninstrumented
+fun:dfsan_get_init_origin=discard
+fun:dfsan_get_track_origins=uninstrumented
+fun:dfsan_get_track_origins=discard
+fun:dfsan_set_conditional_callback=uninstrumented
+fun:dfsan_set_conditional_callback=discard
+fun:dfsan_get_labels_in_signal_conditional=uninstrumented
+fun:dfsan_get_labels_in_signal_conditional=discard
+fun:dfsan_set_reaches_function_callback=uninstrumented
+fun:dfsan_set_reaches_function_callback=discard
+fun:dfsan_get_labels_in_signal_reaches_function=uninstrumented
+fun:dfsan_get_labels_in_signal_reaches_function=discard
+fun:dfsan_reaches_function_callback=uninstrumented
+fun:dfsan_reaches_function_callback=discard
+
+###############################################################################
+# glibc
+###############################################################################
+# Functions of memory allocators
+fun:__libc_memalign=discard
+fun:aligned_alloc=discard
+fun:calloc=discard
+fun:cfree=discard
+fun:mallinfo=discard
+fun:malloc=discard
+fun:free=discard
+fun:malloc_stats=discard
+fun:malloc_usable_size=discard
+fun:mallopt=discard
+fun:memalign=discard
+fun:posix_memalign=discard
+fun:pvalloc=discard
+fun:realloc=discard
+fun:reallocarray=discard
+fun:valloc=discard
+
+# Functions that return a value that depends on the input, but the output might
+# not be necessarily data-dependent on the input.
+fun:isalpha=functional
+fun:isdigit=functional
+fun:isprint=functional
+fun:isxdigit=functional
+fun:isalnum=functional
+fun:ispunct=functional
+fun:isspace=functional
+fun:tolower=functional
+fun:_tolower=functional
+fun:toupper=functional
+
+# Functions that return a value that is data-dependent on the input.
+fun:__isinf=functional
+fun:__isinff=functional
+fun:__signbit=functional
+fun:__signbitf=functional
+fun:__signbitl=functional
+fun:btowc=functional
+fun:exp=functional
+fun:exp2=functional
+fun:expf=functional
+fun:expl=functional
+fun:fabs=functional
+fun:finite=functional
+fun:finitef=functional
+fun:finitel=functional
+fun:floor=functional
+fun:fmod=functional
+fun:isinf=functional
+fun:isinff=functional
+fun:isinfl=functional
+fun:isnan=functional
+fun:isnanf=functional
+fun:isnanl=functional
+fun:log=functional
+fun:log1p=functional
+fun:log1pf=functional
+fun:log1pl=functional
+fun:log2=functional
+fun:log2f=functional
+fun:log2l=functional
+fun:modf=functional
+fun:nextafter=functional
+fun:nextafterf=functional
+fun:nextafterl=functional
+fun:nexttoward=functional
+fun:nexttowardf=functional
+fun:nexttowardl=functional
+fun:pow=functional
+fun:powf=functional
+fun:powl=functional
+fun:round=functional
+fun:sqrt=functional
+fun:sqrtf=functional
+fun:sqrtl=functional
+fun:wctob=functional
+
+# Functions that produce an output that does not depend on the input (shadow is
+# zeroed automatically).
+fun:__assert_fail=discard
+fun:__cmsg_nxthdr=discard
+fun:__ctype_b_loc=discard
+fun:__cxa_atexit=discard
+fun:__errno_location=discard
+fun:__newlocale=discard
+fun:__sbrk=discard
+fun:__sigsetjmp=discard
+fun:__uselocale=discard
+fun:__wctype_l=discard
+fun:access=discard
+fun:alarm=discard
+fun:atexit=discard
+fun:bind=discard
+fun:chdir=discard
+fun:close=discard
+fun:closedir=discard
+fun:connect=discard
+fun:creat=discard
+fun:dladdr=discard
+fun:dlclose=discard
+fun:epoll_create=discard
+fun:epoll_create1=discard
+fun:epoll_ctl=discard
+fun:fclose=discard
+fun:feof=discard
+fun:ferror=discard
+fun:fflush=discard
+fun:fileno=discard
+fun:fopen=discard
+fun:fprintf=discard
+fun:fputc=discard
+fun:fputc=discard
+fun:fputs=discard
+fun:fputs=discard
+fun:fseek=discard
+fun:ftell=discard
+fun:fwrite=discard
+fun:getenv=discard
+fun:getuid=discard
+fun:geteuid=discard
+fun:getpagesize=discard
+fun:getpid=discard
+fun:kill=discard
+fun:listen=discard
+fun:lseek=discard
+fun:mkdir=discard
+fun:mmap=discard
+fun:munmap=discard
+fun:open=discard
+fun:openat=discard
+fun:pipe=discard
+fun:posix_fadvise=discard
+fun:prctl=discard
+fun:printf=discard
+fun:pthread_sigmask=discard
+fun:putc=discard
+fun:putchar=discard
+fun:puts=discard
+fun:rand=discard
+fun:random=discard
+fun:remove=discard
+fun:sched_getcpu=discard
+fun:sched_get_priority_max=discard
+fun:sched_setaffinity=discard
+fun:sched_yield=discard
+fun:sem_destroy=discard
+fun:sem_init=discard
+fun:sem_post=discard
+fun:sem_wait=discard
+fun:send=discard
+fun:sendmsg=discard
+fun:sendto=discard
+fun:setsockopt=discard
+fun:shutdown=discard
+fun:sleep=discard
+fun:socket=discard
+fun:strerror=discard
+fun:strspn=discard
+fun:strcspn=discard
+fun:symlink=discard
+fun:syscall=discard
+fun:unlink=discard
+fun:uselocale=discard
+fun:vfprintf=discard
+
+# Functions that produce output does not depend on the input (need to zero the
+# shadow manually).
+fun:_dl_get_tls_static_info=custom
+fun:clock_gettime=custom
+fun:dlopen=custom
+fun:epoll_wait=custom
+fun:fgets=custom
+fun:fstat=custom
+fun:getcwd=custom
+fun:get_current_dir_name=custom
+fun:getentropy=custom
+fun:gethostname=custom
+fun:getpeername=custom
+fun:getrlimit=custom
+fun:getrusage=custom
+fun:getsockname=custom
+fun:getsockopt=custom
+fun:nanosleep=custom
+fun:pread=custom
+fun:read=custom
+fun:recvmmsg=custom
+fun:recvmsg=custom
+fun:sigaltstack=custom
+fun:socketpair=custom
+fun:stat=custom
+fun:time=custom
+
+# Functions that produce an output that depend on the input (propagate the
+# shadow manually).
+fun:ctime_r=custom
+fun:inet_pton=custom
+fun:localtime_r=custom
+fun:memcpy=custom
+fun:memmove=custom
+fun:memset=custom
+fun:strcpy=custom
+fun:strdup=custom
+fun:strncpy=custom
+fun:strtod=custom
+fun:strtol=custom
+fun:strtoll=custom
+fun:strtoul=custom
+fun:strtoull=custom
+fun:strcat=custom
+fun:strncat=custom
+fun:__isoc23_strtod=custom
+fun:__isoc23_strtol=custom
+fun:__isoc23_strtoll=custom
+fun:__isoc23_strtoul=custom
+fun:__isoc23_strtoull=custom
+
+# Functions that produce an output that is computed from the input, but is not
+# necessarily data dependent.
+fun:bcmp=custom
+fun:memchr=custom
+fun:memcmp=custom
+fun:strcasecmp=custom
+fun:strchr=custom
+fun:strcmp=custom
+fun:strlen=custom
+fun:strnlen=custom
+fun:strncasecmp=custom
+fun:strncmp=custom
+fun:strpbrk=custom
+fun:strrchr=custom
+fun:strstr=custom
+fun:strsep=custom
+
+# Functions which take action based on global state, such as running a callback
+# set by a separate function.
+fun:write=custom
+
+# Functions that take a callback (wrap the callback manually).
+fun:dl_iterate_phdr=custom
+
+fun:getpwuid_r=custom
+fun:poll=custom
+fun:sched_getaffinity=custom
+fun:select=custom
+fun:sigemptyset=custom
+fun:sigaction=custom
+fun:signal=custom
+fun:gettimeofday=custom
+
+# sprintf-like
+fun:sprintf=custom
+fun:snprintf=custom
+
+# scanf-like
+fun:sscanf=custom
+fun:__isoc99_sscanf=custom
+fun:__isoc23_sscanf=custom
+
+# TODO: custom
+fun:asprintf=discard
+fun:qsort=discard
+
+# fork
+fun:fork=custom
+
+###############################################################################
+# pthread
+###############################################################################
+fun:__pthread_register_cancel=discard
+fun:__pthread_unregister_cancel=discard
+fun:pthread_attr_destroy=discard
+fun:pthread_attr_getaffinity_np=discard
+fun:pthread_attr_getdetachstate=discard
+fun:pthread_attr_getguardsize=discard
+fun:pthread_attr_getinheritsched=discard
+fun:pthread_attr_getschedparam=discard
+fun:pthread_attr_getschedpolicy=discard
+fun:pthread_attr_getscope=discard
+fun:pthread_attr_getstack=discard
+fun:pthread_attr_getstackaddr=disacrd
+fun:pthread_attr_getstacksize=discard
+fun:pthread_attr_init=discard
+fun:pthread_attr_setaffinity_np=discard
+fun:pthread_attr_setdetachstate=discard
+fun:pthread_attr_setguardsize=discard
+fun:pthread_attr_setinheritsched=discard
+fun:pthread_attr_setschedparam=discard
+fun:pthread_attr_setschedpolicy=discard
+fun:pthread_attr_setscope=discard
+fun:pthread_attr_setstack=discard
+fun:pthread_attr_setstackaddr=discard
+fun:pthread_attr_setstacksize=discard
+fun:pthread_equal=discard
+fun:pthread_getschedparam=discard
+fun:pthread_getspecific=discard
+fun:pthread_key_create=discard
+fun:pthread_key_delete=discard
+fun:pthread_mutex_destroy=discard
+fun:pthread_mutex_init=discard
+fun:pthread_mutex_lock=discard
+fun:pthread_mutex_trylock=discard
+fun:pthread_mutex_unlock=discard
+fun:pthread_mutexattr_destroy=discard
+fun:pthread_mutexattr_init=discard
+fun:pthread_mutexattr_settype=discard
+fun:pthread_rwlock_destroy=discard
+fun:pthread_rwlock_init=discard
+fun:pthread_rwlock_rdlock=discard
+fun:pthread_rwlock_timedrdlock=discard
+fun:pthread_rwlock_timedwrlock=discard
+fun:pthread_rwlock_tryrdlock=discard
+fun:pthread_rwlock_trywrlock=discard
+fun:pthread_rwlock_wrlock=discard
+fun:pthread_rwlock_unlock=discard
+fun:pthread_setschedparam=discard
+fun:pthread_setname_np=discard
+fun:pthread_once=discard
+fun:pthread_self=discard
+fun:pthread_setspecific=discard
+
+# Functions that take a callback (wrap the callback manually).
+fun:pthread_create=custom
+
+# Functions that produce output does not depend on the input (need to zero the
+# shadow manually).
+fun:pthread_join=custom
+
+###############################################################################
+# libffi/libgo
+###############################################################################
+# Functions that are written in asm or are called from asm.
+fun:ffi_call_unix64=uninstrumented
+fun:ffi_call_unix64=discard
+fun:ffi_closure_unix64_inner=uninstrumented
+fun:ffi_closure_unix64_inner=discard
+fun:ffi_closure_unix64=uninstrumented
+fun:ffi_closure_unix64=discard
+fun:__go_get_closure=uninstrumented
+fun:__go_get_closure=discard
+fun:__go_makefunc_can_recover=uninstrumented
+fun:__go_makefunc_can_recover=discard
+fun:__go_makefunc_returning=uninstrumented
+fun:__go_makefunc_returning=discard
+fun:reflect.MakeFuncStubGo=uninstrumented
+fun:reflect.MakeFuncStubGo=discard
+fun:reflect.makeFuncStub=uninstrumented
+fun:reflect.makeFuncStub=discard
+
+
+###############################################################################
+# lib/Fuzzer
+###############################################################################
+# Replaces __sanitizer_cov_trace_cmp with __dfsw___sanitizer_cov_trace_cmp
+fun:__sanitizer_cov_trace_cmp1=custom
+fun:__sanitizer_cov_trace_cmp1=uninstrumented
+fun:__sanitizer_cov_trace_cmp2=custom
+fun:__sanitizer_cov_trace_cmp2=uninstrumented
+fun:__sanitizer_cov_trace_cmp4=custom
+fun:__sanitizer_cov_trace_cmp4=uninstrumented
+fun:__sanitizer_cov_trace_cmp8=custom
+fun:__sanitizer_cov_trace_cmp8=uninstrumented
+fun:__sanitizer_cov_trace_const_cmp1=custom
+fun:__sanitizer_cov_trace_const_cmp1=uninstrumented
+fun:__sanitizer_cov_trace_const_cmp2=custom
+fun:__sanitizer_cov_trace_const_cmp2=uninstrumented
+fun:__sanitizer_cov_trace_const_cmp4=custom
+fun:__sanitizer_cov_trace_const_cmp4=uninstrumented
+fun:__sanitizer_cov_trace_const_cmp8=custom
+fun:__sanitizer_cov_trace_const_cmp8=uninstrumented
+# Similar for __sanitizer_cov_trace_switch
+fun:__sanitizer_cov_trace_switch=custom
+fun:__sanitizer_cov_trace_switch=uninstrumented
+
+# Ignores all other __sanitizer callbacks.
+fun:__sanitizer_cov=uninstrumented
+fun:__sanitizer_cov=discard
+fun:__sanitizer_cov_module_init=uninstrumented
+fun:__sanitizer_cov_module_init=discard
+fun:__sanitizer_cov_with_check=uninstrumented
+fun:__sanitizer_cov_with_check=discard
+fun:__sanitizer_set_death_callback=uninstrumented
+fun:__sanitizer_set_death_callback=discard
+fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented
+fun:__sanitizer_update_counter_bitset_and_clear_counters=discard
+fun:__sanitizer_cov_trace_pc*=uninstrumented
+fun:__sanitizer_cov_trace_pc*=discard
+fun:__sanitizer_cov_pcs_init=uninstrumented
+fun:__sanitizer_cov_pcs_init=discard
+
+fun:__sanitizer_get_current_allocated_bytes=uninstrumented
+fun:__sanitizer_get_current_allocated_bytes=discard
+fun:__sanitizer_get_heap_size=uninstrumented
+fun:__sanitizer_get_heap_size=discard
+fun:__sanitizer_get_free_bytes=uninstrumented
+fun:__sanitizer_get_free_bytes=discard
+fun:__sanitizer_get_unmapped_bytes=uninstrumented
+fun:__sanitizer_get_unmapped_bytes=discard
+fun:__sanitizer_get_estimated_allocated_size=uninstrumented
+fun:__sanitizer_get_estimated_allocated_size=discard
+fun:__sanitizer_get_ownership=uninstrumented
+fun:__sanitizer_get_ownership=discard
+fun:__sanitizer_get_allocated_begin=uninstrumented
+fun:__sanitizer_get_allocated_begin=discard
+fun:__sanitizer_get_allocated_size=uninstrumented
+fun:__sanitizer_get_allocated_size=discard
+fun:__sanitizer_get_allocated_size_fast=uninstrumented
+fun:__sanitizer_get_allocated_size_fast=discard
+fun:__sanitizer_print_stack_trace=uninstrumented
+fun:__sanitizer_print_stack_trace=discard
+
+fun:TcmallocSlab_Internal_PushBatch_FixedShift=uninstrumented
+fun:TcmallocSlab_Internal_PushBatch_FixedShift=discard
+fun:TcmallocSlab_Internal_PushBatch_FixedShift_VCPU=uninstrumented
+fun:TcmallocSlab_Internal_PushBatch_FixedShift_VCPU=discard
+fun:TcmallocSlab_Internal_PerCpuCmpxchg64=uninstrumented
+fun:TcmallocSlab_Internal_PerCpuCmpxchg64=discard
+fun:TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU=uninstrumented
+fun:TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU=discard
+fun:TcmallocSlab_Internal_PopBatch_FixedShift=uninstrumented
+fun:TcmallocSlab_Internal_PopBatch_FixedShift=discard
+fun:TcmallocSlab_Internal_PopBatch_FixedShift_VCPU=uninstrumented
+fun:TcmallocSlab_Internal_PopBatch_FixedShift_VCPU=discard
+
+# Ignores the dfsan wrappers.
+fun:__dfsw_*=uninstrumented
+fun:__dfsw_*=discard
+fun:__dfso_*=uninstrumented
+fun:__dfso_*=discard
+
+# Rust functions.
+fun:__rdl_alloc=uninstrumented
+fun:__rdl_alloc_zeroed=uninstrumented
+fun:__rdl_dealloc=uninstrumented
+fun:__rdl_realloc=uninstrumented
+fun:__rg_oom=uninstrumented
+fun:__rust_alloc=uninstrumented
+fun:__rust_alloc_error_handler=uninstrumented
+fun:__rust_alloc_zeroed=uninstrumented
+fun:__rust_dealloc=uninstrumented
+fun:__rust_realloc=uninstrumented
+fun:_ZN4core*=uninstrumented
+fun:_ZN3std*=uninstrumented
+fun:rust_eh_personality=uninstrumented
diff --git a/tests/ui/sanitizer/dataflow.rs b/tests/ui/sanitizer/dataflow.rs
new file mode 100644
index 00000000000..658a9e48086
--- /dev/null
+++ b/tests/ui/sanitizer/dataflow.rs
@@ -0,0 +1,60 @@
+#![allow(non_camel_case_types)]
+// Verifies that labels are propagated through loads and stores.
+//
+//@ needs-sanitizer-support
+//@ needs-sanitizer-dataflow
+//@ run-pass
+//@ compile-flags: -Zsanitizer=dataflow -Zsanitizer-dataflow-abilist={{src-base}}/sanitizer/dataflow-abilist.txt
+
+use std::mem::size_of;
+use std::os::raw::{c_int, c_long, c_void};
+
+type dfsan_label = u8;
+
+extern "C" {
+    fn dfsan_add_label(label: dfsan_label, addr: *mut c_void, size: usize);
+    fn dfsan_get_label(data: c_long) -> dfsan_label;
+    fn dfsan_has_label(label: dfsan_label, elem: dfsan_label) -> c_int;
+    fn dfsan_read_label(addr: *const c_void, size: usize) -> dfsan_label;
+    fn dfsan_set_label(label: dfsan_label, addr: *mut c_void, size: usize);
+}
+
+fn propagate2(i: &i64) -> i64 {
+    i.clone()
+}
+
+fn propagate(i: i64) -> i64 {
+    let v = vec!(i, 1, 2, 3);
+    let j = v.iter().sum();
+    propagate2(&j)
+}
+
+pub fn main() {
+    let mut i = 1i64;
+    let i_ptr = &mut i as *mut i64;
+    let i_label: dfsan_label = 1;
+    unsafe {
+        dfsan_set_label(i_label, i_ptr as *mut c_void, size_of::<i64>());
+    }
+
+    let new_label = unsafe { dfsan_get_label(i) };
+    assert_eq!(i_label, new_label);
+
+    let read_label = unsafe { dfsan_read_label(i_ptr as *const c_void, size_of::<i64>()) };
+    assert_eq!(i_label, read_label);
+
+    let j_label: dfsan_label = 2;
+    unsafe {
+        dfsan_add_label(j_label, i_ptr as *mut c_void, size_of::<i64>());
+    }
+
+    let read_label = unsafe { dfsan_read_label(i_ptr as *const c_void, size_of::<i64>()) };
+    assert_eq!(unsafe { dfsan_has_label(read_label, i_label) }, 1);
+    assert_eq!(unsafe { dfsan_has_label(read_label, j_label) }, 1);
+
+    let mut new_i = propagate(i);
+    let new_i_ptr = &mut new_i as *mut i64;
+    let read_label = unsafe { dfsan_read_label(new_i_ptr as *const c_void, size_of::<i64>()) };
+    assert_eq!(unsafe { dfsan_has_label(read_label, i_label) }, 1);
+    assert_eq!(unsafe { dfsan_has_label(read_label, j_label) }, 1);
+}