beginning of a taint mode; type system enhancements

This commit is contained in:
Araq
2011-09-24 00:46:41 +02:00
parent 2359b8b107
commit 6023e994fb
18 changed files with 265 additions and 283 deletions

View File

@@ -36,15 +36,18 @@ type
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
nnkAsmStmt, nnkPragma, nnkIfStmt, nnkWhenStmt,
nnkForStmt, nnkWhileStmt, nnkCaseStmt, nnkVarSection,
nnkConstSection, nnkConstDef, nnkTypeSection, nnkTypeDef,
nnkForStmt, nnkWhileStmt, nnkCaseStmt,
nnkVarSection, nnkLetSection, nnkConstSection,
nnkConstDef, nnkTypeSection, nnkTypeDef,
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt,
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
nnkRefTy, nnkPtrTy, nnkVarTy, nnkDistinctTy,
nnkRefTy, nnkPtrTy, nnkVarTy,
nnkConstTy, nnkMutableTy,
nnkDistinctTy,
nnkProcTy, nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
TNimNodeKinds* = set[TNimrodNodeKind]
TNimrodTypeKind* = enum
@@ -184,7 +187,7 @@ proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
## in a string literal node
return newStrLitNode(repr(n))
proc prettyPrint*(n: PNimrodNode): string {.compileTime.} =
proc toLisp*(n: PNimrodNode): string {.compileTime.} =
## Convert the AST `n` to a human-readable string
##
## You can use this as a tool to explore the Nimrod's abstract syntax
@@ -204,10 +207,10 @@ proc prettyPrint*(n: PNimrodNode): string {.compileTime.} =
of nnkIdent: add(result, $n.ident)
of nnkSym, nnkNone: assert false
else:
add(result, prettyPrint(n[0]))
add(result, toLisp(n[0]))
for j in 1..n.len-1:
add(result, ", ")
add(result, prettyPrint(n[j]))
add(result, toLisp(n[j]))
add(result, ")")
@@ -215,7 +218,7 @@ proc toYaml*(n: PNimrodNode): string {.magic: "AstToYaml".}
## Converts the AST `n` to an YAML string
##
## Provides more detailed, potentially harder to digest information
## than `prettyPrint`
## than `toLisp`
proc parseExpr*(s: string) : expr {.magic: "ParseExprToAst".}
## Compiles the passed string to its AST representation
@@ -226,10 +229,13 @@ proc parseStmt*(s: string) : stmt {.magic: "ParseStmtToAst".}
## Expects one or more statements
proc getAst*(macroOrTemplate: expr): expr {.magic: "ExpandMacroToAst".}
## Obtains the AST nodes returned from a macro or template invocation
## example:
## macro FooMacro() =
## var ast = getAst(BarTemplate())
## Obtains the AST nodes returned from a macro or template invocation.
## Example:
##
## .. code-block:: nimrod
##
## macro FooMacro() =
## var ast = getAst(BarTemplate())
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
## checks that `n` is of kind `k`. If this is not the case,

View File

