summary refs log tree commit diff stats
path: root/lib/system/ansi_c.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/system/ansi_c.nim')
-rw-r--r--lib/system/ansi_c.nim335
1 files changed, 200 insertions, 135 deletions
diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim
index 702559034..3098e17d6 100644
--- a/lib/system/ansi_c.nim
+++ b/lib/system/ansi_c.nim
@@ -7,162 +7,227 @@
 #    distribution, for details about the copyright.
 #
 
-# This include file contains headers of Ansi C procs
+# This module contains headers of Ansi C procs
 # and definitions of Ansi C types in Nim syntax
 # All symbols are prefixed with 'c_' to avoid ambiguities
 
-{.push hints:off}
-
-proc c_strcmp(a, b: cstring): cint {.header: "<string.h>",
-  noSideEffect, importc: "strcmp".}
-proc c_memcmp(a, b: cstring, size: int): cint {.header: "<string.h>",
-  noSideEffect, importc: "memcmp".}
-proc c_memcpy(a, b: cstring, size: int) {.header: "<string.h>", importc: "memcpy".}
-proc c_strlen(a: cstring): int {.header: "<string.h>",
-  noSideEffect, importc: "strlen".}
-proc c_memset(p: pointer, value: cint, size: int) {.
-  header: "<string.h>", importc: "memset".}
-
-type
-  C_TextFile {.importc: "FILE", header: "<stdio.h>",
-               final, incompleteStruct.} = object
-  C_BinaryFile {.importc: "FILE", header: "<stdio.h>",
-                 final, incompleteStruct.} = object
-  C_TextFileStar = ptr C_TextFile
-  C_BinaryFileStar = ptr C_BinaryFile
-
-  C_JmpBuf {.importc: "jmp_buf", header: "<setjmp.h>".} = object
-
-when not defined(vm):
-  var
-    c_stdin {.importc: "stdin", nodecl.}: C_TextFileStar
-    c_stdout {.importc: "stdout", nodecl.}: C_TextFileStar
-    c_stderr {.importc: "stderr", nodecl.}: C_TextFileStar
-
-# constants faked as variables:
-when not declared(SIGINT):
-  when NoFakeVars:
-    when defined(windows):
-      const
-        SIGABRT = cint(22)
-        SIGFPE = cint(8)
-        SIGILL = cint(4)
-        SIGINT = cint(2)
-        SIGSEGV = cint(11)
-        SIGTERM = cint(15)
-    elif defined(macosx) or defined(linux):
-      const
-        SIGABRT = cint(6)
-        SIGFPE = cint(8)
-        SIGILL = cint(4)
-        SIGINT = cint(2)
-        SIGSEGV = cint(11)
-        SIGTERM = cint(15)
-        SIGPIPE = cint(13)
-    else:
-      {.error: "SIGABRT not ported to your platform".}
+{.push hints:off, stack_trace: off, profiler: off.}
+
+proc c_memchr*(s: pointer, c: cint, n: csize_t): pointer {.
+  importc: "memchr", header: "<string.h>".}
+proc c_memcmp*(a, b: pointer, size: csize_t): cint {.
+  importc: "memcmp", header: "<string.h>", noSideEffect.}
+proc c_memcpy*(a, b: pointer, size: csize_t): pointer {.
+  importc: "memcpy", header: "<string.h>", discardable.}
+proc c_memmove*(a, b: pointer, size: csize_t): pointer {.
+  importc: "memmove", header: "<string.h>",discardable.}
+proc c_memset*(p: pointer, value: cint, size: csize_t): pointer {.
+  importc: "memset", header: "<string.h>", discardable.}
+proc c_strcmp*(a, b: cstring): cint {.
+  importc: "strcmp", header: "<string.h>", noSideEffect.}
+proc c_strlen*(a: cstring): csize_t {.
+  importc: "strlen", header: "<string.h>", noSideEffect.}
+proc c_abort*() {.
+  importc: "abort", header: "<stdlib.h>", noSideEffect, noreturn.}
+
+
+when defined(nimBuiltinSetjmp):
+  type
+    C_JmpBuf* = array[5, pointer]
+elif defined(linux) and defined(amd64):
+  type
+    C_JmpBuf* {.importc: "jmp_buf", header: "<setjmp.h>", bycopy.} = object
+        abi: array[200 div sizeof(clong), clong]
+else:
+  type
+    C_JmpBuf* {.importc: "jmp_buf", header: "<setjmp.h>".} = object
+
+
+type CSighandlerT = proc (a: cint) {.noconv.}
+when defined(windows):
+  const
+    SIGABRT* = cint(22)
+    SIGFPE* = cint(8)
+    SIGILL* = cint(4)
+    SIGINT* = cint(2)
+    SIGSEGV* = cint(11)
+    SIGTERM = cint(15)
+    SIG_DFL* = cast[CSighandlerT](0)
+elif defined(macosx) or defined(linux) or defined(freebsd) or
+     defined(openbsd) or defined(netbsd) or defined(solaris) or
+     defined(dragonfly) or defined(nintendoswitch) or defined(genode) or
+     defined(aix) or hostOS == "standalone":
+  const
+    SIGABRT* = cint(6)
+    SIGFPE* = cint(8)
+    SIGILL* = cint(4)
+    SIGINT* = cint(2)
+    SIGSEGV* = cint(11)
+    SIGTERM* = cint(15)
+    SIGPIPE* = cint(13)
+    SIG_DFL* = CSighandlerT(nil)
+elif defined(haiku):
+  const
+    SIGABRT* = cint(6)
+    SIGFPE* = cint(8)
+    SIGILL* = cint(4)
+    SIGINT* = cint(2)
+    SIGSEGV* = cint(11)
+    SIGTERM* = cint(15)
+    SIGPIPE* = cint(7)
+    SIG_DFL* = CSighandlerT(nil)
+else:
+  when defined(nimscript):
+    {.error: "SIGABRT not ported to your platform".}
   else:
     var
