]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
analyzer: add known function handling for atoi, atol, and atoll
authorSaksham Gupta <io.sakshamgupta@gmail.com>
Mon, 9 Mar 2026 06:20:36 +0000 (11:50 +0530)
committerDavid Malcolm <dmalcolm@redhat.com>
Tue, 28 Apr 2026 23:11:25 +0000 (19:11 -0400)
This patch adds kf_atoi_family to handle atoi, atol, and atoll functions in the
analyzer, ensuring that the argument is checked for a valid,
null-terminated string.

gcc/analyzer/ChangeLog:
* kf.cc (class kf_atoi_family): New class.
(register_known_functions): Register atoi, atol, and atoll.

gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/atoi-1.c: Update test coverage.

Signed-off-by: Saksham Gupta <io.sakshamgupta@gmail.com>
gcc/analyzer/kf.cc
gcc/testsuite/gcc.dg/analyzer/atoi-1.c [new file with mode: 0644]

index b1ccbd6584aeb569071e1692ae312a01e28a0401..69ce37272ac4eff2e9770dfd8a4684f26587c047 100644 (file)
@@ -833,6 +833,25 @@ private:
   tree m_var_decl; // could be NULL
 };
 
+class kf_atoi_family: public known_function
+{
+public:
+  bool matches_call_types_p (const call_details &cd) const final override
+  {
+    return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
+  }
+
+  void impl_call_pre (const call_details &cd) const final override
+  {
+    /* atoi expects a valid, null-terminated string. */
+    cd.check_for_null_terminated_string_arg (0, false, nullptr);
+    
+    /* atoi returns an integer, but we don't know what it is statically. 
+       Tell the analyzer to assume it returns a generic, unknown value. */
+    cd.set_any_lhs_with_defaults ();
+  }
+};
+
 /* Handler for calls to "putenv".
 
    In theory we could try to model the state of the environment variables
@@ -2289,6 +2308,10 @@ register_known_functions (known_function_manager &kfm,
   /* Known builtins and C standard library functions
      the analyzer has known functions for.  */
   {
+    kfm.add ("atoi", std::make_unique<kf_atoi_family> ());
+    kfm.add ("atol", std::make_unique<kf_atoi_family> ());
+    kfm.add ("atoll", std::make_unique<kf_atoi_family> ());
+
     kfm.add ("alloca", std::make_unique<kf_alloca> ());
     kfm.add ("__builtin_alloca", std::make_unique<kf_alloca> ());
     kfm.add ("calloc", std::make_unique<kf_calloc> ());
@@ -2388,6 +2411,10 @@ register_known_functions (known_function_manager &kfm,
      from <cstdlib> etc for the C spellings of these headers (e.g. <stdlib.h>),
      so we must match against these too.  */
   {
+    kfm.add_std_ns ("atoi", std::make_unique<kf_atoi_family> ());
+    kfm.add_std_ns ("atol", std::make_unique<kf_atoi_family> ());
+    kfm.add_std_ns ("atoll", std::make_unique<kf_atoi_family> ());
+
     kfm.add_std_ns ("malloc", std::make_unique<kf_malloc> ());
     kfm.add_std_ns ("free", std::make_unique<kf_free> ());
     kfm.add_std_ns ("realloc", std::make_unique<kf_realloc> ());
diff --git a/gcc/testsuite/gcc.dg/analyzer/atoi-1.c b/gcc/testsuite/gcc.dg/analyzer/atoi-1.c
new file mode 100644 (file)
index 0000000..5b008bf
--- /dev/null
@@ -0,0 +1,27 @@
+#include <stdlib.h>
+
+void test_valid_atoi(void) {
+    int val = atoi("123"); /* Should be fine. */
+}
+
+void test_uninitialized_atoi(void) {
+    char buf[10];
+    int val = atoi(buf); /* { dg-warning "use of uninitialized value" } */
+}
+
+void test_atoi_no_lhs(void) {
+    atoi("123"); /* Should be fine, shouldn't crash. */
+}
+
+void test_unterminated_atoi(void) {
+    char buf[3] = {'1', '2', '3'};
+    int val = atoi(buf); /* { dg-warning "over-read" } */
+}
+
+void test_valid_atol(void) {
+    long val = atol("123"); /* Should be fine. */
+}
+
+void test_valid_atoll(void) {
+    long long val = atoll("123"); /* Should be fine. */
+}