From c15c985c1fa1c58abfeba7ba46393f9238a2fd84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan=20Talpalaru?= Date: Thu, 6 May 2021 09:49:55 +0200 Subject: [PATCH] support nimStackTraceOverride (#181) --- .appveyor.yml | 3 +- .github/workflows/ci.yml | 23 +++---------- chronos.nimble | 19 +++++++---- chronos/asyncfutures2.nim | 69 +++++++++++++++++++++++++++------------ 4 files changed, 68 insertions(+), 46 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 64fd339..768c261 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -30,7 +30,8 @@ install: build_script: - cd C:\projects\%APPVEYOR_PROJECT_SLUG% - - nimble install -y + - nimble install -y --depsOnly + - nimble install -y libbacktrace test_script: - nimble test diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6036a6a..40358ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,19 +11,14 @@ jobs: target: - os: linux cpu: amd64 - TEST_LANG: c - os: linux cpu: i386 - TEST_LANG: c - os: macos cpu: amd64 - TEST_LANG: c - os: windows cpu: amd64 - TEST_LANG: c - os: windows cpu: i386 - TEST_LANG: c include: - target: os: linux @@ -35,7 +30,7 @@ jobs: os: windows builder: windows-2019 - name: '${{ matrix.target.os }}-${{ matrix.target.cpu }}-${{ matrix.target.TEST_LANG }} (${{ matrix.branch }})' + name: '${{ matrix.target.os }}-${{ matrix.target.cpu }} (${{ matrix.branch }})' runs-on: ${{ matrix.builder }} steps: - name: Checkout nim-chronos @@ -130,8 +125,8 @@ jobs: id: nim-cache uses: actions/cache@v2 with: - path: nim - key: 'nim-${{ matrix.target.os }}-${{ matrix.target.cpu }}-${{ steps.versions.outputs.nimbus_build_system }}' + path: NimBinaries + key: 'nim-${{ matrix.target.os }}-${{ matrix.target.cpu }}-${{ steps.versions.outputs.nimbus_build_system }}-2' - name: Build Nim and associated tools if: steps.nim-cache.outputs.cache-hit != 'true' @@ -150,15 +145,6 @@ jobs: fi env MAKE="$MAKE_CMD -j2" ARCH_OVERRIDE=$PLATFORM CC=gcc bash build_nim.sh nim csources dist/nimble NimBinaries - # clean up to save cache space - cd nim - rm koch - rm -rf nimcache - rm -rf csources - rm -rf tests - rm -rf dist - rm -rf .git - - name: Setup environment shell: bash run: echo '${{ github.workspace }}/nim/bin' >> $GITHUB_PATH @@ -168,4 +154,5 @@ jobs: working-directory: nim-chronos run: | nimble install -y --depsOnly - env TEST_LANG="${{ matrix.target.TEST_LANG }}" nimble test + nimble install -y libbacktrace + nimble test diff --git a/chronos.nimble b/chronos.nimble index 9a21e19..8adfd52 100644 --- a/chronos.nimble +++ b/chronos.nimble @@ -14,17 +14,22 @@ requires "nim > 1.2.0", "https://github.com/status-im/nim-unittest2.git#head" task test, "Run all tests": - var commands = @[ - "nim c -r -d:useSysAssert -d:useGcAssert tests/", - "nim c -r -d:chronosStackTrace -d:chronosStrictException tests/", - "nim c -r -d:release tests/", - "nim c -r -d:release -d:chronosFutureTracking tests/" - ] + var + commandStart = "nim c -r --hints:off --verbosity:0 --skipParentCfg:on --warning[ObservableStores]:off" + commands = @[ + commandStart & " -d:useSysAssert -d:useGcAssert tests/", + commandStart & " -d:chronosStackTrace -d:chronosStrictException tests/", + commandStart & " -d:release tests/", + commandStart & " -d:release -d:chronosFutureTracking tests/", + commandStart & " -d:release --debugger:native -d:chronosStackTrace -d:nimStackTraceOverride --import:libbacktrace tests/", + ] when (NimMajor, NimMinor) >= (1, 5): - commands.add "nim c -r --gc:orc -d:chronosFutureTracking -d:release -d:chronosStackTrace tests/" + commands.add commandStart & " --gc:orc -d:chronosFutureTracking -d:release -d:chronosStackTrace tests/" for testname in ["testall"]: for cmd in commands: let curcmd = cmd & testname echo "\n" & curcmd exec curcmd + rmFile "tests/" & testname + diff --git a/chronos/asyncfutures2.nim b/chronos/asyncfutures2.nim index b78058c..7ba352b 100644 --- a/chronos/asyncfutures2.nim +++ b/chronos/asyncfutures2.nim @@ -1,8 +1,8 @@ # # Chronos # -# (c) Copyright 2015 Dominik Picheta -# (c) Copyright 2018-Present Status Research & Development GmbH +# (c) Copyright 2015 Dominik Picheta +# (c) Copyright 2018-2021 Status Research & Development GmbH # # Licensed under either of # Apache License, version 2.0, (LICENSE-APACHEv2) @@ -12,6 +12,13 @@ import std/[os, tables, strutils, heapqueue, options, deques, cstrutils, sequtil import ./srcloc export srcloc +when defined(nimHasStacktracesModule): + import system/stacktraces +else: + const + reraisedFromBegin = -10 + reraisedFromEnd = -100 + const LocCreateIndex* = 0 LocCompleteIndex* = 1 @@ -390,49 +397,71 @@ proc `cancelCallback=`*[T](future: Future[T], cb: CallbackFunc) = ## This callback will be called immediately as ``future.cancel()`` invoked. future.cancelcb = cb +template getFilenameProcname(entry: StackTraceEntry): (string, string) = + when compiles(entry.filenameStr) and compiles(entry.procnameStr): + # We can't rely on "entry.filename" and "entry.procname" still being valid + # cstring pointers, because the "string.data" buffers they pointed to might + # be already garbage collected (this entry being a non-shallow copy, + # "entry.filename" no longer points to "entry.filenameStr.data", but to the + # buffer of the original object). + (entry.filenameStr, entry.procnameStr) + else: + ($entry.filename, $entry.procname) + proc getHint(entry: StackTraceEntry): string = ## We try to provide some hints about stack trace entries that the user ## may not be familiar with, in particular calls inside the stdlib. - result = "" - if entry.procname == "processPendingCallbacks": - if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0: + + let (filename, procname) = getFilenameProcname(entry) + + if procname == "processPendingCallbacks": + if cmpIgnoreStyle(filename, "asyncdispatch.nim") == 0: return "Executes pending callbacks" - elif entry.procname == "poll": - if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0: + elif procname == "poll": + if cmpIgnoreStyle(filename, "asyncdispatch.nim") == 0: return "Processes asynchronous completion events" - if entry.procname.endsWith("_continue"): - if cmpIgnoreStyle(entry.filename, "asyncmacro.nim") == 0: + if procname.endsWith("_continue"): + if cmpIgnoreStyle(filename, "asyncmacro.nim") == 0: return "Resumes an async procedure" -proc `$`*(entries: seq[StackTraceEntry]): string = +proc `$`(stackTraceEntries: seq[StackTraceEntry]): string = try: + when defined(nimStackTraceOverride) and declared(addDebuggingInfo): + let entries = addDebuggingInfo(stackTraceEntries) + else: + let entries = stackTraceEntries + # Find longest filename & line number combo for alignment purposes. var longestLeft = 0 for entry in entries: - if isNil(entry.procName): continue + let (filename, procname) = getFilenameProcname(entry) - let left = $entry.filename & $entry.line - if left.len > longestLeft: - longestLeft = left.len + if procname == "": continue + + let leftLen = filename.len + len($entry.line) + if leftLen > longestLeft: + longestLeft = leftLen var indent = 2 # Format the entries. for entry in entries: - if isNil(entry.procName): - if entry.line == -10: + let (filename, procname) = getFilenameProcname(entry) + + if procname == "": + if entry.line == reraisedFromBegin: result.add(spaces(indent) & "#[\n") indent.inc(2) - else: + elif entry.line == reraisedFromEnd: indent.dec(2) result.add(spaces(indent) & "]#\n") continue - let left = "$#($#)" % [$entry.filename, $entry.line] + let left = "$#($#)" % [filename, $entry.line] result.add((spaces(indent) & "$#$# $#\n") % [ left, spaces(longestLeft - left.len + 2), - $entry.procName + procname ]) let hint = getHint(entry) if hint.len > 0: @@ -457,9 +486,9 @@ when defined(chronosStackTrace): newMsg.add($entries) newMsg.add("Exception message: " & exceptionMsg & "\n") - newMsg.add("Exception type:") # # For debugging purposes + # newMsg.add("Exception type:") # for entry in getStackTraceEntries(future.error): # newMsg.add "\n" & $entry future.error.msg = newMsg