[libc-commits] [libc] b47c9f5 - [libc] Add initial assert definition

Alex Brachet via libc-commits libc-commits at lists.llvm.org
Wed Mar 11 20:47:08 PDT 2020


Author: Alex Brachet
Date: 2020-03-11T23:45:58-04:00
New Revision: b47c9f535c8a0fffeb7634a82e3901d416915938

URL: https://github.com/llvm/llvm-project/commit/b47c9f535c8a0fffeb7634a82e3901d416915938
DIFF: https://github.com/llvm/llvm-project/commit/b47c9f535c8a0fffeb7634a82e3901d416915938.diff

LOG: [libc] Add initial assert definition

Summary: This patch adds a temporary `__assert_fail` and `assert` definition to make it available to internal llvm libc code. `__assert_fail` writes to fd 2 directly instead of `stderr`, using SYS_write. I have not put it in its own linux directory because this is temporary and it should be using stdio's api in the future. It does not currently print out the line number (although we could do that by stringifying `__LINE__` if reviewers wish).

Reviewers: sivachandra, gchatelet, PaulkaToast

Reviewed By: sivachandra

Subscribers: mgorny, MaskRay, tschuett, libc-commits

Differential Revision: https://reviews.llvm.org/D75420

Added: 
    libc/include/assert.h.def
    libc/src/assert/CMakeLists.txt
    libc/src/assert/__assert_fail.cpp
    libc/src/assert/assert.h
    libc/test/src/assert/CMakeLists.txt
    libc/test/src/assert/assert_test.cpp

Modified: 
    libc/config/linux/api.td
    libc/include/CMakeLists.txt
    libc/lib/CMakeLists.txt
    libc/spec/stdc.td
    libc/src/CMakeLists.txt
    libc/test/src/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 1d78a598d21e..aecdce206f65 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -18,6 +18,35 @@ def OffT : TypeDecl<"off_t"> {
   }];
 }
 