@@ -107,7 +107,7 @@ proc cgiError*(msg: string) {.noreturn.} =
raise e
proc getEncodedData(allowedMethods: set[TRequestMethod]): string =
case getenv("REQUEST_METHOD")
case getenv("REQUEST_METHOD").string
of "POST":
if methodPost notin allowedMethods:
cgiError("'REQUEST_METHOD' 'POST' is not supported")
@@ -192,131 +192,131 @@ proc validateData*(data: PStringTable, validKeys: openarray[string]) =
proc getContentLength*(): string =
## returns contents of the ``CONTENT_LENGTH`` environment variable
return getenv("CONTENT_LENGTH")
return getenv("CONTENT_LENGTH").string
proc getContentType*(): string =
## returns contents of the ``CONTENT_TYPE`` environment variable
return getenv("CONTENT_Type")
return getenv("CONTENT_Type").string
proc getDocumentRoot*(): string =
## returns contents of the ``DOCUMENT_ROOT`` environment variable
return getenv("DOCUMENT_ROOT")
return getenv("DOCUMENT_ROOT").string
proc getGatewayInterface*(): string =
## returns contents of the ``GATEWAY_INTERFACE`` environment variable
return getenv("GATEWAY_INTERFACE")
return getenv("GATEWAY_INTERFACE").string
proc getHttpAccept*(): string =
## returns contents of the ``HTTP_ACCEPT`` environment variable
return getenv("HTTP_ACCEPT")
return getenv("HTTP_ACCEPT").string
proc getHttpAcceptCharset*(): string =
## returns contents of the ``HTTP_ACCEPT_CHARSET`` environment variable
return getenv("HTTP_ACCEPT_CHARSET")
return getenv("HTTP_ACCEPT_CHARSET").string
proc getHttpAcceptEncoding*(): string =
## returns contents of the ``HTTP_ACCEPT_ENCODING`` environment variable
return getenv("HTTP_ACCEPT_ENCODING")
return getenv("HTTP_ACCEPT_ENCODING").string
proc getHttpAcceptLanguage*(): string =
## returns contents of the ``HTTP_ACCEPT_LANGUAGE`` environment variable
return getenv("HTTP_ACCEPT_LANGUAGE")
return getenv("HTTP_ACCEPT_LANGUAGE").string
proc getHttpConnection*(): string =
## returns contents of the ``HTTP_CONNECTION`` environment variable
return getenv("HTTP_CONNECTION")
return getenv("HTTP_CONNECTION").string
proc getHttpCookie*(): string =
## returns contents of the ``HTTP_COOKIE`` environment variable
return getenv("HTTP_COOKIE")
return getenv("HTTP_COOKIE").string
proc getHttpHost*(): string =
## returns contents of the ``HTTP_HOST`` environment variable
return getenv("HTTP_HOST")
return getenv("HTTP_HOST").string
proc getHttpReferer*(): string =
## returns contents of the ``HTTP_REFERER`` environment variable
return getenv("HTTP_REFERER")
return getenv("HTTP_REFERER").string
proc getHttpUserAgent*(): string =
## returns contents of the ``HTTP_USER_AGENT`` environment variable
return getenv("HTTP_USER_AGENT")
return getenv("HTTP_USER_AGENT").string
proc getPathInfo*(): string =
## returns contents of the ``PATH_INFO`` environment variable
return getenv("PATH_INFO")
return getenv("PATH_INFO").string
proc getPathTranslated*(): string =
## returns contents of the ``PATH_TRANSLATED`` environment variable
return getenv("PATH_TRANSLATED")
return getenv("PATH_TRANSLATED").string
proc getQueryString*(): string =
## returns contents of the ``QUERY_STRING`` environment variable
return getenv("QUERY_STRING")
return getenv("QUERY_STRING").string
proc getRemoteAddr*(): string =
## returns contents of the ``REMOTE_ADDR`` environment variable
return getenv("REMOTE_ADDR")
return getenv("REMOTE_ADDR").string
proc getRemoteHost*(): string =
## returns contents of the ``REMOTE_HOST`` environment variable
return getenv("REMOTE_HOST")
return getenv("REMOTE_HOST").string
proc getRemoteIdent*(): string =
## returns contents of the ``REMOTE_IDENT`` environment variable
return getenv("REMOTE_IDENT")
return getenv("REMOTE_IDENT").string
proc getRemotePort*(): string =
## returns contents of the ``REMOTE_PORT`` environment variable
return getenv("REMOTE_PORT")
return getenv("REMOTE_PORT").string
proc getRemoteUser*(): string =
## returns contents of the ``REMOTE_USER`` environment variable
return getenv("REMOTE_USER")
return getenv("REMOTE_USER").string
proc getRequestMethod*(): string =
## returns contents of the ``REQUEST_METHOD`` environment variable
return getenv("REQUEST_METHOD")
return getenv("REQUEST_METHOD").string
proc getRequestURI*(): string =
## returns contents of the ``REQUEST_URI`` environment variable
return getenv("REQUEST_URI")
return getenv("REQUEST_URI").string
proc getScriptFilename*(): string =
## returns contents of the ``SCRIPT_FILENAME`` environment variable
return getenv("SCRIPT_FILENAME")
return getenv("SCRIPT_FILENAME").string
proc getScriptName*(): string =
## returns contents of the ``SCRIPT_NAME`` environment variable
return getenv("SCRIPT_NAME")
return getenv("SCRIPT_NAME").string
proc getServerAddr*(): string =
## returns contents of the ``SERVER_ADDR`` environment variable
return getenv("SERVER_ADDR")
return getenv("SERVER_ADDR").string
proc getServerAdmin*(): string =
## returns contents of the ``SERVER_ADMIN`` environment variable
return getenv("SERVER_ADMIN")
return getenv("SERVER_ADMIN").string
proc getServerName*(): string =
## returns contents of the ``SERVER_NAME`` environment variable
return getenv("SERVER_NAME")
return getenv("SERVER_NAME").string
proc getServerPort*(): string =
## returns contents of the ``SERVER_PORT`` environment variable
return getenv("SERVER_PORT")
return getenv("SERVER_PORT").string
proc getServerProtocol*(): string =
## returns contents of the ``SERVER_PROTOCOL`` environment variable
return getenv("SERVER_PROTOCOL")
return getenv("SERVER_PROTOCOL").string
proc getServerSignature*(): string =
## returns contents of the ``SERVER_SIGNATURE`` environment variable
return getenv("SERVER_SIGNATURE")
return getenv("SERVER_SIGNATURE").string
proc getServerSoftware*(): string =
## returns contents of the ``SERVER_SOFTWARE`` environment variable
return getenv("SERVER_SOFTWARE")
return getenv("SERVER_SOFTWARE").string
proc setTestData*(keysvalues: openarray[string]) =
## fills the appropriate environment variables to test your CGI application.
@@ -360,10 +360,10 @@ proc setCookie*(name, value: string) =
var
gcookies: PStringTable = nil
proc getCookie*(name: string): string =
proc getCookie*(name: string): TaintedString =
## Gets a cookie. If no cookie of `name` exists, "" is returned.
if gcookies == nil: gcookies = parseCookies(getHttpCookie())
result = gcookies[name]
result = TaintedString(gcookies[name])
proc existsCookie*(name: string): bool =
## Checks if a cookie of `name` exists.

