Compare commits

...

59 Commits

Author SHA1 Message Date
zah
fb03c4b937 Remove the use of usrToCell in gcMark [backport:1.2] (#17709)
* Remove the use of usrToCell in gcMark [backport:1.2]

Recently, we've discovered a GC crash resulting from inlining of
the memory allocation procs that allowed the compiler to avoid
maintaining any references to the "user pointer" on the stack.
Instead, a "cell pointer" appeared there and all field accesses
were performed with adjusted offsets. This interfered with the
ability of the GC to mark the correct cell in the conservative
stack scans which lead to premature collection of objects.

More details here:
af69b3ceae

This commit closes another theoretical loophole that may lead to
the same problem. If a short proc is accessing both the object and
its reference count in a short sequence of instructions, the compiler
may be enticed to reduce the number of registers being used by storing
only a single pointer to the object and using offsets when reading
and writing fields. A perfectly good strategy would be to store only
the cell pointer, so the reference count updates can be performed
without applying offsets. Accessing the fields of the object requires
offsets anyway, but these can be adjusted at compile-time without any
loss. Following this strategy will lead to the same problem of marking
a wrong cell during the conservative stack scan, leading to premature
collection.

The problem is avoided by not using `usrToCell` in `gcMark`. Since
the cell discovery logic can already handle interior pointers, the
user pointers don't need to be adjusted for the GC to function correctly.

(cherry picked from commit 3b47a689cf)
2021-04-14 12:10:39 +02:00
narimiran
ba8f657635 bump NimVersion to 1.2.12 2021-04-13 21:52:25 +02:00
narimiran
6238f2ee1e Revert "fixes #11225; generic sandwich problems; [backport:1.2] (#17255)"
This reverts commit d85b7dde7b.
2021-04-13 09:59:53 +02:00
narimiran
7aff6ded84 [ci skip] minor: fix indentation in manual.rst
(cherry picked from commit d3529d0d5a)
2021-03-31 13:42:48 +02:00
Miran
fe8b84496f [backport:1.2] Avoid inlining of newObj and newObjRC1 calls (#17582)
This is taken from:
af69b3ceae

Full original comment:

This is to avoid heavy inlining happening when two allocation calls
would occur shortly after each other.

This inlining would sometimes be accompanied with an optimisation
as the compiler is able to see that cellToUsr ending the first
allocation call is shortly followed by an usrToCell call. The
pointer arithmetic is redundant and the compiler can eliminate it,
leaving only the cell address in a register (and later the stack)
instead of the actual pointer to the user data, as one would expect.

This combined with a GC collect cycle will cause the stack scan to
only notice the cell address, which is of no good due to a usrToCell
in the gcMark call which shifts that address to an adjacent cell.
This means that the actual cell of importance will not get marked
and thus cause a premature collection of that cell. BOOM.

(cherry picked from commit 40093b4a93)
2021-03-30 11:47:39 +02:00
Danil Yarantsev
7f834c69fb Free the certificate after checking in checkCertName (#17558) [backport:1.2]
* Fix small leak in checkCertName
* Size is not needed either
* Free the certificate after checking

(cherry picked from commit b36182b0a4)
2021-03-29 15:34:11 +02:00
Timothee Cour
9a58bddc55 fix #17454 (#17461)
(cherry picked from commit d78ebe4a0e)
2021-03-29 15:34:03 +02:00
narimiran
9ebf537341 bump NimVersion to 1.2.11 2021-03-26 09:02:54 +01:00
narimiran
5ea5d82507 Revert "fixes #15210 [backport:1.2] (#15237)"
This reverts commit ae688aa7f5.
2021-03-22 11:52:22 +01:00
Andreas Rumpf
d85b7dde7b fixes #11225; generic sandwich problems; [backport:1.2] (#17255)
* fixes #11225; generic sandwich problems; [backport:1.2]
* progress
* delegating these symbols must be done via 'bind'

(cherry picked from commit 2f213db7ee)
2021-03-20 08:44:04 +01:00
Igor Ribeiro de Assis
1d301e354f Fix FutureStream memory usage (#17395) [backport:1.2]
(cherry picked from commit 9bb0e55749)
2021-03-18 17:46:59 +01:00
xioren
a7570ff0c2 Relocate 4xx/5xx exception in downloadFile (#17332) [backport:1.2]
Move 4xx/5xx exception to before disk i/o. As it stands an empty file is created on http error 4xx/5xx.

(cherry picked from commit 3d198fdcc2)
2021-03-18 17:30:15 +01:00
alaviss
86c8977726 compiler/installer.ini: package cacert.pem on Windows [backport:1.2] (#17172)
Follow up of 5dc544e1f5

After updating windeps.zip, it appears that Windows' build was
unchanged. As it turns out, cacert.pem is not set for packaging by the
compiler package manifest.

This commit add cacert.pem to the Windows package.

(cherry picked from commit d35f366d6f)
2021-03-18 17:25:41 +01:00
Andreas Rumpf
2ee078cdf8 fixes yet another SSL problem on Windows [backport:1.2] (#17167)
(cherry picked from commit b48a32053f)
2021-03-18 17:24:37 +01:00
narimiran
ebc114c526 Revert "fix #17118 (#17119) [backport:1.2]"
This reverts commit 2e896e3360.
2021-02-22 13:51:01 +01:00
narimiran
6da0bf80c3 bump NimVersion to 1.2.10 2021-02-22 10:31:38 +01:00
flywind
2e896e3360 fix #17118 (#17119) [backport:1.2]
* fix js unsigned integer
* Use `std` prefix for standard library modules
* fix #17118

(cherry picked from commit 32bf10126c)
2021-02-22 10:31:14 +01:00
Miran
d922751d98 [backport:1.2] update nimble commit hash (#17109)
(cherry picked from commit da52e81327)
2021-02-19 20:38:09 +01:00
Andreas Rumpf
ca1f97951c fixes #17085 [backport:1.2] (#17101)
(cherry picked from commit 4395a26764)
2021-02-19 20:36:13 +01:00
Benoit Favre
a48abc262c Fix bug in removeDotSegments when path ends with dot (#17038) [backport:1.2]
(cherry picked from commit 8f54d3b792)
2021-02-17 18:39:34 +01:00
narimiran
c18726f4a1 correctly backport pragmas changes 2021-02-09 20:23:13 +01:00
Miran
965b37ab4a [backport:1.2] update the nimble commit hash to the latest one (#16971)
(cherry picked from commit 0d34345f29)
2021-02-09 19:09:37 +01:00
narimiran
7deedd3601 remove 'tsugar' 2021-02-09 17:33:38 +01:00
Andreas Rumpf
2db37e2e0e final SSL changes [backport:1.2] (#16983)
(cherry picked from commit 74d6a4d7f4)
2021-02-09 15:45:05 +01:00
hlaaftana
aa98aee18d Remove declPragmas from lambdas [backport:1.0] (#16966)
* Remove declPragmas from lambdas [backport:1.0]

* add test for exportc

* fix test

* fix align, nodecl -> noinit

(cherry picked from commit 49b64e8dc7)
2021-02-09 15:44:29 +01:00
hlaaftana
3fb7979211 fix #16967 [backport:1.2] (#16976)
* fix #16967 [backport:1.2]

* move test to tsugar

(cherry picked from commit 49ee2f7f3b)
2021-02-09 15:41:34 +01:00
narimiran
5ffa88e7e0 enable 'protobuf' 2021-02-09 15:40:26 +01:00
narimiran
5788d288ad disable 'protobuf' package 2021-02-08 18:45:45 +01:00
Andreas Rumpf
793bd0a977 basic cleanups regarding SSL handling (#16940) [backport:1.0]
* basic cleanups regarding SSL handling
* enabled certificate checking on Windows
* updated the SSL test
* quoting helps

(cherry picked from commit abac35e743)
2021-02-08 17:26:07 +01:00
Andreas Rumpf
90cf7177ca fixes #16897 [backport:1.2] (#16900)
(cherry picked from commit 91ace2188a)
2021-02-02 14:35:54 +01:00
narimiran
98894e5e07 disable unsupported packages 2021-02-02 08:46:29 +01:00
Timothee Cour
040adf415b [backport 1.0] add backend support for js bigint (#16606)
* add backend support for js bigint

* cleanup

* add tests

* add -d:nimHasJsBigIntBackend

* cleanup

* more tests

(cherry picked from commit 025ca660f7)
2021-02-01 15:24:46 +01:00
Timothee Cour
bdb3cc3a8a [backport => 1.0] fix #16428 vmops now works for generic procs (#16429)
* fix #16428 vmops now works for generic procs

* remove duplication

(cherry picked from commit bc84d9c8cb)
2021-02-01 15:23:58 +01:00
Code Hz
435eca6232 removing out T from docs since it no longer working (#16378) [backport]
* remove `out T` from docs

see https://github.com/nim-lang/Nim/issues/16131

* remove `out T` in title
* remove entire paragraph

(cherry picked from commit 90dbb6f3fb)
2021-02-01 15:23:23 +01:00
Araq
6d75a9c996 better documentation
(cherry picked from commit cb19dc53ca)
2020-12-27 15:06:09 +01:00
Tomohiro
6e0c052509 Fix osproc so that it doesn't close pipe/process/thread handles twice (#16385) [backport]
* Add error check to closeHandle and fix closing handle twice in osproc

* Fix compile error on Linux

(cherry picked from commit dcdbae798c)
2020-12-19 14:28:53 +01:00
Andreas Rumpf
c5bf0d6fa9 fixes #16359 [backport] (#16377)
(cherry picked from commit b87bcb6d92)
2020-12-19 14:23:11 +01:00
Andreas Rumpf
2b9c458692 OSX: support for M1 [backport:1.0] (#16279)
(cherry picked from commit 94bb816de3)
2020-12-19 14:21:50 +01:00
Andreas Rumpf
28049053e8 fixes #16214 [backport] (#16252)
(cherry picked from commit edce5897a5)
2020-12-19 14:16:16 +01:00
Timothee Cour
a82cfb2d54 simplify toHex (#15821)
(cherry picked from commit 235e4930ab)
2020-12-07 15:47:36 +01:00
Miran
e3810646eb fix toHex - make it work with int literals (#15770)
(cherry picked from commit c0fdc8b215)
2020-12-07 15:47:26 +01:00
Andreas Rumpf
0888ac4097 fixes #16069; [backport:1.2] [backport:1.4] (#16115)
* fixes #16069; refs https://github.com/nim-lang/RFCs/issues/257 [backport:1.2] [backport:1.4]

* make tests green again

(cherry picked from commit d306a04466)
2020-11-26 08:09:49 +01:00
narimiran
c2982d5a9d re-enable telebot 2020-11-25 16:03:50 +01:00
Euan
212dcafcaa Fix FreeBSD build failures (#15613)
The FreeBSD is/was failing, due to a conflict with installing Git.

Git is guaranteed to be in the base image, so this removes that package from the package list. It also reverts back to the built-in `packages` tag since it's officially supported.

Should the build fail in the future, the best place to go is the #sr.ht channel on freenode.

(cherry picked from commit ba2a477e64)
2020-11-25 16:03:11 +01:00
narimiran
f04c8f0ba4 disable failing packages 2020-11-25 15:30:53 +01:00
Araq
67bdbb676e fixes 'nim doc'
(cherry picked from commit 19d52033f8)
2020-11-25 15:30:23 +01:00
flywind
93552e2e31 fix rope index (#16100)
* fix rope index

* add testcase

(cherry picked from commit ab2c082cb3)
2020-11-25 13:49:47 +01:00
ee7
1ee94744e3 CI(actions): Replace deprecated add-path commands (#15892)
This commit resolves the following warning in the CI logs:

> Error: The `add-path` command is deprecated and will be disabled soon.
> Please upgrade to using Environment Files. For more information see:
> https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/

The deprecation is due to an injection vulnerability (CVE-2020-15228).

See:
- https://bugs.chromium.org/p/project-zero/issues/detail?id=2070
- https://github.com/nim-lang/Nim/runs/1373146963#step:8:1

(cherry picked from commit 3948b40bcd)
2020-11-25 13:39:55 +01:00
flywind
db70fec7ca fix #16103 (#16109) [backport:1.0]
* fix #16103

* docs

(cherry picked from commit 823a71380d)
2020-11-25 13:02:20 +01:00
flywind
252bebd16e fix ropes format errors (#16106) [backport:1.0]
* fix rope index

* add testcase

* fix ropes format

(cherry picked from commit 0c6c4be0e7)
2020-11-25 13:02:02 +01:00
flywind
a27459fc08 fix #9695 asyncmacro: tfuturevar fails when activated [backport: 1.0] (#16090)
* fix asyncmacro

* Apply suggestions from code review

* Update lib/pure/asyncmacro.nim

(cherry picked from commit 6f1a72069a)
2020-11-25 12:59:01 +01:00
Andreas Rumpf
8c3f500338 fixes #15942 [backport:1.2] [backport:1.4] (#16051)
(cherry picked from commit 1efd11e266)
2020-11-25 12:58:49 +01:00
Andreas Rumpf
9af27994c9 makes parsesql .gcsafe [backport:1.0] (#16039)
(cherry picked from commit 743f2f5faa)
2020-11-25 12:58:35 +01:00
Igor Ribeiro de Assis
ee6b9d37c0 Do not read the whole file to compute SHA1 hash (fixes 15997) (#16006)
* Do not read the whole file to compute SHA1 hash (fixes 15997)

* Update lib/std/sha1.nim

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>

* Update lib/std/sha1.nim

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>

* Directly break from loop

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>

 [backport:1.2] [backport:1.4]

(cherry picked from commit baaa19b927)
2020-11-25 12:58:23 +01:00
Andreas Rumpf
71c0b6e76c asynchttpserver cleanups [backport:1.0] (#15966)
* asynchttpserver cleanups [backport:1.0]

(cherry picked from commit 122f22d163)
2020-11-25 12:57:21 +01:00
Araq
b3a12b4e3f attempt to make asynchttpserver better; fixes #15925; [backport:1.0]
(cherry picked from commit 8778d4a6f3)
2020-11-25 12:54:07 +01:00
Bung
a832fa65c4 Fix #8404 JS backend doesn't handle float->int type conversion (#15950) [backport]
* Fix #8404 JS backend doesn't handle float->int type conversion
* handle conv to uint as cast, discard other cases
* limit to int32, times use int64
* toInt including tyInt64 break times timezones lib, ignore for now
* also affect to vm
* move to tests/misc/t8404.nim

(cherry picked from commit 797cb2e67b)
2020-11-25 12:52:23 +01:00
Christopher Dunn
6c5eaa955d Fix a problem for long symlinks in conda (#15908) [backport]
* d8c80ea69d (diff-e1d8e552330911f9f779f85b6f2c00a15e790dcc3fbb3b28f5da1d660a30c5b8)

(cherry picked from commit c6ceefea6d)
2020-11-25 12:52:10 +01:00
narimiran
e9e93bd0ca bump NimVersion to 1.2.9 2020-11-25 12:47:35 +01:00
64 changed files with 662 additions and 268 deletions

View File

@@ -1,25 +1,19 @@
# see https://man.sr.ht/builds.sr.ht/compatibility.md#freebsd
image: freebsd/latest
# packages:
# - databases/sqlite3
# - devel/boehm-gc-threaded
# - devel/pcre
# - devel/sdl20
# - devel/sfml
# - www/node
# - devel/gmake
# - devel/git
packages:
- databases/sqlite3
- devel/boehm-gc-threaded
- devel/pcre
- devel/sdl20
- devel/sfml
- www/node
- devel/gmake
sources:
- https://github.com/nim-lang/Nim
environment:
CC: /usr/bin/clang
tasks:
- setup: |
# workaround https://github.com/timotheecour/Nim/issues/76
sudo pkg update -q -f
sudo pkg install -y -q databases/sqlite3 devel/boehm-gc-threaded devel/pcre \
devel/sdl20 devel/sfml www/node devel/gmake devel/git
cd Nim
git clone --depth 1 -q https://github.com/nim-lang/csources.git
gmake -C csources -j $(sysctl -n hw.ncpu)

View File

@@ -85,11 +85,11 @@ jobs:
curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip
7z x dist/mingw64.7z -odist
7z x dist/dlls.zip -obin
echo "::add-path::${{ github.workspace }}/dist/mingw64/bin"
echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
- name: 'Add build binaries to PATH'
shell: bash
run: echo "::add-path::${{ github.workspace }}/bin"
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
- name: 'Build csources'
shell: bash

View File

@@ -49,11 +49,11 @@ jobs:
curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip
7z x dist/mingw64.7z -odist
7z x dist/dlls.zip -obin
echo "::add-path::${{ github.workspace }}/dist/mingw64/bin"
echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
- name: 'Add build binaries to PATH'
shell: bash
run: echo "::add-path::${{ github.workspace }}/bin"
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
- name: 'Get current csources version'
id: csources-version

View File

@@ -47,11 +47,11 @@ jobs:
curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip
7z x dist/mingw64.7z -odist
7z x dist/dlls.zip -obin
echo "::add-path::${{ github.workspace }}/dist/mingw64/bin"
echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
- name: 'Add build binaries to PATH'
shell: bash
run: echo "::add-path::${{ github.workspace }}/bin"
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
- name: 'Build 1-stage compiler from csources'
shell: bash

View File

@@ -125,6 +125,20 @@
Proc `rightSize` for Tables and HashSets is deprecated, as it is not needed anymore.
`CountTable.inc` takes `val: int` again not `val: Positive`; I.e. it can "count down" again.
- Removed deprecated symbols from `macros` module, deprecated as far back as `0.15`.
- On Windows the SSL library now checks for valid certificates.
It uses the `cacert.pem` file for this purpose which was extracted
from `https://curl.se/ca/cacert.pem`. Besides
the OpenSSL DLLs (e.g. libssl-1_1-x64.dll, libcrypto-1_1-x64.dll) you
now also need to ship `cacert.pem` with your `.exe` file.
- Make `{.requiresInit.}` pragma to work for `distinct` types.
- Added `asyncdispatch.activeDescriptors` that returns the number of currently
active async event handles/file descriptors
- Added `asyncdispatch.maxDescriptors` that returns the maximum number of
active async event handles/file descriptors.
## Language changes

View File

@@ -1085,7 +1085,7 @@ proc safeLen*(n: PNode): int {.inline.} =
proc safeArrLen*(n: PNode): int {.inline.} =
## works for array-like objects (strings passed as openArray in VM).
if n.kind in {nkStrLit..nkTripleStrLit}:result = n.strVal.len
if n.kind in {nkStrLit..nkTripleStrLit}: result = n.strVal.len
elif n.kind in {nkNone..nkFloat128Lit}: result = 0
else: result = n.len

View File

@@ -833,6 +833,7 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
[rdLoc(test), strLit, raiseInstr(p)])
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
assert e[0].kind == nkDotExpr
if optFieldCheck in p.options:
var a: TLoc
genRecordFieldAux(p, e[0], d, a)
@@ -1981,30 +1982,25 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) =
checkUnsignedConversions notin p.config.legacyFeatures):
discard "no need to generate a check because it was disabled"
else:
let raiser =
case skipTypes(n.typ, abstractVarRange).kind
of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
of tyFloat..tyFloat128: "raiseRangeErrorF"
else: "raiseRangeErrorI"
discard cgsym(p.module, raiser)
# This seems to be bug-compatible with Nim version 1 but what we
# should really do here is to check if uint64Value < high(int)
let n0t = n[0].typ
let boundaryCast =
if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64} or
(n0t.sym != nil and sfSystemModule in n0t.sym.owner.flags and n0t.sym.name.s == "csize"):
"(NI64)"
else:
""
# emit range check:
if n0t.kind in {tyUInt, tyUInt64}:
linefmt(p, cpsStmts, "if ($1 > ($6)($3)){ #raiseRangeErrorNoArgs(); $5}$n",
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
raiser, raiseInstr(p), getTypeDesc(p.module, n0t)])
else:
let raiser =
case skipTypes(n.typ, abstractVarRange).kind
of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
of tyFloat..tyFloat128: "raiseRangeErrorF"
else: "raiseRangeErrorI"
discard cgsym(p.module, raiser)
let boundaryCast =
if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64} or
(n0t.sym != nil and sfSystemModule in n0t.sym.owner.flags and n0t.sym.name.s == "csize"):
"(NI64)"
else:
""
linefmt(p, cpsStmts, "if ($6($1) < $2 || $6($1) > $3){ $4($1, $2, $3); $5}$n",
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
raiser, raiseInstr(p), boundaryCast])
linefmt(p, cpsStmts, "if ($6($1) < $2 || $6($1) > $3){ $4($1, $2, $3); $5}$n",
[rdCharLoc(a), genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
raiser, raiseInstr(p), boundaryCast])
putIntoDest(p, d, n, "(($1) ($2))" %
[getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage)
@@ -2670,7 +2666,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
expr(p, n[1][0], d)
of nkObjDownConv: downConv(p, n, d)
of nkObjUpConv: upConv(p, n, d)
of nkChckRangeF, nkChckRange64, nkChckRange: genRangeChck(p, n, d)
of nkChckRangeF: genRangeChck(p, n, d)
of nkChckRange64: genRangeChck(p, n, d)
of nkChckRange: genRangeChck(p, n, d)
of nkStringToCString: convStrToCStr(p, n, d)
of nkCStringToString: convCStrToStr(p, n, d)
of nkLambdaKinds:

View File

@@ -25,10 +25,10 @@ proc getTraverseProc(p: BProc, v: PSym): Rope =
proc registerTraverseProc(p: BProc, v: PSym, traverseProc: Rope) =
if sfThread in v.flags:
appcg(p.module, p.module.initProc.procSec(cpsInit),
appcg(p.module, p.module.preInitProc.procSec(cpsInit),
"$n\t#nimRegisterThreadLocalMarker($1);$n$n", [traverseProc])
else:
appcg(p.module, p.module.initProc.procSec(cpsInit),
appcg(p.module, p.module.preInitProc.procSec(cpsInit),
"$n\t#nimRegisterGlobalMarker($1);$n$n", [traverseProc])
proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =

View File

@@ -244,7 +244,7 @@ proc safeLineNm(info: TLineInfo): int =
proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
assert line >= 0
if optLineDir in conf.options:
if optLineDir in conf.options and line > 0:
r.addf("$N#line $2 $1$N",
[rope(makeSingleLineCString(filename)), rope(line)])
@@ -1645,7 +1645,7 @@ proc genInitCode(m: BModule) =
writeSection(preInitProc, cpsLocals)
writeSection(preInitProc, cpsInit, m.hcrOn)
writeSection(preInitProc, cpsStmts)
prc.addf("}$N", [])
prc.addf("}/* preInitProc end */$N", [])
# add new scope for following code, because old vcc compiler need variable
# be defined at the top of the block

View File

@@ -117,3 +117,4 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasInvariant")
defineSymbol("nimHasStacktraceMsgs")
defineSymbol("nimHasStacktracesModule")
defineSymbol("nimHasJsBigIntBackend")

View File

@@ -6,12 +6,12 @@ Name: "Nim"
Version: "$version"
Platforms: """
windows: i386;amd64
linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv64
macosx: i386;amd64;powerpc64
linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv32;riscv64
macosx: i386;amd64;powerpc64;arm64
solaris: i386;amd64;sparc;sparc64
freebsd: i386;amd64;powerpc64;arm;arm64
freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el
netbsd: i386;amd64
openbsd: i386;amd64
openbsd: i386;amd64;arm;arm64
dragonfly: i386;amd64
haiku: i386;amd64
android: i386;arm;arm64
@@ -111,6 +111,7 @@ Download: r"Aporia Text Editor|dist|aporia.zip|97997|https://nim-lang.org/downlo
Files: "bin/makelink.exe"
Files: "bin/7zG.exe"
Files: "bin/*.dll"
Files: "bin/cacert.pem"
[UnixBin]
Files: "bin/nim"

View File

@@ -1591,7 +1591,10 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
var t = skipTypes(typ, abstractInst)
case t.kind
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar:
result = putToSeq("0", indirect)
if $t.sym.loc.r == "bigint":
result = putToSeq("0n", indirect)
else:
result = putToSeq("0", indirect)
of tyFloat..tyFloat128:
result = putToSeq("0.0", indirect)
of tyRange, tyGenericInst, tyAlias, tySink, tyOwned:
@@ -2124,11 +2127,17 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) =
if dest.kind == src.kind:
# no-op conversion
return
case dest.kind:
of tyBool:
let toInt = (dest.kind in tyInt..tyInt32)
let fromInt = (src.kind in tyInt..tyInt32)
let toUint = (dest.kind in tyUInt..tyUInt32)
let fromUint = (src.kind in tyUInt..tyUInt32)
if toUint and (fromInt or fromUint):
let trimmer = unsignedTrimmer(dest.size)
r.res = "($1 $2)" % [r.res, trimmer]
elif dest.kind == tyBool:
r.res = "(!!($1))" % [r.res]
r.kind = resExpr
of tyInt:
elif toInt:
r.res = "(($1)|0)" % [r.res]
else:
# TODO: What types must we handle here?

View File

@@ -22,7 +22,7 @@ type
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx,
osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osAny
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osFreeRTOS, osAny
type
TInfoOSProp* = enum
@@ -177,6 +177,10 @@ const
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".",
props: {ospNeedsPIC, ospPosix}),
(name: "FreeRTOS", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
props: {ospPosix}),
(name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
@@ -189,7 +193,7 @@ type
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
cpuPowerpc64el, cpuSparc, cpuVm, cpuHppa, cpuIa64, cpuAmd64, cpuMips,
cpuMipsel, cpuArm, cpuArm64, cpuJS, cpuNimVM, cpuAVR, cpuMSP430,
cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV64, cpuWasm32
cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV32, cpuRiscV64, cpuEsp, cpuWasm32
type
TEndian* = enum
@@ -222,7 +226,9 @@ const
(name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
(name: "mips64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
(name: "mips64el", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
(name: "riscv32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
(name: "riscv64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
(name: "esp", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
(name: "wasm32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32)]
type

View File

@@ -20,7 +20,7 @@ const
const
declPragmas = {wImportc, wImportObjC, wImportCpp, wImportJs, wExportc, wExportCpp,
wExportNims, wExtern, wDeprecated, wNodecl, wError, wUsed, wAlign}
wExportNims, wExtern, wDeprecated, wNodecl, wError, wUsed}
## common pragmas for declarations, to a good approximation
procPragmas* = declPragmas + {FirstCallConv..LastCallConv,
wMagic, wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader,
@@ -54,22 +54,22 @@ const
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wLinearScanEnd, wPatterns, wTrMacros, wEffects, wNoForward, wReorder, wComputedGoto,
wInjectStmt, wExperimental, wThis, wUsed, wInvariant, wAssume}
lambdaPragmas* = declPragmas + {FirstCallConv..LastCallConv,
lambdaPragmas* = {FirstCallConv..LastCallConv,
wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader,
wThread, wAsmNoStackFrame,
wRaises, wLocks, wTags, wRequires, wEnsures,
wGcSafe, wCodegenDecl} - {wExportNims, wError, wUsed} # why exclude these?
wGcSafe, wCodegenDecl, wNoInit}
typePragmas* = declPragmas + {wMagic, wAcyclic,
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow,
wIncompleteStruct, wByCopy, wByRef,
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
wBorrow, wGcSafe, wPartial, wExplain, wPackage}
fieldPragmas* = declPragmas + {
wGuard, wBitsize, wCursor, wRequiresInit} - {wExportNims, wNodecl} # why exclude these?
fieldPragmas* = declPragmas + {wGuard, wBitsize, wCursor,
wRequiresInit, wAlign} - {wExportNims, wNodecl} # why exclude these?
varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar,
wMagic, wHeader, wCompilerProc, wCore, wDynlib,
wNoInit, wCompileTime, wGlobal,
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor}
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor, wAlign}
constPragmas* = declPragmas + {wHeader, wMagic,
wGensym, wInject,
wIntDefine, wStrDefine, wBoolDefine, wCompilerProc, wCore}

View File

@@ -715,6 +715,9 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
result.typ = n.typ
of nkBracketExpr: result = foldArrayAccess(m, n, g)
of nkDotExpr: result = foldFieldAccess(m, n, g)
of nkCheckedFieldExpr:
assert n[0].kind == nkDotExpr
result = foldFieldAccess(m, n[0], g)
of nkStmtListExpr:
var i = 0
while i <= n.len - 2:

View File

@@ -1028,6 +1028,11 @@ proc transform(c: PTransf, n: PNode): PNode =
return n
of nkExceptBranch:
result = transformExceptBranch(c, n)
of nkCheckedFieldExpr:
result = transformSons(c, n)
if result[0].kind != nkDotExpr:
# simplfied beyond a dot expression --> simplify further.
result = result[0]
else:
result = transformSons(c, n)
when false:

View File

@@ -173,6 +173,6 @@ proc extractRange*(k: TNodeKind, n: PNode, a, b: int): PNode =
proc dontInlineConstant*(orig, cnst: PNode): bool {.inline.} =
# symbols that expand to a complex constant (array, etc.) should not be
# inlined, unless it's the empty array:
result = orig.kind == nkSym and
result = orig.kind != cnst.kind and
cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket, nkObjConstr} and
cnst.len > ord(cnst.kind == nkObjConstr)

View File

@@ -71,7 +71,7 @@ const
tyInferred, tySink, tyLent, tyOwned}
# typedescX is used if we're sure tyTypeDesc should be included (or skipped)
typedescPtrs* = abstractPtrs + {tyTypeDesc}
typedescInst* = abstractInst + {tyTypeDesc, tyOwned}
typedescInst* = abstractInst + {tyTypeDesc, tyOwned, tyUserTypeClass}
proc invalidGenericInst*(f: PType): bool =
result = f.kind == tyGenericInst and lastSon(f) == nil

View File

@@ -1959,14 +1959,6 @@ proc genProc*(c: PCtx; s: PSym): int
proc matches(s: PSym; x: string): bool =
let y = x.split('.')
var s = s
for i in 1..y.len:
if s == nil or (y[^i].cmpIgnoreStyle(s.name.s) != 0 and y[^i] != "*"):
return false
s = s.owner
result = true
proc matches(s: PSym; y: varargs[string]): bool =
var s = s
for i in 1..y.len:
if s == nil or (y[^i].cmpIgnoreStyle(s.name.s) != 0 and y[^i] != "*"):
@@ -2027,11 +2019,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
elif s.kind == skMethod:
localError(c.config, n.info, "cannot call method " & s.name.s &
" at compile time")
elif matches(s, "stdlib", "marshal", "to"):
elif matches(s, "stdlib.marshal.to"):
# XXX marshal load&store should not be opcodes, but use the
# general callback mechanisms.
genMarshalLoad(c, n, dest)
elif matches(s, "stdlib", "marshal", "$$"):
elif matches(s, "stdlib.marshal.$$"):
genMarshalStore(c, n, dest)
else:
genCall(c, n, dest)

View File

@@ -2483,9 +2483,10 @@ matches) is preferred:
Overloading based on 'var T'
----------------------------
If the formal parameter ``f`` is of type ``var T`` in addition to the ordinary
type checking, the argument is checked to be an `l-value`:idx:. ``var T``
matches better than just ``T`` then.
If the formal parameter ``f`` is of type ``var T``
in addition to the ordinary type checking,
the argument is checked to be an `l-value`:idx:.
``var T`` matches better than just ``T`` then.
.. code-block:: nim
proc sayHi(x: int): string =
@@ -5714,12 +5715,12 @@ avoid ambiguity when there are multiple modules with the same path.
There are two pseudo directories:
1. ``std``: The ``std`` pseudo directory is the abstract location of Nim's standard
library. For example, the syntax ``import std / strutils`` is used to unambiguously
refer to the standard library's ``strutils`` module.
library. For example, the syntax ``import std / strutils`` is used to unambiguously
refer to the standard library's ``strutils`` module.
2. ``pkg``: The ``pkg`` pseudo directory is used to unambiguously refer to a Nimble
package. However, for technical details that lie outside of the scope of this document
its semantics are: *Use the search path to look for module name but ignore the standard
library locations*. In other words, it is the opposite of ``std``.
package. However, for technical details that lie outside of the scope of this document
its semantics are: *Use the search path to look for module name but ignore the standard
library locations*. In other words, it is the opposite of ``std``.
From import statement
@@ -5981,10 +5982,10 @@ noSideEffect pragma
The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side
effects. This means that the proc/iterator only changes locations that are
reachable from its parameters and the return value only depends on the
arguments. If none of its parameters have the type ``var T``
or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static
error to mark a proc/iterator to have no side effect if the compiler cannot
verify this.
arguments. If none of its parameters have the type ``var T`` or ``ref T``
or ``ptr T`` this means no locations are modified. It is a static error to
mark a proc/iterator to have no side effect if the compiler cannot verify
this.
As a special semantic rule, the built-in `debugEcho
<system.html#debugEcho,varargs[typed,]>`_ pretends to be free of side effects,

View File

@@ -10,7 +10,7 @@
#
const
NimbleStableCommit = "8f7af860c5ce9634af880a7081c6435e1f2a5148" # master
NimbleStableCommit = "d13f3b8ce288b4dc8c34c219a4e050aaeaf43fc9" # master
when not defined(windows):
const

View File

@@ -1262,7 +1262,15 @@ proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} =
else:
badNodeKind someProc, "body="
proc basename*(a: NimNode): NimNode {.compileTime, benign.}
proc basename*(a: NimNode): NimNode {.raises: [].} =
## Pull an identifier from prefix/postfix expressions.
case a.kind
of nnkIdent: result = a
of nnkPostfix, nnkPrefix: result = a[1]
of nnkPragmaExpr: result = basename(a[0])
else:
error("Do not know how to get basename of (" & treeRepr(a) & ")\n" &
repr(a), a)
proc `$`*(node: NimNode): string {.compileTime.} =
## Get the string of an identifier node.
@@ -1325,16 +1333,6 @@ proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} =
a[i + 1] = a[i]
a[pos] = b
proc basename*(a: NimNode): NimNode =
## Pull an identifier from prefix/postfix expressions.
case a.kind
of nnkIdent: result = a
of nnkPostfix, nnkPrefix: result = a[1]
of nnkPragmaExpr: result = basename(a[0])
else:
error("Do not know how to get basename of (" & treeRepr(a) & ")\n" &
repr(a), a)
proc `basename=`*(a: NimNode; val: string) {.compileTime.}=
case a.kind
of nnkIdent:

View File

@@ -62,7 +62,6 @@ from pcre import nil
import nre/private/util
import tables
from strutils import `%`
from math import ceil
import options
from unicode import runeLenAt
@@ -734,8 +733,25 @@ proc replace*(str: string, pattern: Regex, sub: string): string =
replaceImpl(str, pattern,
formatStr(sub, match.captures[name], match.captures[id - 1]))
let SpecialCharMatcher = re"([\\+*?[^\]$(){}=!<>|:-])"
proc escapeRe*(str: string): string =
## Escapes the string so it doesnt match any special characters.
proc escapeRe*(str: string): string {.gcsafe.} =
## Escapes the string so it doesn't match any special characters.
## Incompatible with the Extra flag (``X``).
str.replace(SpecialCharMatcher, "\\$1")
##
## Escaped char: `\ + * ? [ ^ ] $ ( ) { } = ! < > | : -`
runnableExamples:
doAssert escapeRe("fly+wind") == "fly\\+wind"
doAssert escapeRe("!") == "\\!"
doAssert escapeRe("nim*") == "nim\\*"
#([\\+*?[^\]$(){}=!<>|:-])
const SpecialCharMatcher = {'\\', '+', '*', '?', '[', '^', ']', '$', '(',
')', '{', '}', '=', '!', '<', '>', '|', ':',
'-'}
for c in items(str):
case c
of SpecialCharMatcher:
result.add("\\")
result.add(c)
else:
result.add(c)

View File

@@ -1892,3 +1892,25 @@ proc waitFor*[T](fut: Future[T]): T =
poll()
fut.read
proc activeDescriptors*(): int {.inline.} =
## Returns the current number of active file descriptors for the current
## event loop. This is a cheap operation that does not involve a system call.
when defined(windows):
result = getGlobalDispatcher().handles.len
elif not defined(nimdoc):
result = getGlobalDispatcher().selector.count
when defined(posix):
import posix
proc maxDescriptors*(): int {.raises: OSError.} =
## Returns the maximum number of active file descriptors for the current
## process. This involves a system call.
when defined(windows):
result = 16_700_000
else:
var fdLim: RLimit
if getrlimit(RLIMIT_NOFILE, fdLim) < 0:
raiseOSError(osLastError())
result = int(fdLim.rlim_cur) - 1

View File

@@ -11,24 +11,36 @@
##
## This HTTP server has not been designed to be used in production, but
## for testing applications locally. Because of this, when deploying your
## application you should use a reverse proxy (for example nginx) instead of
## allowing users to connect directly to this server.
## application in production you should use a reverse proxy (for example nginx)
## instead of allowing users to connect directly to this server.
##
## Basic usage
## ===========
## Example
## =======
##
## This example will create an HTTP server on port 8080. The server will
## respond to all requests with a ``200 OK`` response code and "Hello World"
## as the response body.
##
## .. code-block::nim
## import asynchttpserver, asyncdispatch
## .. code-block:: Nim
##
## var server = newAsyncHttpServer()
## proc cb(req: Request) {.async.} =
## await req.respond(Http200, "Hello World")
## import asynchttpserver, asyncdispatch
##
## waitFor server.serve(Port(8080), cb)
## proc main {.async.} =
## var server = newAsyncHttpServer()
## proc cb(req: Request) {.async.} =
## let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT",
## "Content-type": "text/plain; charset=utf-8"}
## await req.respond(Http200, "Hello World", headers.newHttpHeaders())
##
## server.listen Port(8080)
## while true:
## if server.shouldAcceptRequest():
## asyncCheck server.acceptRequest(cb)
## else:
## poll()
##
## asyncCheck main()
## runForever()
import asyncnet, asyncdispatch, parseutils, uri, strutils
import httpcore
@@ -58,14 +70,12 @@ type
reuseAddr: bool
reusePort: bool
maxBody: int ## The maximum content-length that will be read for the body.
maxFDs: int
proc newAsyncHttpServer*(reuseAddr = true, reusePort = false,
maxBody = 8388608): AsyncHttpServer =
## Creates a new ``AsyncHttpServer`` instance.
new result
result.reuseAddr = reuseAddr
result.reusePort = reusePort
result.maxBody = maxBody
result = AsyncHttpServer(reuseAddr: reuseAddr, reusePort: reusePort, maxBody: maxBody)
proc addHeaders(msg: var string, headers: HttpHeaders) =
for k, v in headers:
@@ -294,13 +304,9 @@ proc processClient(server: AsyncHttpServer, client: AsyncSocket, address: string
)
if not retry: break
proc serve*(server: AsyncHttpServer, port: Port,
callback: proc (request: Request): Future[void] {.closure, gcsafe.},
address = "") {.async.} =
## Starts the process of listening for incoming HTTP connections on the
## specified address and port.
##
## When a request is made by a client the specified callback will be called.
proc listen*(server: AsyncHttpServer; port: Port; address = "") =
## Listen to the given port and address.
server.maxFDs = maxDescriptors()
server.socket = newAsyncSocket()
if server.reuseAddr:
server.socket.setSockOpt(OptReuseAddr, true)
@@ -309,9 +315,44 @@ proc serve*(server: AsyncHttpServer, port: Port,
server.socket.bindAddr(port, address)
server.socket.listen()
proc shouldAcceptRequest*(server: AsyncHttpServer;
assumedDescriptorsPerRequest = 5): bool {.inline.} =
## Returns true if the process's current number of opened file
## descriptors is still within the maximum limit and so it's reasonable to
## accept yet another request.
result = assumedDescriptorsPerRequest < 0 or
(activeDescriptors() + assumedDescriptorsPerRequest < server.maxFDs)
proc acceptRequest*(server: AsyncHttpServer,
callback: proc (request: Request): Future[void] {.closure, gcsafe.}) {.async.} =
## Accepts a single request. Write an explicit loop around this proc so that
## errors can be handled properly.
var (address, client) = await server.socket.acceptAddr()
asyncCheck processClient(server, client, address, callback)
proc serve*(server: AsyncHttpServer, port: Port,
callback: proc (request: Request): Future[void] {.closure, gcsafe.},
address = "";
assumedDescriptorsPerRequest = -1) {.async.} =
## Starts the process of listening for incoming HTTP connections on the
## specified address and port.
##
## When a request is made by a client the specified callback will be called.
##
## If `assumedDescriptorsPerRequest` is 0 or greater the server cares about
## the process's maximum file descriptor limit. It then ensures that the
## process still has the resources for `assumedDescriptorsPerRequest`
## file descriptors before accepting a connection.
##
## You should prefer to call `acceptRequest` instead with a custom server
## loop so that you're in control over the error handling and logging.
listen server, port, address
while true:
var (address, client) = await server.socket.acceptAddr()
asyncCheck processClient(server, client, address, callback)
if shouldAcceptRequest(server, assumedDescriptorsPerRequest):
var (address, client) = await server.socket.acceptAddr()
asyncCheck processClient(server, client, address, callback)
else:
poll()
#echo(f.isNil)
#echo(f.repr)
@@ -320,7 +361,7 @@ proc close*(server: AsyncHttpServer) =
server.socket.close()
when not defined(testing) and isMainModule:
proc main =
proc main {.async.} =
var server = newAsyncHttpServer()
proc cb(req: Request) {.async.} =
#echo(req.reqMethod, " ", req.url)
@@ -329,6 +370,12 @@ when not defined(testing) and isMainModule:
"Content-type": "text/plain; charset=utf-8"}
await req.respond(Http200, "Hello World", headers.newHttpHeaders())
asyncCheck server.serve(Port(5555), cb)
runForever()
main()
server.listen Port(5555)
while true:
if server.shouldAcceptRequest():
asyncCheck server.acceptRequest(cb)
else:
poll()
asyncCheck main()
runForever()

View File

@@ -198,7 +198,8 @@ proc getFutureVarIdents(params: NimNode): seq[NimNode] {.compileTime.} =
for i in 1 ..< len(params):
expectKind(params[i], nnkIdentDefs)
if params[i][1].kind == nnkBracketExpr and
params[i][1][0].eqIdent("futurevar"):
params[i][1][0].eqIdent(FutureVar.astToStr):
## eqIdent: first char is case sensitive!!!
result.add(params[i][0])
proc isInvalidReturnType(typeName: string): bool =

View File

@@ -110,7 +110,11 @@ proc read*[T](future: FutureStream[T]): owned(Future[(bool, T)]) =
resFut.complete(res)
# If the saved callback isn't nil then let's call it.
if not savedCb.isNil: savedCb()
if not savedCb.isNil:
if fs.queue.len > 0:
savedCb()
else:
future.cb = savedCb
if future.queue.len > 0 or future.finished:
newCb(future)

View File

@@ -317,7 +317,7 @@ proc getDefaultSSL(): SslContext =
result = defaultSslContext
when defined(ssl):
if result == nil:
defaultSslContext = newContext(verifyMode = CVerifyNone)
defaultSslContext = newContext(verifyMode = CVerifyPeer)
result = defaultSslContext
doAssert result != nil, "failure to initialize the SSL context"
@@ -1140,15 +1140,15 @@ proc downloadFile*(client: HttpClient, url: string, filename: string) =
client.getBody = true
let resp = client.get(url)
if resp.code.is4xx or resp.code.is5xx:
raise newException(HttpRequestError, resp.status)
client.bodyStream = newFileStream(filename, fmWrite)
if client.bodyStream.isNil:
fileError("Unable to open file")
parseBody(client, resp.headers, resp.version)
client.bodyStream.close()
if resp.code.is4xx or resp.code.is5xx:
raise newException(HttpRequestError, resp.status)
proc downloadFile*(client: AsyncHttpClient, url: string,
filename: string): Future[void] =
proc downloadFileEx(client: AsyncHttpClient,

View File

@@ -114,7 +114,7 @@ proc osLastError*(): OSErrorCode {.sideEffect.} =
when defined(nimscript):
discard
elif defined(windows):
result = OSErrorCode(getLastError())
result = cast[OSErrorCode](getLastError())
else:
result = OSErrorCode(errno)
{.pop.}

View File

@@ -55,7 +55,7 @@ when hasThreadSupport:
maxFD: int
numFD: int
fds: ptr SharedArray[SelectorKey[T]]
count: int
count*: int
Selector*[T] = ptr SelectorImpl[T]
else:
type
@@ -64,7 +64,7 @@ else:
maxFD: int
numFD: int
fds: seq[SelectorKey[T]]
count: int
count*: int
Selector*[T] = ref SelectorImpl[T]
type
SelectEventImpl = object

View File

@@ -30,7 +30,7 @@ when defined(macosx) or defined(freebsd) or defined(dragonfly):
proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize_t,
newp: pointer, newplen: csize_t): cint
{.importc: "sysctl",header: """#include <sys/types.h>
#include <sys/sysctl.h>"""}
#include <sys/sysctl.h>""".}
elif defined(netbsd) or defined(openbsd):
# OpenBSD and NetBSD don't have KERN_MAXFILESPERPROC, so we are using
# KERN_MAXFILES, because KERN_MAXFILES is always bigger,
@@ -39,7 +39,7 @@ elif defined(netbsd) or defined(openbsd):
proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize_t,
newp: pointer, newplen: csize_t): cint
{.importc: "sysctl",header: """#include <sys/param.h>
#include <sys/sysctl.h>"""}
#include <sys/sysctl.h>""".}
when hasThreadSupport:
type
@@ -48,7 +48,7 @@ when hasThreadSupport:
maxFD: int
changes: ptr SharedArray[KEvent]
fds: ptr SharedArray[SelectorKey[T]]
count: int
count*: int
changesLock: Lock
changesSize: int
changesLength: int
@@ -61,7 +61,7 @@ else:
maxFD: int
changes: seq[KEvent]
fds: seq[SelectorKey[T]]
count: int
count*: int
sock: cint
Selector*[T] = ref SelectorImpl[T]

View File

@@ -21,7 +21,7 @@ when hasThreadSupport:
pollcnt: int
fds: ptr SharedArray[SelectorKey[T]]
pollfds: ptr SharedArray[TPollFd]
count: int
count*: int
lock: Lock
Selector*[T] = ptr SelectorImpl[T]
else:
@@ -31,7 +31,7 @@ else:
pollcnt: int
fds: seq[SelectorKey[T]]
pollfds: seq[TPollFd]
count: int
count*: int
Selector*[T] = ref SelectorImpl[T]
type

View File

@@ -58,7 +58,7 @@ when hasThreadSupport:
eSet: FdSet
maxFD: int
fds: ptr SharedArray[SelectorKey[T]]
count: int
count*: int
lock: Lock
Selector*[T] = ptr SelectorImpl[T]
else:
@@ -69,7 +69,7 @@ else:
eSet: FdSet
maxFD: int
fds: seq[SelectorKey[T]]
count: int
count*: int
Selector*[T] = ref SelectorImpl[T]
type

View File

@@ -22,6 +22,17 @@
## In order to use the SSL procedures defined in this module, you will need to
## compile your application with the ``-d:ssl`` flag.
##
##
## SSL on Windows
## ==============
##
## On Windows the SSL library checks for valid certificates.
## It uses the `cacert.pem` file for this purpose which was extracted
## from `https://curl.se/ca/cacert.pem`. Besides
## the OpenSSL DLLs (e.g. libssl-1_1-x64.dll, libcrypto-1_1-x64.dll) you
## also need to ship `cacert.pem` with your `.exe` file.
##
##
## Examples
## ========
##
@@ -572,7 +583,7 @@ when defineSsl:
if newCTX.SSL_CTX_set_cipher_list(cipherList) != 1:
raiseSSLError()
when defined(nimDisableCertificateValidation) or defined(windows):
when defined(nimDisableCertificateValidation):
newCTX.SSL_CTX_set_verify(SSL_VERIFY_NONE, nil)
else:
case verifyMode
@@ -587,11 +598,13 @@ when defineSsl:
discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
newCTX.loadCertificates(certFile, keyFile)
when not defined(nimDisableCertificateValidation) and not defined(windows):
const VerifySuccess = 1 # SSL_CTX_load_verify_locations returns 1 on success.
when not defined(nimDisableCertificateValidation):
if verifyMode != CVerifyNone:
# Use the caDir and caFile parameters if set
if caDir != "" or caFile != "":
if newCTX.SSL_CTX_load_verify_locations(caFile, caDir) != 0:
if newCTX.SSL_CTX_load_verify_locations(caFile, caDir) != VerifySuccess:
raise newException(IOError, "Failed to load SSL/TLS CA certificate(s).")
else:
@@ -599,7 +612,7 @@ when defineSsl:
# the SSL_CERT_FILE and SSL_CERT_DIR env vars
var found = false
for fn in scanSSLCertificates():
if newCTX.SSL_CTX_load_verify_locations(fn, "") == 0:
if newCTX.SSL_CTX_load_verify_locations(fn, nil) == VerifySuccess:
found = true
break
if not found:
@@ -716,10 +729,11 @@ when defineSsl:
raiseSSLError("No SSL certificate found.")
const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT = 0x1.cuint
const size = 1024
var peername: string = newString(size)
# https://www.openssl.org/docs/man1.1.1/man3/X509_check_host.html
let match = certificate.X509_check_host(hostname.cstring, hostname.len.cint,
X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT, peername)
X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT, nil)
# https://www.openssl.org/docs/man1.1.1/man3/SSL_get_peer_certificate.html
X509_free(certificate)
if match != 1:
raiseSSLError("SSL Certificate check failed.")

View File

@@ -1156,6 +1156,7 @@ when not defined(windows) and not weirdTarget:
else: result = S_ISLNK(rawInfo.st_mode)
const
maxSymlinkLen = 1024
ExeExts* = ## Platform specific file extension for executables.
## On Windows ``["exe", "cmd", "bat"]``, on Posix ``[""]``.
when defined(windows): ["exe", "cmd", "bat"] else: [""]
@@ -1197,11 +1198,11 @@ proc findExe*(exe: string, followSymlinks: bool = true;
when not defined(windows):
while followSymlinks: # doubles as if here
if x.checkSymlink:
var r = newString(256)
var len = readlink(x, r, 256)
var r = newString(maxSymlinkLen)
var len = readlink(x, r, maxSymlinkLen)
if len < 0:
raiseOSError(osLastError(), exe)
if len > 256:
if len > maxSymlinkLen:
r = newString(len+1)
len = readlink(x, r, len)
setLen(r, len)
@@ -2517,11 +2518,11 @@ proc expandSymlink*(symlinkPath: string): string {.noNimScript.} =
when defined(windows):
result = symlinkPath
else:
result = newString(256)
var len = readlink(symlinkPath, result, 256)
result = newString(maxSymlinkLen)
var len = readlink(symlinkPath, result, maxSymlinkLen)
if len < 0:
raiseOSError(osLastError(), symlinkPath)
if len > 256:
if len > maxSymlinkLen:
result = newString(len+1)
len = readlink(symlinkPath, result, len)
setLen(result, len)
@@ -2811,9 +2812,9 @@ when not weirdTarget and (defined(freebsd) or defined(dragonfly)):
when not weirdTarget and (defined(linux) or defined(solaris) or defined(bsd) or defined(aix)):
proc getApplAux(procPath: string): string =
result = newString(256)
var len = readlink(procPath, result, 256)
if len > 256:
result = newString(maxSymlinkLen)
var len = readlink(procPath, result, maxSymlinkLen)
if len > maxSymlinkLen:
result = newString(len+1)
len = readlink(procPath, result, len)
setLen(result, len)

View File

@@ -381,6 +381,8 @@ proc execProcesses*(cmds: openArray[string],
raiseOSError(err)
if rexit >= 0:
when defined(windows):
let processHandle = q[rexit].fProcessHandle
result = max(result, abs(q[rexit].peekExitCode()))
if afterRunEvent != nil: afterRunEvent(idxs[rexit], q[rexit])
close(q[rexit])
@@ -395,7 +397,7 @@ proc execProcesses*(cmds: openArray[string],
else:
when defined(windows):
for k in 0..wcount - 1:
if w[k] == q[rexit].fProcessHandle:
if w[k] == processHandle:
w[k] = w[wcount - 1]
w[wcount - 1] = 0
dec(wcount)
@@ -441,10 +443,17 @@ when defined(Windows) and not defined(useNimRtl):
handle: Handle
atTheEnd: bool
proc closeHandleCheck(handle: Handle) {.inline.} =
if handle.closeHandle() == 0:
raiseOSError(osLastError())
proc fileClose[T: Handle | FileHandle](h: var T) {.inline.} =
if h > 4:
closeHandleCheck(h)
h = INVALID_HANDLE_VALUE.T
proc hsClose(s: Stream) =
# xxx here + elsewhere: check instead of discard; ignoring errors leads to
# hard to track bugs
discard FileHandleStream(s).handle.closeHandle
FileHandleStream(s).handle.fileClose()
proc hsAtEnd(s: Stream): bool = return FileHandleStream(s).atTheEnd
@@ -549,8 +558,8 @@ when defined(Windows) and not defined(useNimRtl):
stdin = myDup(pipeIn, 0)
stdout = myDup(pipeOut, 0)
discard closeHandle(pipeIn)
discard closeHandle(pipeOut)
closeHandleCheck(pipeIn)
closeHandleCheck(pipeOut)
stderr = stdout
proc createPipeHandles(rdHandle, wrHandle: var Handle) =
@@ -561,9 +570,6 @@ when defined(Windows) and not defined(useNimRtl):
if createPipe(rdHandle, wrHandle, sa, 0) == 0'i32:
raiseOSError(osLastError())
proc fileClose(h: Handle) {.inline.} =
if h > 4: discard closeHandle(h)
proc startProcess(command: string, workingDir: string = "",
args: openArray[string] = [], env: StringTableRef = nil,
options: set[ProcessOption] = {poStdErrToStdOut}):
@@ -658,13 +664,31 @@ when defined(Windows) and not defined(useNimRtl):
result.id = procInfo.dwProcessId
result.exitFlag = false
proc closeThreadAndProcessHandle(p: Process) =
if p.fThreadHandle != 0:
closeHandleCheck(p.fThreadHandle)
p.fThreadHandle = 0
if p.fProcessHandle != 0:
closeHandleCheck(p.fProcessHandle)
p.fProcessHandle = 0
proc close(p: Process) =
if poParentStreams notin p.options:
discard closeHandle(p.inHandle)
discard closeHandle(p.outHandle)
discard closeHandle(p.errHandle)
discard closeHandle(p.fThreadHandle)
discard closeHandle(p.fProcessHandle)
if p.inStream == nil:
p.inHandle.fileClose()
else:
# p.inHandle can be already closed via inputStream.
p.inStream.close
# You may NOT close outputStream and errorStream.
assert p.outStream == nil or FileHandleStream(p.outStream).handle != INVALID_HANDLE_VALUE
assert p.errStream == nil or FileHandleStream(p.errStream).handle != INVALID_HANDLE_VALUE
if p.outHandle != p.errHandle:
p.errHandle.fileClose()
p.outHandle.fileClose()
p.closeThreadAndProcessHandle()
proc suspend(p: Process) =
discard suspendThread(p.fThreadHandle)
@@ -698,8 +722,7 @@ when defined(Windows) and not defined(useNimRtl):
if status != STILL_ACTIVE:
p.exitFlag = true
p.exitStatus = status
discard closeHandle(p.fThreadHandle)
discard closeHandle(p.fProcessHandle)
p.closeThreadAndProcessHandle()
result = status
else:
result = -1
@@ -715,8 +738,7 @@ when defined(Windows) and not defined(useNimRtl):
discard getExitCodeProcess(p.fProcessHandle, status)
p.exitFlag = true
p.exitStatus = status
discard closeHandle(p.fThreadHandle)
discard closeHandle(p.fProcessHandle)
p.closeThreadAndProcessHandle()
result = status
proc inputStream(p: Process): Stream =

View File

@@ -672,8 +672,8 @@ proc getPrecedence(p: SqlParser): int =
else:
result = - 1
proc parseExpr(p: var SqlParser): SqlNode
proc parseSelect(p: var SqlParser): SqlNode
proc parseExpr(p: var SqlParser): SqlNode {.gcsafe.}
proc parseSelect(p: var SqlParser): SqlNode {.gcsafe.}
proc identOrLiteral(p: var SqlParser): SqlNode =
case p.tok.kind
@@ -1201,7 +1201,7 @@ proc addIden(s: var SqlWriter, thing: string) =
iden = '"' & iden & '"'
s.add(iden)
proc ra(n: SqlNode, s: var SqlWriter)
proc ra(n: SqlNode, s: var SqlWriter) {.gcsafe.}
proc rs(n: SqlNode, s: var SqlWriter, prefix = "(", suffix = ")", sep = ", ") =
if n.len > 0:

View File

@@ -204,8 +204,8 @@ proc `[]`*(r: Rope, i: int): char {.rtl, extern: "nroCharAt".} =
if x.left.length > j:
x = x.left
else:
dec(j, x.left.length)
x = x.right
dec(j, x.len)
iterator leaves*(r: Rope): string =
## iterates over any leaf string in the rope `r`.
@@ -262,7 +262,7 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
while true:
j = j * 10 + ord(frmt[i]) - ord('0')
inc(i)
if frmt[i] notin {'0'..'9'}: break
if i >= frmt.len or frmt[i] notin {'0'..'9'}: break
add(result, args[j-1])
of '{':
inc(i)

View File

@@ -11,16 +11,48 @@
## SSL_CERT_DIR environment variables.
import os, strutils
from ospaths import existsEnv, getEnv
import strutils
# SECURITY: this unnecessarily scans through dirs/files regardless of the
# actual host OS/distribution. Hopefully all the paths are writeble only by
# root.
# FWIW look for files before scanning entire dirs.
const certificate_paths = [
when defined(macosx):
const certificatePaths = [
"/etc/ssl/cert.pem",
"/System/Library/OpenSSL/certs/cert.pem"
]
elif defined(linux):
const certificatePaths = [
# Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo
# NetBSD (security/mozilla-rootcerts)
# SLES10/SLES11, https://golang.org/issue/12139
"/etc/ssl/certs/ca-certificates.crt",
# OpenSUSE
"/etc/ssl/ca-bundle.pem",
# Red Hat 5+, Fedora, Centos
"/etc/pki/tls/certs/ca-bundle.crt",
# Red Hat 4
"/usr/share/ssl/certs/ca-bundle.crt",
# Fedora/RHEL
"/etc/pki/tls/certs",
# Android
"/system/etc/security/cacerts",
]
elif defined(bsd):
const certificatePaths = [
# Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo
# NetBSD (security/mozilla-rootcerts)
# SLES10/SLES11, https://golang.org/issue/12139
"/etc/ssl/certs/ca-certificates.crt",
# FreeBSD (security/ca-root-nss package)
"/usr/local/share/certs/ca-root-nss.crt",
# OpenBSD, FreeBSD (optional symlink)
"/etc/ssl/cert.pem",
# FreeBSD
"/usr/local/share/certs",
# NetBSD
"/etc/openssl/certs",
]
else:
const certificatePaths = [
# Debian, Ubuntu, Arch: maintained by update-ca-certificates, SUSE, Gentoo
# NetBSD (security/mozilla-rootcerts)
# SLES10/SLES11, https://golang.org/issue/12139
@@ -37,8 +69,6 @@ const certificate_paths = [
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
# OpenBSD, FreeBSD (optional symlink)
"/etc/ssl/cert.pem",
# Mac OS X
"/System/Library/OpenSSL/certs/cert.pem",
# Fedora/RHEL
"/etc/pki/tls/certs",
# Android
@@ -47,7 +77,7 @@ const certificate_paths = [
"/usr/local/share/certs",
# NetBSD
"/etc/openssl/certs",
]
]
when defined(haiku):
const
@@ -67,17 +97,30 @@ iterator scanSSLCertificates*(useEnvVars = false): string =
## if `useEnvVars` is true, the SSL_CERT_FILE and SSL_CERT_DIR
## environment variables can be used to override the certificate
## directories to scan or specify a CA certificate file.
if existsEnv("SSL_CERT_FILE"):
if useEnvVars and existsEnv("SSL_CERT_FILE"):
yield getEnv("SSL_CERT_FILE")
elif existsEnv("SSL_CERT_DIR"):
elif useEnvVars and existsEnv("SSL_CERT_DIR"):
let p = getEnv("SSL_CERT_DIR")
for fn in joinPath(p, "*").walkFiles():
yield fn
else:
when not defined(haiku):
for p in certificate_paths:
when defined(windows):
const cacert = "cacert.pem"
let pem = getAppDir() / cacert
if fileExists(pem):
yield pem
else:
let path = getEnv("PATH")
for candidate in split(path, PathSep):
if candidate.len != 0:
let x = (if candidate[0] == '"' and candidate[^1] == '"':
substr(candidate, 1, candidate.len-2) else: candidate) / cacert
if fileExists(x):
yield x
elif not defined(haiku):
for p in certificatePaths:
if p.endsWith(".pem") or p.endsWith(".crt"):
if existsFile(p):
yield p

View File

@@ -928,11 +928,11 @@ proc toHexImpl(x: BiggestUInt, len: Positive, handleNegative: bool): string {.no
# handle negative overflow
if n == 0 and handleNegative: n = not(BiggestUInt 0)
proc toHex*(x: BiggestUInt, len: Positive): string {.noSideEffect.} =
proc toHex*[T: SomeInteger](x: T, len: Positive): string {.noSideEffect.} =
## Converts `x` to its hexadecimal representation.
##
## The resulting string will be exactly `len` characters long. No prefix like
## ``0x`` is generated.
## ``0x`` is generated. `x` is treated as an unsigned value.
runnableExamples:
let
a = 62'u64
@@ -940,23 +940,8 @@ proc toHex*(x: BiggestUInt, len: Positive): string {.noSideEffect.} =
doAssert a.toHex(3) == "03E"
doAssert b.toHex(3) == "001"
doAssert b.toHex(4) == "1001"
toHexImpl(x, len, false)
proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
rtl, extern: "nsuToHex".} =
## Converts `x` to its hexadecimal representation.
##
## The resulting string will be exactly `len` characters long. No prefix like
## ``0x`` is generated. `x` is treated as an unsigned value.
runnableExamples:
let
a = 62
b = 4097
c = -8
doAssert a.toHex(3) == "03E"
doAssert b.toHex(3) == "001"
doAssert b.toHex(4) == "1001"
doAssert c.toHex(6) == "FFFFF8"
doAssert toHex(62, 3) == "03E"
doAssert toHex(-8, 6) == "FFFFF8"
toHexImpl(cast[BiggestUInt](x), len, x < 0)
proc toHex*[T: SomeInteger](x: T): string {.noSideEffect.} =

View File

@@ -188,7 +188,7 @@ macro capture*(locals: varargs[typed], body: untyped): untyped {.since: (1, 1).}
for arg in locals:
params.add(newIdentDefs(ident(arg.strVal), freshIdentNodes getTypeInst arg))
result = newNimNode(nnkCall)
result.add(newProc(newEmptyNode(), params, body, nnkProcDef))
result.add(newProc(newEmptyNode(), params, body, nnkLambda))
for arg in locals: result.add(arg)
when (NimMajor, NimMinor) >= (1, 1):

View File

@@ -284,7 +284,7 @@ proc removeDotSegments(path: string): string =
discard collection.pop()
i.inc 3
continue
elif path[i+1] == '/':
elif i + 1 < path.len and path[i+1] == '/':
i.inc 2
continue
currentSegment.add path[i]

View File

@@ -213,7 +213,22 @@ proc secureHashFile*(filename: string): SecureHash =
## **See also:**
## * `secureHash proc <#secureHash,openArray[char]>`_ for generating a ``SecureHash`` from a string
## * `parseSecureHash proc <#parseSecureHash,string>`_ for converting a string ``hash`` to ``SecureHash``
secureHash(readFile(filename))
const BufferLength = 8192
let f = open(filename)
var state = newSha1State()
var buffer = newString(BufferLength)
while true:
let length = readChars(f, buffer, 0, BufferLength)
if length == 0:
break
buffer.setLen(length)
state.update(buffer)
if length != BufferLength:
break
close(f)
SecureHash(state.finalize())
proc `$`*(self: SecureHash): string =
## Returns the string representation of a ``SecureHash``.

View File

@@ -2058,7 +2058,7 @@ const
NimMinor* {.intdefine.}: int = 2
## is the minor number of Nim's version.
NimPatch* {.intdefine.}: int = 8
NimPatch* {.intdefine.}: int = 12
## is the patch number of Nim's version.
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch

View File

@@ -250,7 +250,7 @@ proc llAlloc(a: var MemRegion, size: int): pointer =
sysAssert roundup(size+sizeof(LLChunk), PageSize) == PageSize, "roundup 6"
var old = a.llmem # can be nil and is correct with nil
a.llmem = cast[PLLChunk](osAllocPages(PageSize))
when defined(avlcorruption):
when defined(nimAvlcorruption):
trackLocation(a.llmem, PageSize)
incCurrMem(a, PageSize)
a.llmem.size = PageSize - sizeof(LLChunk)
@@ -273,7 +273,7 @@ proc allocAvlNode(a: var MemRegion, key, upperBound: int): PAvlNode =
a.freeAvlNodes = a.freeAvlNodes.link[0]
else:
result = cast[PAvlNode](llAlloc(a, sizeof(AvlNode)))
when defined(avlcorruption):
when defined(nimAvlcorruption):
cprintf("tracking location: %p\n", result)
result.key = key
result.upperBound = upperBound
@@ -281,7 +281,7 @@ proc allocAvlNode(a: var MemRegion, key, upperBound: int): PAvlNode =
result.link[0] = bottom
result.link[1] = bottom
result.level = 1
#when defined(avlcorruption):
#when defined(nimAvlcorruption):
# track("allocAvlNode", result, sizeof(AvlNode))
sysAssert(bottom == addr(a.bottomData), "bottom data")
sysAssert(bottom.link[0] == bottom, "bottom link[0]")
@@ -1013,7 +1013,7 @@ when defined(nimTypeNames):
template instantiateForRegion(allocator: untyped) {.dirty.} =
{.push stackTrace: off.}
when defined(fulldebug):
when defined(nimFulldebug):
proc interiorAllocatedPtr*(p: pointer): pointer =
result = interiorAllocatedPtr(allocator, p)

View File

@@ -38,9 +38,6 @@ proc raiseRangeErrorU(i, a, b: uint64) {.compilerproc, noinline.} =
# todo: better error reporting
sysFatal(RangeError, "value out of range")
proc raiseRangeErrorNoArgs() {.compilerproc, noinline.} =
sysFatal(RangeError, "value out of range")
proc raiseObjectConversionError() {.compilerproc, noinline.} =
sysFatal(ObjectConversionError, "invalid object conversion")

View File

@@ -436,7 +436,7 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
result = rawNewObj(typ, size, gch)
when defined(memProfiler): nimProfile(size)
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
result = rawNewObj(typ, size, gch)
zeroMem(result, size)
when defined(memProfiler): nimProfile(size)
@@ -451,7 +451,7 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
when defined(memProfiler): nimProfile(size)
{.pop.}
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
# generates a new object and sets its reference counter to 1
incTypeSize typ, size
sysAssert(allocInv(gch.region), "newObjRC1 begin")
@@ -662,16 +662,16 @@ proc collectCycles(gch: var GcHeap) =
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells:
sysAssert(allocInv(gch.region), "gcMark begin")
var cell = usrToCell(p)
var c = cast[ByteAddress](cell)
var c = cast[ByteAddress](p)
if c >% PageSize:
# fast check: does it look like a cell?
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p))
if objStart != nil:
# mark the cell:
incRef(objStart)
add(gch.decStack, objStart)
when false:
let cell = usrToCell(p)
if isAllocatedPtr(gch.region, cell):
sysAssert false, "allocated pointer but not interior?"
# mark the cell:

View File

@@ -454,11 +454,10 @@ proc markGlobals(gch: var GcHeap) =
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells:
var cell = usrToCell(p)
var c = cast[ByteAddress](cell)
var c = cast[ByteAddress](p)
if c >% PageSize:
# fast check: does it look like a cell?
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p))
if objStart != nil:
mark(gch, objStart)

View File

@@ -17,10 +17,10 @@ const
debugGC = false # we wish to debug the GC...
logGC = false
traceGC = false # extensive debugging
alwaysCycleGC = defined(smokeCycles)
alwaysGC = defined(fulldebug) # collect after every memory
alwaysCycleGC = defined(nimSmokeCycles)
alwaysGC = defined(nimFulldebug) # collect after every memory
# allocation (for debugging)
leakDetector = defined(leakDetector)
leakDetector = defined(nimLeakDetector)
overwriteFree = defined(nimBurnFree) # overwrite memory with 0xFF before free
trackAllocationSource = leakDetector
@@ -30,7 +30,7 @@ const
coalescRight = true
coalescLeft = true
logAlloc = false
useCellIds = defined(corruption)
useCellIds = defined(nimCorruption)
type
PPointer = ptr pointer

View File

@@ -719,6 +719,8 @@ when not defined(nimDisableCertificateValidation) and not defined(windows):
proc X509_check_host*(cert: PX509, name: cstring, namelen: cint, flags:cuint, peername: cstring): cint {.cdecl, dynlib: DLLSSLName, importc.}
proc X509_free*(cert: PX509) {.cdecl, dynlib: DLLSSLName, importc.}
# Certificates store
type PX509_STORE* = SslPtr

View File

@@ -217,6 +217,7 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
test "stackrefleak"
test "cyclecollector"
test "trace_globals"
proc longGCTests(r: var TResults, cat: Category, options: string) =
when defined(windows):

View File

@@ -9,7 +9,7 @@ pkg "argparse"
pkg "arraymancer", true, "nim c tests/tests_cpu.nim"
pkg "ast_pattern_matching", false, "nim c -r --oldgensym:on tests/test1.nim"
pkg "asyncmysql", true
pkg "bigints", url = "https://github.com/Araq/nim-bigints"
pkg "bigints"
pkg "binaryheap", false, "nim c -r binaryheap.nim"
# pkg "blscurve", true # pending https://github.com/status-im/nim-blscurve/issues/39
pkg "bncurve", true
@@ -24,7 +24,7 @@ pkg "coco", true
pkg "combparser"
pkg "compactdict"
pkg "comprehension", false, "nimble test", "https://github.com/alehander42/comprehension"
pkg "criterion"
# pkg "criterion"
pkg "dashing", false, "nim c tests/functional.nim"
pkg "docopt"
pkg "easygl", true, "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl"
@@ -55,7 +55,7 @@ pkg "nimfp", true, "nim c -o:nfp -r src/fp.nim"
pkg "nimgame2", true, "nim c nimgame2/nimgame.nim"
pkg "nimgen", true, "nim c -o:nimgenn -r src/nimgen/runcfg.nim"
# pkg "nimlsp", true
pkg "nimly", true
# pkg "nimly", true
# pkg "nimongo", true, "nimble test_ci"
pkg "nimpy", false, "nim c -r tests/nimfrompy.nim"
pkg "nimquery"
@@ -63,10 +63,10 @@ pkg "nimsl", true
pkg "nimsvg"
# pkg "nimterop", true
# pkg "nimx", true, "nim c --threads:on test/main.nim"
pkg "norm", true, "nim c -r tests/tsqliterows.nim"
# pkg "norm", true, "nim c -r tests/tsqliterows.nim"
pkg "npeg"
pkg "ormin", true, "nim c -o:orminn ormin.nim"
pkg "parsetoml"
# pkg "parsetoml"
pkg "patty"
pkg "plotly", true, "nim c --oldgensym:on examples/all.nim"
pkg "pnm"

View File

@@ -1,8 +1,3 @@
discard """
action: compile
"""
# XXX: action should be run!
import asyncdispatch
proc completeOnReturn(fut: FutureVar[string], x: bool) {.async.} =

View File

@@ -5,8 +5,8 @@ nimout: '''
type mismatch: got <AsyncHttpServer, Port, proc (req: Request): Future[system.void]{.locks: <unknown>.}>
but expected one of:
proc serve(server: AsyncHttpServer; port: Port;
callback: proc (request: Request): Future[void] {.closure, gcsafe.};
address = ""): owned(Future[void])
callback: proc (request: Request): Future[void] {.closure, gcsafe.};
address = ""; assumedDescriptorsPerRequest = -1): owned(Future[void])
first type mismatch at position: 3
required type for callback: proc (request: Request): Future[system.void]{.closure, gcsafe.}
but expression 'cb' is of type: proc (req: Request): Future[system.void]{.locks: <unknown>.}

View File

@@ -0,0 +1,22 @@
discard """
output: '''10000000
10000000
10000000'''
"""
# bug #17085
proc init(): string =
for a in 0..<10000000:
result.add 'c'
proc f() =
var a {.global.} = init()
var b {.global.} = init()
var c {.global.} = init()
echo a.len
echo b.len
echo c.len
f()

View File

@@ -0,0 +1,58 @@
proc jsTypeOf*[T](x: T): cstring {.importjs: "typeof(#)".}
## Returns the name of the JsObject's JavaScript type as a cstring.
# xxx replace jsffi.jsTypeOf with this definition and add tests
type JsBigIntImpl {.importc: "bigint".} = int
type JsBigInt = distinct JsBigIntImpl
doAssert JsBigInt isnot int
func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".}
func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".}
func `<=`*(x, y: JsBigInt): bool {.importjs: "(# $1 #)".}
func `==`*(x, y: JsBigInt): bool {.importjs: "(# === #)".}
func inc*(x: var JsBigInt) {.importjs: "[#][0][0]++".}
func inc2*(x: var JsBigInt) {.importjs: "#++".}
func toCstring*(this: JsBigInt): cstring {.importjs: "#.toString()".}
func `$`*(this: JsBigInt): string =
$toCstring(this)
block:
doAssert defined(nimHasJsBigIntBackend)
let z1 = big"10"
let z2 = big"15"
doAssert z1 == big"10"
doAssert z1 == z1
doAssert z1 != z2
var s: seq[cstring]
for i in z1 .. z2:
s.add $i
doAssert s == @["10".cstring, "11", "12", "13", "14", "15"]
block:
var a=big"3"
a.inc
doAssert a == big"4"
block:
var z: JsBigInt
doAssert $z == "0"
doAssert z.jsTypeOf == "bigint" # would fail without codegen change
doAssert z != big(1)
doAssert z == big"0" # ditto
# ditto below
block:
let z: JsBigInt = big"1"
doAssert $z == "1"
doAssert z.jsTypeOf == "bigint"
doAssert z == big"1"
block:
let z = JsBigInt.default
doAssert $z == "0"
doAssert z.jsTypeOf == "bigint"
doAssert z == big"0"
block:
var a: seq[JsBigInt]
a.setLen 3
doAssert a[^1].jsTypeOf == "bigint"
doAssert a[^1] == big"0"

33
tests/misc/t8404.nim Normal file
View File

@@ -0,0 +1,33 @@
discard """
targets: "c cpp js"
"""
template main() =
block: # bug #8404
# can conv
template float2int(T) =
var a = -1.0
let b = T(a)
doAssert b < 0
let c = b + 1
doAssert c is T
doAssert c == 0
float2int(int8)
float2int(int16)
float2int(int32)
float2int(int64)
block:
# can handle middle conv
# `/` can trigger int to float
template float2int(T) =
let n = T(1 / 256)
doAssert n == 0
float2int(int8)
float2int(int16)
float2int(int32)
# float2int(int64)
main()
static:
main()

View File

@@ -75,14 +75,3 @@ let rangeVar = 0'u64 ..< limit
doAssert repr(rangeVar) == """[a = 0,
b = 0]
"""
# bug #15210
let a3 = not 0'u64
var success = false
try:
discard a3.int64
except RangeError:
success = true
doAssert success, "conversion should fail at runtime"

View File

@@ -0,0 +1,7 @@
discard """
errormsg: "invalid pragma: exportc"
"""
let _ = proc () {.exportc.} =
# this would previously cause a codegen error
discard

View File

@@ -99,7 +99,7 @@ when not defined(windows):
let t = spawn runServer(port)
sleep(100)
var client = newHttpClient()
var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyNone))
try:
log "client: connect"
discard client.getContent("https://127.0.0.1:12345")

4
tests/stdlib/tmacros.nim Normal file
View File

@@ -0,0 +1,4 @@
import macros
block: # bug #17454
proc f(v: NimNode): string {.raises: [].} = $v

73
tests/stdlib/tropes.nim Normal file
View File

@@ -0,0 +1,73 @@
import ropes
block:
let r: Rope = nil
doAssert r[0] == '\0'
block:
var
r1 = rope("Hello")
r2 = rope("Nim-Lang")
let r = r1 & r2
let s = $r
for i in 0 ..< r.len:
doAssert r[i] == s[i]
doAssert r[66] == '\0'
block:
let r = rope("Hello, Nim-Lang")
let s = $r
for i in 0 ..< r.len:
doAssert r[i] == s[i]
doAssert r[66] == '\0'
block:
var r: Rope
r.add rope("Nim ")
r.add rope("is ")
r.add rope("a ")
r.add rope("great ")
r.add rope("language")
let s = $r
for i in 0 ..< r.len:
doAssert r[i] == s[i]
doAssert r[66] == '\0'
block:
var r: Rope
r.add rope("My Conquest")
r.add rope(" is ")
r.add rope("the Sea of Stars")
let s = $r
for i in 0 ..< r.len:
doAssert r[i] == s[i]
doAssert r[66] == '\0'
block:
var r: Rope
r.add rope("My Conquest")
r.add rope(" is ")
r.add rope("the Sea of Stars")
var i: int
for item in r:
doAssert r[i] == item
inc i
doAssert r[66] == '\0'
block:
let r1 = "$1 $2 $3" % [rope("Nim"), rope("is"), rope("a great language")]
doAssert $r1 == "Nim is a great language"
let r2 = "$# $# $#" % [rope("Nim"), rope("is"), rope("a great language")]
doAssert $r2 == "Nim is a great language"

View File

@@ -3,6 +3,7 @@ discard """
(name: "hello")
(-1, 0)
(FirstName: "James", LastName: "Franco")
[1, 2, 3]
'''
"""
@@ -70,3 +71,20 @@ static: # issue #11861
var ifb2: InheritedFromBase
initBase(ifb2)
doAssert(ifb2.txt == "Initialized string from base")
# bug #16069
type
E = enum
val1, val2
Obj = object
case k: E
of val1:
x: array[3, int]
of val2:
y: uint32
const
foo = [1, 2, 3]
arr = Obj(k: val1, x: foo)
echo arr.x

View File

@@ -1,3 +1,7 @@
discard """
targets: "c cpp js"
"""
#[
test for vmops.nim
]#