* [committed] analyzer: check for writes to consts via access attr [PR104793]
@ 2022-03-10 14:18 David Malcolm
0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2022-03-10 14:18 UTC (permalink / raw)
To: gcc-patches
This patch extends:
-Wanalyzer-write-to-const
-Wanalyzer-write-to-string-literal
so that they will check for __attribute__ ((access, ....) on calls to
externally-defined functions, and complain about read-only regions
pointed to by arguments marked with a "write_only" or "read_write"
attribute.
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r12-7595-gb6eaf90c64f915.
gcc/analyzer/ChangeLog:
PR analyzer/104793
* region-model.cc
(region_model::check_external_function_for_access_attr): New.
(region_model::handle_unrecognized_call): Call it.
* region-model.h
(region_model::check_external_function_for_access_attr): New decl.
(region_model::handle_unrecognized_call): New decl.
gcc/testsuite/ChangeLog:
PR analyzer/104793
* gcc.dg/analyzer/write-to-const-2.c: New test.
* gcc.dg/analyzer/write-to-function-1.c: New test.
* gcc.dg/analyzer/write-to-string-literal-2.c: New test.
* gcc.dg/analyzer/write-to-string-literal-3.c: New test.
* gcc.dg/analyzer/write-to-string-literal-4.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
---
gcc/analyzer/region-model.cc | 58 ++++++++++++++++
gcc/analyzer/region-model.h | 3 +
.../gcc.dg/analyzer/write-to-const-2.c | 60 +++++++++++++++++
.../gcc.dg/analyzer/write-to-function-1.c | 15 +++++
.../analyzer/write-to-string-literal-2.c | 19 ++++++
.../analyzer/write-to-string-literal-3.c | 66 +++++++++++++++++++
.../analyzer/write-to-string-literal-4.c | 23 +++++++
7 files changed, 244 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/analyzer/write-to-const-2.c
create mode 100644 gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c
create mode 100644 gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-2.c
create mode 100644 gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-3.c
create mode 100644 gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4.c
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 5cfa3543f17..5760ff70938 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1583,6 +1583,61 @@ region_model::purge_state_involving (const svalue *sval,
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
@@ -1598,6 +1653,9 @@ region_model::handle_unrecognized_call (const gcall *call,
{
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. */
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index aa489d06a38..788d0c22bca 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -846,6 +846,9 @@ class region_model
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;
diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-const-2.c b/gcc/testsuite/gcc.dg/analyzer/write-to-const-2.c
new file mode 100644
index 00000000000..d0f2f29e985
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/write-to-const-2.c
@@ -0,0 +1,60 @@
+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));
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c b/gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c
new file mode 100644
index 00000000000..38374ddf9e4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c
@@ -0,0 +1,15 @@
+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);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-2.c b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-2.c
new file mode 100644
index 00000000000..e5906cd5546
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-2.c
@@ -0,0 +1,19 @@
+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;
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-3.c b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-3.c
new file mode 100644
index 00000000000..7f4fb4f3aa0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-3.c
@@ -0,0 +1,66 @@
+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));
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4.c b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4.c
new file mode 100644
index 00000000000..3d3270ffdbb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4.c
@@ -0,0 +1,23 @@
+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);
+}
--
2.26.3
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-03-10 14:18 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-10 14:18 [committed] analyzer: check for writes to consts via access attr [PR104793] David Malcolm
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).