View File

@@ -692,7 +692,7 @@ proc findEnvVar(key: string): int =
if startsWith(environment[i], temp): return i
return -1
proc getEnv*(key: string): string =
proc getEnv*(key: string): TaintedString =
## Returns the value of the `environment variable`:idx: named `key`.
##
## If the variable does not exist, "" is returned. To distinguish
@@ -700,11 +700,11 @@ proc getEnv*(key: string): string =
## `existsEnv(key)`.
var i = findEnvVar(key)
if i >= 0:
return substr(environment[i], find(environment[i], '=')+1)
return TaintedString(substr(environment[i], find(environment[i], '=')+1))
else:
var env = cgetenv(key)
if env == nil: return ""
result = $env
if env == nil: return TaintedString("")
result = TaintedString($env)
proc existsEnv*(key: string): bool =
## Checks whether the environment variable named `key` exists.
@@ -733,14 +733,15 @@ proc putEnv*(key, val: string) =
if SetEnvironmentVariableA(key, val) == 0'i32:
OSError()
iterator envPairs*(): tuple[key, value: string] =
iterator envPairs*(): tuple[key, value: TaintedString] =
## Iterate over all `environments variables`:idx:. In the first component
## of the tuple is the name of the current variable stored, in the second
## its value.
getEnvVarsC()
for i in 0..high(environment):
var p = find(environment[i], '=')
yield (substr(environment[i], 0, p-1), substr(environment[i], p+1))
yield (TaintedString(substr(environment[i], 0, p-1)),
TaintedString(substr(environment[i], p+1)))
iterator walkFiles*(pattern: string): string =
## Iterate over all the files that match the `pattern`. On POSIX this uses
@@ -1078,18 +1079,18 @@ proc exclFilePermissions*(filename: string,
proc getHomeDir*(): string {.rtl, extern: "nos$1".} =
## Returns the home directory of the current user.
when defined(windows): return getEnv("USERPROFILE") & "\\"
else: return getEnv("HOME") & "/"
when defined(windows): return string(getEnv("USERPROFILE")) & "\\"
else: return string(getEnv("HOME")) & "/"
proc getConfigDir*(): string {.rtl, extern: "nos$1".} =
## Returns the config directory of the current user for applications.
when defined(windows): return getEnv("APPDATA") & "\\"
else: return getEnv("HOME") & "/.config/"
when defined(windows): return string(getEnv("APPDATA")) & "\\"
else: return string(getEnv("HOME")) & "/.config/"
proc getTempDir*(): string {.rtl, extern: "nos$1".} =
## Returns the temporary directory of the current user for applications to
## save temporary files in.
when defined(windows): return getEnv("TEMP") & "\\"
when defined(windows): return string(getEnv("TEMP")) & "\\"
else: return "/tmp/"
when defined(windows):
@@ -1107,14 +1108,14 @@ when defined(windows):
if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLineA())
result = ownArgv.len-1
proc paramStr*(i: int): string {.rtl, extern: "nos$1".} =
proc paramStr*(i: int): TaintedString {.rtl, extern: "nos$1".} =
## Returns the `i`-th `command line argument`:idx: given to the
## application.
##
## `i` should be in the range `1..paramCount()`, else
## the `EOutOfIndex` exception is raised.
if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLineA())
return ownArgv[i]
return TaintedString(ownArgv[i])
elif not defined(createNimRtl):
# On Posix, there is no portable way to get the command line from a DLL.
@@ -1122,8 +1123,8 @@ elif not defined(createNimRtl):
cmdCount {.importc: "cmdCount".}: cint
cmdLine {.importc: "cmdLine".}: cstringArray
proc paramStr*(i: int): string =
if i < cmdCount and i >= 0: return $cmdLine[i]
proc paramStr*(i: int): TaintedString =
if i < cmdCount and i >= 0: return TaintedString($cmdLine[i])
raise newException(EInvalidIndex, "invalid index")
proc paramCount*(): int = return cmdCount-1
@@ -1172,13 +1173,14 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1".} =
result = "" # error!
else:
# little heuristic that may work on other POSIX-like systems:
result = getEnv("_")
result = string(getEnv("_"))
if len(result) == 0:
result = ParamStr(0) # POSIX guaranties that this contains the executable
# as it has been executed by the calling process
result = string(ParamStr(0))
# POSIX guaranties that this contains the executable
# as it has been executed by the calling process
if len(result) > 0 and result[0] != DirSep: # not an absolute path?
# iterate over any path in the $PATH environment variable
for p in split(getEnv("PATH"), {PathSep}):
for p in split(string(getEnv("PATH")), {PathSep}):
var x = joinPath(p, result)
if ExistsFile(x): return x
@@ -1230,7 +1232,7 @@ proc findExe*(exe: string): string =
## is added an ``.exe`` file extension if it has no extension.
result = addFileExt(exe, os.exeExt)
if ExistsFile(result): return
var path = os.getEnv("PATH")
var path = string(os.getEnv("PATH"))
for candidate in split(path, pathSep):
var x = candidate / result
if ExistsFile(x): return x

