ctxt->purge_state_involving (sval);
}
+/* Check CALL a call to external function CALLEE_FNDECL based on
+ any __attribute__ ((access, ....) on the latter, complaining to
+ CTXT about any issues.
+
+ Currently we merely call check_region_for_write on any regions
+ pointed to by arguments marked with a "write_only" or "read_write"
+ attribute. */
+
+void
+region_model::
+check_external_function_for_access_attr (const gcall *call,
+ tree callee_fndecl,
+ region_model_context *ctxt) const
+{
+ gcc_assert (call);
+ gcc_assert (callee_fndecl);
+ gcc_assert (ctxt);
+
+ tree fntype = TREE_TYPE (callee_fndecl);
+ if (!fntype)
+ return;
+
+ if (!TYPE_ATTRIBUTES (fntype))
+ return;
+
+ /* Initialize a map of attribute access specifications for arguments
+ to the function call. */
+ rdwr_map rdwr_idx;
+ init_attr_rdwr_indices (&rdwr_idx, TYPE_ATTRIBUTES (fntype));
+
+ unsigned argno = 0;
+
+ for (tree iter = TYPE_ARG_TYPES (fntype); iter;
+ iter = TREE_CHAIN (iter), ++argno)
+ {
+ const attr_access* access = rdwr_idx.get (argno);
+ if (!access)
+ continue;
+
+ /* Ignore any duplicate entry in the map for the size argument. */
+ if (access->ptrarg != argno)
+ continue;
+
+ if (access->mode == access_write_only
+ || access->mode == access_read_write)
+ {
+ tree ptr_tree = gimple_call_arg (call, access->ptrarg);
+ const svalue *ptr_sval = get_rvalue (ptr_tree, ctxt);
+ const region *reg = deref_rvalue (ptr_sval, ptr_tree, ctxt);
+ check_region_for_write (reg, ctxt);
+ /* We don't use the size arg for now. */
+ }
+ }
+}
+
/* Handle a call CALL to a function with unknown behavior.
Traverse the regions in this model, determining what regions are
{
tree fndecl = get_fndecl_for_call (call, ctxt);
+ if (fndecl && ctxt)
+ check_external_function_for_access_attr (call, fndecl, ctxt);
+
reachable_regions reachable_regs (this);
/* Determine the reachable regions and their mutability. */
region_model_context *ctxt) const;
void check_call_args (const call_details &cd) const;
+ void check_external_function_for_access_attr (const gcall *call,
+ tree callee_fndecl,
+ region_model_context *ctxt) const;
/* Storing this here to avoid passing it around everywhere. */
region_model_manager *const m_mgr;
--- /dev/null
+typedef __SIZE_TYPE__ size_t;
+
+void read_only (void *)
+ __attribute__ ((access (read_only, 1)));
+void write_only (void *)
+ __attribute__ ((access (write_only, 1)));
+void read_write (void *)
+ __attribute__ ((access (read_write, 1)));
+void none (void *)
+ __attribute__ ((access (none, 1)));
+void read_only_with_size (void *, size_t)
+ __attribute__ ((access (read_only, 1, 2)));
+void write_only_with_size (void *, size_t)
+ __attribute__ ((access (write_only, 1, 2)));
+void read_write_with_size (void *, size_t)
+ __attribute__ ((access (read_write, 1, 2)));
+void none_with_size (void *, size_t)
+ __attribute__ ((access (none, 1, 2)));
+
+const char buf[5] = { 0 }; /* { dg-message "declared here" } */
+
+void test_read_only (void)
+{
+ read_only ((char *)buf);
+}
+
+void test_write_only (void)
+{
+ write_only ((char *)buf); /* { dg-warning "write to 'const' object 'buf'" } */
+}
+
+void test_read_write (void)
+{
+ read_write ((char *)buf); /* { dg-warning "write to 'const' object 'buf'" } */
+}
+
+void test_none (void)
+{
+ none ((char *)buf);
+}
+
+void test_read_only_with_size (void)
+{
+ read_only_with_size ((char *)buf, sizeof (buf));
+}
+
+void test_write_only_with_size (void)
+{
+ write_only_with_size ((char *)buf, sizeof (buf)); /* { dg-warning "write to 'const' object 'buf'" } */
+}
+
+void test_read_write_with_size (void)
+{
+ read_write_with_size ((char *)buf, sizeof (buf)); /* { dg-warning "write to 'const' object 'buf'" } */
+}
+
+void test_none_with_size (void)
+{
+ none_with_size ((char *)buf, sizeof (buf));
+}
--- /dev/null
+typedef __SIZE_TYPE__ size_t;
+
+int getrandom (void *__buffer, size_t __length,
+ unsigned int __flags)
+ __attribute__ ((access (__write_only__, 1, 2)));
+
+#define GRND_RANDOM 0x02
+
+void test (void)
+{
+ char buf[16];
+
+ if (getrandom(test, 16, GRND_RANDOM)) /* { dg-warning "write to function 'test'" } */
+ __builtin_printf("%s\n", buf);
+}
--- /dev/null
+typedef __SIZE_TYPE__ size_t;
+
+int getrandom (void *__buffer, size_t __length,
+ unsigned int __flags)
+ __attribute__ ((access (__write_only__, 1, 2)));
+
+#define GRND_RANDOM 0x02
+
+const char *test = "test";
+
+int main(void)
+{
+ const char buf[5] = { 0 };
+
+ if (getrandom((char *)test, sizeof(buf), GRND_RANDOM)) /* { dg-warning "write to string literal" } */
+ __builtin_printf("%s\n", buf);
+
+ return 0;
+}
--- /dev/null
+typedef __SIZE_TYPE__ size_t;
+
+void read_only (void *)
+ __attribute__ ((access (read_only, 1)));
+void write_only (void *)
+ __attribute__ ((access (write_only, 1)));
+void read_write (void *)
+ __attribute__ ((access (read_write, 1)));
+void none (void *)
+ __attribute__ ((access (none, 1)));
+void read_only_with_size (void *, size_t)
+ __attribute__ ((access (read_only, 1, 2)));
+void write_only_with_size (void *, size_t)
+ __attribute__ ((access (write_only, 1, 2)));
+void read_write_with_size (void *, size_t)
+ __attribute__ ((access (read_write, 1, 2)));
+void none_with_size (void *, size_t)
+ __attribute__ ((access (none, 1, 2)));
+
+void test_read_only (void)
+{
+ const char *str = "hello world";
+ read_only ((char *)str);
+}
+
+void test_write_only (void)
+{
+ const char *str = "hello world";
+ write_only ((char *)str); /* { dg-warning "write to string literal" } */
+}
+
+void test_read_write (void)
+{
+ const char *str = "hello world";
+ read_write ((char *)str); /* { dg-warning "write to string literal" } */
+}
+
+void test_none (void)
+{
+ const char *str = "hello world";
+ none ((char *)str);
+}
+
+void test_read_only_with_size (void)
+{
+ const char *str = "hello world";
+ read_only_with_size ((char *)str, sizeof (str));
+}
+
+void test_write_only_with_size (void)
+{
+ const char *str = "hello world";
+ write_only_with_size ((char *)str, sizeof (str)); /* { dg-warning "write to string literal" } */
+}
+
+void test_read_write_with_size (void)
+{
+ const char *str = "hello world";
+ read_write_with_size ((char *)str, sizeof (str)); /* { dg-warning "write to string literal" } */
+}
+
+void test_none_with_size (void)
+{
+ const char *str = "hello world";
+ none_with_size ((char *)str, sizeof (str));
+}
--- /dev/null
+typedef __SIZE_TYPE__ size_t;
+
+int getrandom (void *__buffer, size_t __length,
+ unsigned int __flags)
+ __attribute__ ((access (__write_only__, 1, 2)));
+
+#define GRND_RANDOM 0x02
+
+void test (int flag)
+{
+ char *buf;
+
+ if (flag)
+ buf = __builtin_malloc (1024);
+ else
+ buf = (char *)""; /* { dg-message "here" } */
+
+ if (getrandom(buf, 16, GRND_RANDOM)) /* { dg-warning "write to string literal" } */
+ __builtin_printf("%s\n", buf);
+
+ if (flag)
+ __builtin_free (buf);
+}