aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/analyzer/sm-fd.cc33
-rw-r--r--gcc/analyzer/sm-file.cc10
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/fread-pr108661.c40
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/read-pr108661.c33
4 files changed, 115 insertions, 1 deletions
diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc
index 494d802..d107390 100644
--- a/gcc/analyzer/sm-fd.cc
+++ b/gcc/analyzer/sm-fd.cc
@@ -2659,6 +2659,38 @@ private:
unsigned m_num_args;
};
+/* Handler for "read".
+ ssize_t read(int fildes, void *buf, size_t nbyte);
+ See e.g. https://man7.org/linux/man-pages/man2/read.2.html */
+
+class kf_read : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return (cd.num_args () == 3
+ && cd.arg_is_pointer_p (1)
+ && cd.arg_is_size_p (2));
+ }
+
+ /* For now, assume that any call to "read" fully clobbers the buffer
+ passed in. This isn't quite correct (e.g. errors, partial reads;
+ see PR analyzer/108689), but at least stops us falsely complaining
+ about the buffer being uninitialized. */
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model *model = cd.get_model ();
+ const svalue *ptr_sval = cd.get_arg_svalue (1);
+ if (const region *reg = ptr_sval->maybe_get_region ())
+ {
+ const region *base_reg = reg->get_base_region ();
+ const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg);
+ model->set_value (base_reg, new_sval, cd.get_ctxt ());
+ }
+ }
+};
+
+
/* Populate KFM with instances of known functions relating to
file descriptors. */
@@ -2672,6 +2704,7 @@ register_known_fd_functions (known_function_manager &kfm)
kfm.add ("listen", make_unique<kf_listen> ());
kfm.add ("pipe", make_unique<kf_pipe> (1));
kfm.add ("pipe2", make_unique<kf_pipe> (2));
+ kfm.add ("read", make_unique<kf_read> ());
kfm.add ("socket", make_unique<kf_socket> ());
}
diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc
index 9cb4e32..d99a09b 100644
--- a/gcc/analyzer/sm-file.cc
+++ b/gcc/analyzer/sm-file.cc
@@ -560,7 +560,11 @@ public:
}
};
-/* Handler for "fread"". */
+/* Handler for "fread".
+ size_t fread(void *restrict buffer, size_t size, size_t count,
+ FILE *restrict stream);
+ See e.g. https://en.cppreference.com/w/c/io/fread
+ and https://www.man7.org/linux/man-pages/man3/fread.3.html */
class kf_fread : public known_function
{
@@ -574,6 +578,10 @@ public:
&& cd.arg_is_pointer_p (3));
}
+ /* For now, assume that any call to "fread" fully clobbers the buffer
+ passed in. This isn't quite correct (e.g. errors, partial reads;
+ see PR analyzer/108689), but at least stops us falsely complaining
+ about the buffer being uninitialized. */
void impl_call_pre (const call_details &cd) const final override
{
region_model *model = cd.get_model ();
diff --git a/gcc/testsuite/gcc.dg/analyzer/fread-pr108661.c b/gcc/testsuite/gcc.dg/analyzer/fread-pr108661.c
new file mode 100644
index 0000000..b51cf41
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/fread-pr108661.c
@@ -0,0 +1,40 @@
+typedef __SIZE_TYPE__ size_t;
+
+extern size_t fread (void *, size_t, size_t, void *);
+
+struct ring
+{
+ char buf[1024];
+};
+
+int
+test_one_large_item (void *fp)
+{
+ struct ring ring;
+ int ret;
+
+ ret = fread(&ring, sizeof(ring), 1, fp);
+
+ if (ret != 1)
+ return 1;
+
+ if (ring.buf[0] > 1) /* { dg-bogus "use of uninitialized value" } */
+ return 2;
+ return 3;
+}
+
+int
+test_many_small_items (void *fp)
+{
+ struct ring ring;
+ int ret;
+
+ ret = fread(&ring, 1, sizeof(ring), fp);
+
+ if (ret != sizeof(ring))
+ return 1;
+
+ if (ring.buf[0] > 1) /* { dg-bogus "use of uninitialized value" } */
+ return 2;
+ return 3;
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/read-pr108661.c b/gcc/testsuite/gcc.dg/analyzer/read-pr108661.c
new file mode 100644
index 0000000..70335e6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/read-pr108661.c
@@ -0,0 +1,33 @@
+typedef long int ssize_t;
+typedef long unsigned int size_t;
+
+extern int open(const char* __file, int __oflag, ...) __attribute__((__nonnull__(1)));
+extern int close(int __fd);
+extern ssize_t read(int __fd, void* __buf, size_t __nbytes);
+
+struct ring
+{
+ char buf[1024];
+};
+
+int
+test(const char* name)
+{
+ struct ring ring;
+ int fd;
+ int ret;
+
+ fd = open(name, 00);
+ if (fd < 0)
+ return 0;
+
+ ret = read(fd, &ring, sizeof(ring));
+ close(fd);
+
+ if (ret != sizeof(ring))
+ return 1;
+
+ if (ring.buf[0] > 1) /* { dg-bogus "use of uninitialized value" } */
+ return 2;
+ return 3;
+}