-      SIGINT {.importc: "SIGINT", nodecl.}: cint
-      SIGSEGV {.importc: "SIGSEGV", nodecl.}: cint
-      SIGABRT {.importc: "SIGABRT", nodecl.}: cint
-      SIGFPE {.importc: "SIGFPE", nodecl.}: cint
-      SIGILL {.importc: "SIGILL", nodecl.}: cint
+      SIGINT* {.importc: "SIGINT", nodecl.}: cint
+      SIGSEGV* {.importc: "SIGSEGV", nodecl.}: cint
+      SIGABRT* {.importc: "SIGABRT", nodecl.}: cint
+      SIGFPE* {.importc: "SIGFPE", nodecl.}: cint
+      SIGILL* {.importc: "SIGILL", nodecl.}: cint
+      SIG_DFL* {.importc: "SIG_DFL", nodecl.}: CSighandlerT
     when defined(macosx) or defined(linux):
-      var SIGPIPE {.importc: "SIGPIPE", nodecl.}: cint
+      var SIGPIPE* {.importc: "SIGPIPE", nodecl.}: cint
 
 when defined(macosx):
-  when NoFakeVars:
-    const SIGBUS = cint(10)
-  else:
-    var SIGBUS {.importc: "SIGBUS", nodecl.}: cint
-else:
-  template SIGBUS: expr = SIGSEGV
-
-when defined(nimSigSetjmp) and not defined(nimStdSetjmp):
-  proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.
+  const SIGBUS* = cint(10)
+elif defined(haiku):
+  const SIGBUS* = cint(30)
+
+# "nimRawSetjmp" is defined by default for certain platforms, so we need the
+# "nimStdSetjmp" escape hatch with it.
+when defined(nimSigSetjmp):
+  proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
     header: "<setjmp.h>", importc: "siglongjmp".}
-  template c_setjmp(jmpb: C_JmpBuf): cint =
+  proc c_setjmp*(jmpb: C_JmpBuf): cint =
     proc c_sigsetjmp(jmpb: C_JmpBuf, savemask: cint): cint {.
       header: "<setjmp.h>", importc: "sigsetjmp".}
     c_sigsetjmp(jmpb, 0)
+elif defined(nimBuiltinSetjmp):
+  proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) =
+    # Apple's Clang++ has trouble converting array names to pointers, so we need
+    # to be very explicit here.
+    proc c_builtin_longjmp(jmpb: ptr pointer, retval: cint) {.
+      importc: "__builtin_longjmp", nodecl.}
+    # The second parameter needs to be 1 and sometimes the C/C++ compiler checks it.
+    c_builtin_longjmp(unsafeAddr jmpb[0], 1)
+  proc c_setjmp*(jmpb: C_JmpBuf): cint =
+    proc c_builtin_setjmp(jmpb: ptr pointer): cint {.
+      importc: "__builtin_setjmp", nodecl.}
+    c_builtin_setjmp(unsafeAddr jmpb[0])
+
 elif defined(nimRawSetjmp) and not defined(nimStdSetjmp):
