/* Verify that -Wanalyzer-exposure-through-uninit-copy doesn't get confused if size argument to copy_to_user is an upper bound, rather than a constant. */ /* { dg-do compile } */ /* { dg-options "-fanalyzer" } */ /* { dg-require-effective-target analyzer } */ #include "../analyzer/analyzer-decls.h" typedef __SIZE_TYPE__ size_t; #include "test-uaccess.h" typedef unsigned __INT32_TYPE__ u32; /* min_t adapted from include/linux/kernel.h. */ #define min_t(type, x, y) ({ \ type __min1 = (x); \ type __min2 = (y); \ __min1 < __min2 ? __min1: __min2; }) struct st { u32 a; u32 b; }; /* Verify that we cope with min_t. */ void test_1_full_init (void __user *dst, u32 x, u32 y, unsigned long in_sz) { struct st s; s.a = x; s.b = y; unsigned long copy_sz = min_t(unsigned long, in_sz, sizeof(s)); copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */ } void test_1_partial_init (void __user *dst, u32 x, u32 y, unsigned long in_sz) { struct st s; s.a = x; /* s.y not initialized. */ unsigned long copy_sz = min_t(unsigned long, in_sz, sizeof(s)); copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" } */ } /* Constant on LHS rather than RHS. */ void test_2_full_init (void __user *dst, u32 x, u32 y, unsigned long in_sz) { struct st s; s.a = x; s.b = y; unsigned long copy_sz = min_t(unsigned long, sizeof(s), in_sz); copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */ } void test_2_partial_init (void __user *dst, u32 x, u32 y, unsigned long in_sz) { struct st s; s.a = x; /* s.y not initialized. */ unsigned long copy_sz = min_t(unsigned long, sizeof(s), in_sz); copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" } */ } /* min_t with various casts. */ void test_3_full_init (void __user *dst, u32 x, u32 y, int in_sz) { struct st s; s.a = x; s.b = y; int copy_sz = min_t(unsigned int, in_sz, sizeof(s)); copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */ } void test_3_partial_init (void __user *dst, u32 x, u32 y, int in_sz) { struct st s; s.a = x; /* s.y not initialized. */ int copy_sz = min_t(unsigned int, in_sz, sizeof(s)); copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" } */ } /* Comparison against an upper bound. */ void test_4_full_init (void __user *dst, u32 x, u32 y, size_t in_sz) { struct st s; s.a = x; s.b = y; size_t copy_sz = in_sz; if (copy_sz > sizeof(s)) copy_sz = sizeof(s); copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */ } void test_4_partial_init (void __user *dst, u32 x, u32 y, size_t in_sz) { struct st s; s.a = x; /* s.y not initialized. */ size_t copy_sz = in_sz; if (copy_sz > sizeof(s)) copy_sz = sizeof(s); copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" } */ } /* Comparison against an upper bound with casts. */ void test_5_full_init (void __user *dst, u32 x, u32 y, int in_sz) { struct st s; s.a = x; s.b = y; int copy_sz = in_sz; if (copy_sz > sizeof(s)) copy_sz = sizeof(s); copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */ } /* Comparison against an upper bound with casts. */ void test_5_partial_init (void __user *dst, u32 x, u32 y, int in_sz) { struct st s; s.a = x; /* s.y not initialized. */ int copy_sz = in_sz; if (copy_sz > sizeof(s)) copy_sz = sizeof(s); copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" "" } */ }