View File

@@ -48,7 +48,7 @@ when defined(os.ParamCount):
else:
result.cmd = ""
for i in countup(1, ParamCount()):
result.cmd = result.cmd & quoteIfContainsWhite(paramStr(i)) & ' '
result.cmd = result.cmd & quoteIfContainsWhite(paramStr(i).string) & ' '
result.kind = cmdEnd
result.key = ""
result.val = ""

View File

@@ -787,6 +787,19 @@ proc compileOption*(option, arg: string): bool {.
const
hasThreadSupport = compileOption("threads")
hasSharedHeap = defined(boehmgc) # don't share heaps; every thread has its own
# taintMode = compileOption("taintmode")
when defined(taintMode):
# XXX use a compile time option for it!
type TaintedString* = distinct string ## a distinct string type that
## is `tainted`:idx:. It is an alias for
## ``string`` if the taint mode is not
## turned on. Use the ``-d:taintMode``
## command line switch to turn the taint
## mode on.
else:
type TaintedString* = string
when hasThreadSupport:
{.pragma: rtlThreadVar, threadvar.}
@@ -896,11 +909,6 @@ type # these work for most platforms:
PInt64* = ptr Int64 ## an alias for ``ptr int64``
PInt32* = ptr Int32 ## an alias for ``ptr int32``
type TOptional*[T] = object
case hasValue* : bool
of true: value*: T
of false: nil
proc toFloat*(i: int): float {.
magic: "ToFloat", noSideEffect, importc: "toFloat".}
## converts an integer `i` into a ``float``. If the conversion
@@ -1653,7 +1661,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
proc FlushFile*(f: TFile) {.importc: "fflush", noDecl.}
## Flushes `f`'s buffer.
proc readFile*(filename: string): string
proc readFile*(filename: string): TaintedString
## Opens a file named `filename` for reading. Then reads the
## file's content completely into a string and
## closes the file afterwards. Returns the string.
@@ -1675,7 +1683,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
proc write*(f: TFile, a: openArray[string])
## Writes a value to the file `f`. May throw an IO exception.
proc readLine*(f: TFile): string
proc readLine*(f: TFile): TaintedString
## reads a line of text from the file `f`. May throw an IO exception.
## A line of text may be delimited by ``CR``, ``LF`` or
## ``CRLF``. The newline character(s) are not part of the returned string.
@@ -1814,22 +1822,22 @@ when not defined(EcmaScript) and not defined(NimrodVM):
when hasThreadSupport:
include "system/channels"
iterator lines*(filename: string): string =
iterator lines*(filename: string): TaintedString =
## Iterate over any line in the file named `filename`.
## If the file does not exist `EIO` is raised.
var f = open(filename)
var res = ""
while not endOfFile(f):
rawReadLine(f, res)
yield res
yield TaintedString(res)
Close(f)
iterator lines*(f: TFile): string =
iterator lines*(f: TFile): TaintedString =
## Iterate over any line in the file `f`.
var res = ""
while not endOfFile(f):
rawReadLine(f, res)
yield res
yield TaintedString(res)
include "system/assign"
include "system/repr"

View File

@@ -55,8 +55,8 @@ proc rawReadLine(f: TFile, result: var string) =
break
add result, chr(int(c))
proc readLine(f: TFile): string =
result = ""
proc readLine(f: TFile): TaintedString =
result = TaintedString("")
rawReadLine(f, result)
proc write(f: TFile, i: int) =
@@ -81,7 +81,7 @@ proc write(f: TFile, c: Char) = putc(c, f)
proc write(f: TFile, a: openArray[string]) =
for x in items(a): write(f, x)
proc readFile(filename: string): string =
proc readFile(filename: string): TaintedString =
var f = open(filename)
try:
var len = getFileSize(f)