nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.56k stars 1.47k forks source link

Nim Hot Code Reloading tests fail on OpenBSD #12140

Open euantorano opened 5 years ago

euantorano commented 5 years ago

There are several nimhcr tests that fail on OpenBSD with a Not supported [OSError] error. THe problem appears to be in the reservedmem module as they all fail with a stacktrace similar to the following:

Category: dll
Name: tests/dll/nimhcr_unit.nim C
Action: run
Result: reExitcodesDiffer
-------- Expected -------
exitcode: 0
--------- Given  --------
exitcode: 1

Output:
nimhcr_unit.nim(107)     nimhcr_unit
/home/administrator/build/Nim/lib/nimhcr.nim(342) hcrRegisterProc
/home/administrator/build/Nim/lib/pure/reservedmem.nim(217) setLen
/home/administrator/build/Nim/lib/pure/reservedmem.nim(94) setLen
/home/administrator/build/Nim/lib/pure/includes/oserr.nim(94) raiseOSError
Error: unhandled exception: Not supported [OSError]
timotheecour commented 3 years ago

The stacktrace isn't super helpful because check is a template, not a proc, so it can't (currently! refs https://github.com/timotheecour/Nim/issues/447) tell which line it was called from:

  template check(expr) =
    if not expr:
      raiseOSError(osLastError())

but as I saw in https://github.com/nim-lang/Nim/pull/16329 it actually points to one of these failing: check mprotect or check posix_madvise

proc setLen*(m: var ReservedMem, newLen: int) =
  let len = m.len
  m.usedMemEnd = m.memStart.shift(newLen)
  if newLen > len:
    let d = distance(m.committedMemEnd, m.usedMemEnd)
    if d > 0:
      let commitExtensionSize = nextAlignedOffset(d, allocationGranularity)
      when defined(windows):
        check virtualAlloc(m.committedMemEnd, commitExtensionSize,
                           MEM_COMMIT, m.accessFlags.cint)
      else:
        check mprotect(m.committedMemEnd, commitExtensionSize,
            m.accessFlags.cint) == 0
  else:
    let d = distance(m.usedMemEnd, m.committedMemEnd) -
            m.maxCommittedAndUnusedPages * allocationGranularity
    if d > 0:
      let commitSizeShrinkage = nextAlignedOffset(d, allocationGranularity)
      let newCommitEnd = m.committedMemEnd.shift(-commitSizeShrinkage)

      when defined(windows):
        check virtualFree(newCommitEnd, commitSizeShrinkage, MEM_DECOMMIT)
      else:
        check posix_madvise(newCommitEnd, commitSizeShrinkage,
                            POSIX_MADV_DONTNEED) == 0

      m.committedMemEnd = newCommitEnd

upon further investigation i found this comment:

OpenBSD however doesn't implement posix_madvise().

in https://patchwork.ozlabs.org/project/qemu-devel/patch/1284224755-11299-1-git-send-email-andreas.faerber@web.de/

but there's some contradiction with other sources I found on the topic; it my depend on glibc etc

links

EDIT

looks like it's in fact check mprotect the culprit (really hard to debug via CI)

        check mprotect(m.committedMemEnd, commitExtensionSize,
            m.accessFlags.cint) == 0

I can't find any relevant reference on the web / nim sources to "Not supported" from the errmsg Error: unhandled exception: Not supported [OSError] so it's not clear where that comes from.

Further investigation needs to look what was this equal to: m.accessFlags.cint