[libc-commits] [PATCH] D140350: [libc][NFC] make atoi undefined cases match std

Michael Jones via Phabricator via libc-commits libc-commits at lists.llvm.org
Mon Dec 19 13:39:34 PST 2022


michaelrj created this revision.
michaelrj added a reviewer: sivachandra.
Herald added subscribers: libc-commits, ecnelises, tschuett.
Herald added projects: libc-project, All.
michaelrj requested review of this revision.

The standard describes atoi as:

"equivalent to atoi: (int)strtol(nptr, (char **)NULL, 10)"

Previously, our behavior was slightly different on numbers larger than
INT_MAX, but this patch changes it to just do the cast instead. Both of
these are valid since the standard says

"If the value of the result cannot be represented, the
behavior is undefined."

But matching existing behavior makes differential fuzzing easier.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D140350

Files:
  libc/src/stdlib/atoi.cpp
  libc/test/src/stdlib/AtoiTest.h


Index: libc/test/src/stdlib/AtoiTest.h
===================================================================
--- libc/test/src/stdlib/AtoiTest.h
+++ libc/test/src/stdlib/AtoiTest.h
@@ -54,6 +54,23 @@
       const char *smallest_long_long = "-9223372036854775808";
       ASSERT_EQ(func(smallest_long_long), static_cast<ReturnT>(LLONG_MIN));
     }
+
+    // If this is atoi and the size of int is less than the size of long, then
+    // we parse as long and cast to int to match existing behavior. This only
+    // matters for cases where the result would be outside of the int range, and
+    // those cases are undefined, so we can choose whatever output value we
+    // want. In this case we have chosen to cast since that matches existing
+    // implementations and makes differential fuzzing easier, but no user should
+    // rely on this behavior.
+    if constexpr (sizeof(ReturnT) < sizeof(long)) {
+      const char *bigger_than_biggest_int = "2147483649";
+      ASSERT_EQ(func(bigger_than_biggest_int),
+                static_cast<ReturnT>(2147483649));
+
+      const char *smaller_than_smallest_int = "-2147483649";
+      ASSERT_EQ(func(smaller_than_smallest_int),
+                static_cast<ReturnT>(-2147483649));
+    }
   }
 
   void nonBaseTenWholeNumbers(FunctionT func) {
Index: libc/src/stdlib/atoi.cpp
===================================================================
--- libc/src/stdlib/atoi.cpp
+++ libc/src/stdlib/atoi.cpp
@@ -13,11 +13,13 @@
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, atoi, (const char *str)) {
-  auto result = internal::strtointeger<int>(str, 10);
+  // This is done because the standard specifies that atoi is identical to
+  // (int)(strtol).
+  auto result = internal::strtointeger<long>(str, 10);
   if (result.has_error())
     errno = result.error;
 
-  return result;
+  return static_cast<int>(result);
 }
 
 } // namespace __llvm_libc


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D140350.484059.patch
Type: text/x-patch
Size: 1907 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libc-commits/attachments/20221219/47ef6d41/attachment-0001.bin>


More information about the libc-commits mailing list