+def AssertMacro : MacroDef<"assert"> {
+  let Defn = [{
+    #undef assert
+
+    #ifdef NDEBUG
+    #define assert(e) (void)0
+    #else
+
+    #ifdef __cplusplus
+    extern "C"
+    #endif
+    _Noreturn void __assert_fail(const char *, const char *, unsigned, const char *);
+
+    #define assert(e)  \
+      ((e) ? (void)0 : __assert_fail(#e, __FILE__, __LINE__, __PRETTY_FUNCTION__))
+
+    #endif
+  }];
+}
+
+def StaticAssertMacro : MacroDef<"static_assert"> {
+  let Defn = [{
+    #ifndef __cplusplus
+    #undef static_assert
+    #define static_assert _Static_assert
+    #endif
+  }];
+}
+
 def NullMacro : MacroDef<"NULL"> {
   let Defn = [{
     #define __need_NULL
@@ -35,6 +64,13 @@ def ErrnoMacro : MacroDef<"errno"> {
   }];
 }
 
+def AssertAPI : PublicAPI<"assert.h"> {
+  let Macros = [
+    AssertMacro,
+    StaticAssertMacro,
+  ];
+}
+
 def MathAPI : PublicAPI<"math.h"> {
   let Functions = [
    "acos",

diff  --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index bbc41b0ec151..2ff04231e406 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -27,6 +27,14 @@ add_header(
     llvm_libc_common_h
 )
 
+add_gen_header(
+  assert_h
+  DEF_FILE assert.h.def
+  GEN_HDR assert.h
+  DEPENDS
+    llvm_libc_common_h
+)
+
 add_gen_header(
   string_h
   DEF_FILE string.h.def

diff  --git a/libc/include/assert.h.def b/libc/include/assert.h.def
new file mode 100644
index 000000000000..3d7827799904
--- /dev/null
+++ b/libc/include/assert.h.def
@@ -0,0 +1,14 @@
+//===---------------- C standard library header assert.h ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <__llvm-libc-common.h>
+
+// This file may be usefully included multiple times to change assert()'s
+// definition based on NDEBUG.
+
+%%public_api()

diff  --git a/libc/lib/CMakeLists.txt b/libc/lib/CMakeLists.txt
index ed91367ed1ad..238bcb447512 100644
--- a/libc/lib/CMakeLists.txt
+++ b/libc/lib/CMakeLists.txt
@@ -2,6 +2,9 @@
 add_entrypoint_library(
   llvmlibc
   DEPENDS
+    # assert.h entrypoints
+    __assert_fail
+
     # errno.h entrypoints
     __errno_location
 

diff  --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index babfce4b6ad2..4df855056e9b 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -16,6 +16,17 @@ def StdC : StandardSpec<"stdc"> {
 
   PtrType IntPtr = PtrType<IntType>;
 
+  HeaderSpec Assert = HeaderSpec<
+      "assert.h",
+      [
+          Macro<"static_assert">,
+          Macro<"assert">,
+      ],
+      [], // Types
+      [], // Enumerations
+      []
+  >;
+
   HeaderSpec String = HeaderSpec<
       "string.h",
       [
@@ -285,6 +296,7 @@ def StdC : StandardSpec<"stdc"> {
   >;
 
   let Headers = [
+    Assert,
     Errno,
     Math,
     String,

diff  --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 4e661c838e51..3ee30fd322ac 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(assert)
 add_subdirectory(errno)
 add_subdirectory(math)
 add_subdirectory(signal)

diff  --git a/libc/src/assert/CMakeLists.txt b/libc/src/assert/CMakeLists.txt
new file mode 100644
index 000000000000..4c39b0f93be2
--- /dev/null
+++ b/libc/src/assert/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_entrypoint_object(
+  __assert_fail
+  SRCS
+    __assert_fail.cpp
+  HDRS
+    assert.h
+  DEPENDS
+    abort
+    # These two dependencies are temporary and should be replaced by fprintf
+    # later.
+    sys_syscall_h
+    linux_syscall_h
+)

diff  --git a/libc/src/assert/__assert_fail.cpp b/libc/src/assert/__assert_fail.cpp
new file mode 100644
index 000000000000..4e72ac759c56
--- /dev/null
+++ b/libc/src/assert/__assert_fail.cpp
@@ -0,0 +1,38 @@
+//===----------------- Implementation of __assert_fail --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/assert/assert.h"
+#include "src/stdlib/abort.h"
+
+// These includes are temporary.
+#include "config/linux/syscall.h" // For internal syscall function.
+#include "include/sys/syscall.h"  // For syscall numbers.
+
+namespace __llvm_libc {
+
+// This is just a temporary solution to make assert available to internal
+// llvm libc code. In the future writeToStderr will not exist and __assert_fail
+// will call fprintf(stderr, ...).
+static void writeToStderr(const char *s) {
+  size_t length = 0;
+  for (const char *curr = s; *curr; ++curr, ++length);
+  __llvm_libc::syscall(SYS_write, 2, s, length);
+}
+
+void LLVM_LIBC_ENTRYPOINT(__assert_fail)(const char *assertion, const char *file,
+                                         unsigned line, const char *function) {
+  writeToStderr(file);
+  writeToStderr(": Assertion failed: '");
+  writeToStderr(assertion);
+  writeToStderr("' in function: '");
+  writeToStderr(function);
+  writeToStderr("'\n");
+  __llvm_libc::abort();
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/assert/assert.h b/libc/src/assert/assert.h
new file mode 100644
index 000000000000..ef596daa53fd
--- /dev/null
+++ b/libc/src/assert/assert.h
@@ -0,0 +1,31 @@
+//===-------------------- Internal header for assert ----------*- C++ -*---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_ASSERT_ASSERT_H
+#define LLVM_LIBC_SRC_ASSERT_ASSERT_H
+
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+[[noreturn]] void __assert_fail(const char *assertion, const char *file, unsigned line,
+                  const char *function);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_ASSERT_ASSERT_H
+
+#undef assert
+
+#ifdef NDEBUG
+#define assert(e) (void)0
+#else
+#define assert(e)                                                              \
+  ((e) ? (void)0 :                                                             \
+    __llvm_libc::__assert_fail(#e, __FILE__, __LINE__, __PRETTY_FUNCTION__))
+#endif

diff  --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index 2ff4ca4d1252..30c561634c39 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(assert)
 add_subdirectory(errno)
 add_subdirectory(signal)
 add_subdirectory(stdlib)

diff  --git a/libc/test/src/assert/CMakeLists.txt b/libc/test/src/assert/CMakeLists.txt
new file mode 100644
index 000000000000..c79c76c4c2e4
--- /dev/null
+++ b/libc/test/src/assert/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_libc_testsuite(libc_assert_unittests)
+
+add_libc_unittest(
+  assert_test
+  SUITE
+    libc_assert_unittests
+  SRCS
+    assert_test.cpp
+  DEPENDS
+    __assert_fail
+    # These are necessary for now because dependencies are not properly added.
+    abort
+    raise
+    _Exit
+)

diff  --git a/libc/test/src/assert/assert_test.cpp b/libc/test/src/assert/assert_test.cpp
new file mode 100644
index 000000000000..7d96f98afd7e
--- /dev/null
+++ b/libc/test/src/assert/assert_test.cpp
@@ -0,0 +1,32 @@
+//===---------------------- Unittests for assert --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#undef NDEBUG
+#include "src/assert/assert.h"
+#include "utils/UnitTest/Test.h"
+
+extern "C" int close(int);
+
+TEST(Assert, Enabled) {
+  // -1 matches against any signal, which is necessary for now until
+  // __llvm_libc::abort() unblocks SIGABRT. Close standard error for the
+  // child process so we don't print the assertion failure message.
+  EXPECT_DEATH(
+      [] {
+        close(2);
+        assert(0);
+      },
+      -1);
+}
+
+#define NDEBUG
+#include "src/assert/assert.h"
+
+TEST(Assert, Disabled) {
+  EXPECT_EXITS([] { assert(0); }, 0);
+}


        


More information about the libc-commits mailing list