-  proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.
-    header: "<setjmp.h>", importc: "_longjmp".}
-  proc c_setjmp(jmpb: C_JmpBuf): cint {.
-    header: "<setjmp.h>", importc: "_setjmp".}
+  when defined(windows):
+    # No `_longjmp()` on Windows.
+    proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
+      header: "<setjmp.h>", importc: "longjmp".}
+    when defined(vcc) or defined(clangcl):
+      proc c_setjmp*(jmpb: C_JmpBuf): cint {.
+        header: "<setjmp.h>", importc: "setjmp".}
+    else:
+      # The Windows `_setjmp()` takes two arguments, with the second being an
+      # undocumented buffer used by the SEH mechanism for stack unwinding.
+      # Mingw-w64 has been trying to get it right for years, but it's still
+      # prone to stack corruption during unwinding, so we disable that by setting
+      # it to NULL.
+      # More details: https://github.com/status-im/nimbus-eth2/issues/3121
+      when defined(nimHasStyleChecks):
+        {.push styleChecks: off.}
+
+      proc c_setjmp*(jmpb: C_JmpBuf): cint =
+        proc c_setjmp_win(jmpb: C_JmpBuf, ctx: pointer): cint {.
+          header: "<setjmp.h>", importc: "_setjmp".}
+        c_setjmp_win(jmpb, nil)
+
+      when defined(nimHasStyleChecks):
+        {.pop.}
+  else:
+    proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
+      header: "<setjmp.h>", importc: "_longjmp".}
+    proc c_setjmp*(jmpb: C_JmpBuf): cint {.
+      header: "<setjmp.h>", importc: "_setjmp".}
 else:
-  proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.
+  proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
     header: "<setjmp.h>", importc: "longjmp".}
-  proc c_setjmp(jmpb: C_JmpBuf): cint {.
+  proc c_setjmp*(jmpb: C_JmpBuf): cint {.
     header: "<setjmp.h>", importc: "setjmp".}
 
-proc c_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {.
-  importc: "signal", header: "<signal.h>".}
-proc c_raise(sig: cint) {.importc: "raise", header: "<signal.h>".}
-
-proc c_fputs(c: cstring, f: C_TextFileStar) {.importc: "fputs",
-  header: "<stdio.h>".}
-proc c_fgets(c: cstring, n: int, f: C_TextFileStar): cstring  {.
-  importc: "fgets", header: "<stdio.h>".}
-proc c_fgetc(stream: C_TextFileStar): int {.importc: "fgetc",
-  header: "<stdio.h>".}
-proc c_ungetc(c: int, f: C_TextFileStar) {.importc: "ungetc",
-  header: "<stdio.h>".}
-proc c_putc(c: char, stream: C_TextFileStar) {.importc: "putc",
-  header: "<stdio.h>".}
-proc c_fprintf(f: C_TextFileStar, frmt: cstring) {.
-  importc: "fprintf", header: "<stdio.h>", varargs.}
-proc c_printf(frmt: cstring) {.
-  importc: "printf", header: "<stdio.h>", varargs.}
-
-proc c_fopen(filename, mode: cstring): C_TextFileStar {.
-  importc: "fopen", header: "<stdio.h>".}
-proc c_fclose(f: C_TextFileStar) {.importc: "fclose", header: "<stdio.h>".}
-
-proc c_sprintf(buf, frmt: cstring): cint {.header: "<stdio.h>",
-  importc: "sprintf", varargs, noSideEffect.}
-  # we use it only in a way that cannot lead to security issues
+proc c_signal*(sign: cint, handler: CSighandlerT): CSighandlerT {.
+  importc: "signal", header: "<signal.h>", discardable.}
+proc c_raise*(sign: cint): cint {.importc: "raise", header: "<signal.h>".}
 
-proc c_fread(buf: pointer, size, n: int, f: C_BinaryFileStar): int {.
-  importc: "fread", header: "<stdio.h>".}
-proc c_fseek(f: C_BinaryFileStar, offset: clong, whence: int): int {.
-  importc: "fseek", header: "<stdio.h>".}
+type
+  CFile {.importc: "FILE", header: "<stdio.h>",
+          incompleteStruct.} = object
+  CFilePtr* = ptr CFile ## The type representing a file handle.
+
+# duplicated between io and ansi_c
+const stdioUsesMacros = (defined(osx) or defined(freebsd) or defined(dragonfly)) and not defined(emscripten)
+const stderrName = when stdioUsesMacros: "__stderrp" else: "stderr"
+const stdoutName = when stdioUsesMacros: "__stdoutp" else: "stdout"
+const stdinName = when stdioUsesMacros: "__stdinp" else: "stdin"
+
+var
+  cstderr* {.importc: stderrName, header: "<stdio.h>".}: CFilePtr
+  cstdout* {.importc: stdoutName, header: "<stdio.h>".}: CFilePtr
+  cstdin* {.importc: stdinName, header: "<stdio.h>".}: CFilePtr
+
+proc c_fprintf*(f: CFilePtr, frmt: cstring): cint {.
+  importc: "fprintf", header: "<stdio.h>", varargs, discardable.}
+proc c_printf*(frmt: cstring): cint {.
+  importc: "printf", header: "<stdio.h>", varargs, discardable.}
+
+proc c_fputs*(c: cstring, f: CFilePtr): cint {.
+  importc: "fputs", header: "<stdio.h>", discardable.}
+proc c_fputc*(c: char, f: CFilePtr): cint {.
+  importc: "fputc", header: "<stdio.h>", discardable.}
+
+proc c_sprintf*(buf, frmt: cstring): cint {.
+  importc: "sprintf", header: "<stdio.h>", varargs, noSideEffect.}
+  # we use it only in a way that cannot lead to security issues
 
-proc c_fwrite(buf: pointer, size, n: int, f: C_BinaryFileStar): int {.
+proc c_snprintf*(buf: cstring, n: csize_t, frmt: cstring): cint {.
+  importc: "snprintf", header: "<stdio.h>", varargs, noSideEffect.}
+
+when defined(zephyr) and not defined(zephyrUseLibcMalloc):
+  proc c_malloc*(size: csize_t): pointer {.
+    importc: "k_malloc", header: "<kernel.h>".}
+  proc c_calloc*(nmemb, size: csize_t): pointer {.
+    importc: "k_calloc", header: "<kernel.h>".}
+  proc c_free*(p: pointer) {.
+    importc: "k_free", header: "<kernel.h>".}
+  proc c_realloc*(p: pointer, newsize: csize_t): pointer =
+    # Zephyr's kernel malloc doesn't support realloc
+    result = c_malloc(newSize)
+    # match the ansi c behavior
+    if not result.isNil():
+      copyMem(result, p, newSize)
+      c_free(p)
+else:
+  proc c_malloc*(size: csize_t): pointer {.
+    importc: "malloc", header: "<stdlib.h>".}
+  proc c_calloc*(nmemb, size: csize_t): pointer {.
+    importc: "calloc", header: "<stdlib.h>".}
+  proc c_free*(p: pointer) {.
+    importc: "free", header: "<stdlib.h>".}
+  proc c_realloc*(p: pointer, newsize: csize_t): pointer {.
+    importc: "realloc", header: "<stdlib.h>".}
+
+proc c_fwrite*(buf: pointer, size, n: csize_t, f: CFilePtr): csize_t {.
   importc: "fwrite", header: "<stdio.h>".}
 
-proc c_exit(errorcode: cint) {.importc: "exit", header: "<stdlib.h>".}
-proc c_ferror(stream: C_TextFileStar): bool {.
-  importc: "ferror", header: "<stdio.h>".}
-proc c_fflush(stream: C_TextFileStar) {.importc: "fflush", header: "<stdio.h>".}
-proc c_abort() {.importc: "abort", header: "<stdlib.h>".}
-proc c_feof(stream: C_TextFileStar): bool {.
-  importc: "feof", header: "<stdio.h>".}
-
-proc c_malloc(size: int): pointer {.importc: "malloc", header: "<stdlib.h>".}
-proc c_free(p: pointer) {.importc: "free", header: "<stdlib.h>".}
-proc c_realloc(p: pointer, newsize: int): pointer {.
-  importc: "realloc", header: "<stdlib.h>".}
-
-when hostOS != "standalone":
-  when not declared(errno):
-    when defined(NimrodVM):
-      var vmErrnoWrapper {.importc.}: ptr cint
-      template errno: expr =
-        bind vmErrnoWrapper
-        vmErrnoWrapper[]
-    else:
-      var errno {.importc, header: "<errno.h>".}: cint ## error variable
-proc strerror(errnum: cint): cstring {.importc, header: "<string.h>".}
+proc c_fflush*(f: CFilePtr): cint {.
+  importc: "fflush", header: "<stdio.h>".}
 
-proc c_remove(filename: cstring): cint {.
-  importc: "remove", header: "<stdio.h>".}
-proc c_rename(oldname, newname: cstring): cint {.
-  importc: "rename", header: "<stdio.h>".}
+proc rawWriteString*(f: CFilePtr, s: cstring, length: int) {.compilerproc, nonReloadable, inline.} =
+  # we cannot throw an exception here!
+  discard c_fwrite(s, 1, cast[csize_t](length), f)
+  discard c_fflush(f)
 
-proc c_system(cmd: cstring): cint {.importc: "system", header: "<stdlib.h>".}
-proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "<stdlib.h>".}
-proc c_putenv(env: cstring): cint {.importc: "putenv", header: "<stdlib.h>".}
+proc rawWrite*(f: CFilePtr, s: cstring) {.compilerproc, nonReloadable, inline.} =
+  # we cannot throw an exception here!
+  discard c_fwrite(s, 1, c_strlen(s), f)
+  discard c_fflush(f)
 
-{.pop}
+{.pop.}