Racket: custodian-limit-memory not raising out-of-memory error? - memory-management

I'm trying to use custodians in Racket to set a limit to memory usage within a given scope and raise an out-of-memory error if it exceeds that limit.
Following examples for how to use custodians, I put together this simple program:
#lang racket/base
(with-handlers
([exn:fail:out-of-memory? (λ (err)
(println "Caught out-of-memory error! :D"))])
(parameterize ([current-custodian (make-custodian)])
(custodian-limit-memory (current-custodian) (* 2 1024 1024))
(make-bytes (* 4 1024 1024)))
(println "Should have raised OoM. :("))
I expect to see the output "Caught out-of-memory error! :D", but instead I am seeing "Should have raised OoM. :(".
Any idea why my code isn't raising the out-of-memory error when I call make-bytes here?

Related

How to show error message from eval in Scheme?

I'm trying to create code that evaluates expression and return error as string for error:
(cond-expand
(gambit)
(gauche)
(kawa)
(guile
(import (rnrs base)
(rnrs exceptions)
(rnrs conditions))
(define (error-object-message cond)
(condition-message cond))))
(define (evaluate expr env)
(call-with-current-continuation
(lambda (exit)
(with-exception-handler
(lambda (e)
(exit (error-object-message e)))
(lambda ()
(eval expr env))))))
;; trigger error
(display (evaluate 'xxx (interaction-environment)))
(newline)
I've got
Guile message Unbound variable: ~S how to get actual error message and not a template?
Kawa exception: Argument #1 'unbound location: xxx' to 'error-object-message' has wrong type (gnu.mapping.UnboundLocationException) (gnu.mapping.UnboundLocationException cannot be cast to kawa.lang.NamedException)
Gauche core dump
Gambit freezes
NOTE: this is part of REPL that I'm testing in all Scheme implementations that I have on my system. It almost work, it can run itself, but I would like to show proper error message when exception happen, instead of exiting the REPL.
The reason you get an infinite loop with Gambit is that the variable xxx is unbound so the exception handler (lambda (e) (exit (error-object-message e))) is called with an unbound-global-exception object and this causes error-object-message to be called but the parameter is not an error-object (which is specific to the exceptions raised by a call to the error procedure) so this raises a type-exception object that causes the same exception handler to be called, and so on forever.
If you want an exception handling that "pops" the current exception handler, use with-exception-catcher instead of with-exception-handler. This will avoid the infinite loop.
Converting an exception object to a string can be done in Gambit this way:
(define (exception->string exc)
(with-output-to-string
(lambda ()
(display-exception exc))))
It works for error-objects and other kinds of exceptions, and also any non-exception object.
This is a more portable solution (superficially tested):
(import (scheme base)
(scheme r5rs))
(cond-expand
((or lips kawa gauche)
(define (exception->string exc)
(error-object-message exc)))
(gambit
(define (exception->string exc)
(with-output-to-string
(lambda ()
(display-exception exc)))))
(guile
(import (rnrs base)
(rnrs exceptions)
(rnrs conditions))
(define (exception->string exc)
(condition-message exc))))
(define (evaluate expr env)
(call-with-current-continuation
(lambda (exit)
(with-exception-handler
(lambda (e)
(exit (exception->string e)))
(lambda ()
(eval expr env))))))
(display (evaluate 'xxx (interaction-environment)))
(newline)
Gauche core dump
Oops. It's not ideal, for sure, but it can be explained.
By default, Gauche's with-exception-handler is SRFI-18's, not R7RS's, because of a historical reason. That means the exception handler is called in the dynamic environment where the exception occurs, including exception handler settings. If an exception occurs within the exception handler, the same exception handler is invoked, causing unbounded recursion. Apparently Gauche's runtime eats up C stack or something.
error-object-message is not defined in Gauche's default namespace. So that triggers an exception in the first place.
Add
(import (scheme base) (scheme write) (scheme r5rs))
at the beginning of code makes the program run in R7RS bindings. Then you'll get:
unbound variable: xxx
Actually, your code is not a valid R7RS program (which should begin with at least one import declaration), so anything can happen, depending on the default interpretation of the non-conforming code in the implementation.
[Edit] IMHO, with-exception-handler should be considered as the lowest level construct on which easy-to-use utilities are built, and thus should be used with extra care. In general use case, guard provides a good abstraction.
For Kawa:
(define (exception->string exc)
(call-with-port (open-output-string)
(lambda (port)
(display exc port)
(get-output-string port)))))
This will convert exception to string and get error message

Invalid event "~#chsk/handshake" when using sente packers.transit/get-transit-packer in clojure

I am getting an error when using sente that results in failure while sending information from client to server or vice versa. The problem seems to be that the handshake fails with an error
cljs$core$ExceptionInfo
message: "Invalid event"
data: {:given "~:chsk/handshake", :errors {:wrong-type {…}}}
The successive ws/ping also fail with the same error but with extra information,
sente.cljc:142 Uncaught #error {:message "Invalid event", :data {:given "~#'", :errors {:wrong-type
{…}[:expected :vector]
[:actual {:type #object[String], :value "~#'"}]
What might be the problem, my code seems okay and follows the default example in sente.
Expected behaviour:
Sente would connect and i would be able to call send-fn and send messages between the server and client, successfully.
Edit: Addition of code as suggested in the comments:
(require '[taoensso.sente.server-adapters.aleph :refer (get-sch-adapter)])
;; Create Websocket connection in server
(let [packer (sente-transit/get-transit-packer)
chsk-server (sente/make-channel-socket-server! (get-sch-adapter) {:packer packer
:csrf-token-fn nil})
{:keys [ch-recv send-fn connected-uids ajax-post-fn ajax-get-or-ws-handshake-fn]} chsk-server]
(def ring-ajax-post ajax-post-fn)
(def ring-ajax-get-or-ws-handshake ajax-get-or-ws-handshake-fn)
(def ch-chsk ch-recv)
(def chsk-send! send-fn)
(def connected-uids connected-uids))
;; Start the web server
(defn start-web-server! [& [port]]
(stop-web-server!)
(let [port (or port default-port)
ring-handler (var main-ring-handler)
[port stop-fn]
(let [server (aleph/start-server ring-handler {:port port})
p (promise)]
(future #p)
[(aleph.netty/port server)
(fn [] (.close ^Closeable server) (deliver p nil))])
uri (format "http://localhost:%s/" port)]
(infof "Web server is running at `%s`" uri)
(reset! web-server_ {:port port :stop-fn stop-fn})
(try
(if (and (Desktop/isDesktopSupported)
(.isSupported (Desktop/getDesktop) Desktop$Action/BROWSE))
(.browse (Desktop/getDesktop) (URI. uri))
(.exec (Runtime/getRuntime) (str "xdg-open" uri)))
(Thread/sleep 7500)
(catch HeadlessException _))))
On the client side:
(let [packer (sente-transit/get-transit-packer)
{:keys [chsk ch-recv send-fn state]}
(sente/make-channel-socket-client! "/chsk"
{:type :auto
:packer packer})]
(def chsk chsk)
(def ch-chsk ch-recv)
(def chsk-send! send-fn)
(def chsk-state state))
;; start the router
(defn start-router! []
(stop-router!)
(reset! router_ (sente/start-client-chsk-router! ch-chsk event-msg-handler)))
EDIT, Addition
I have noted that the error only exists when i use the packer, (packers.transit/get-transit-packer) and not :edn
Ran into this issue today coincidentally, so after this issue I was scratching my head a bit, could it be the library which hasn't seen much activity/is stable?
Nope. I simply forgot to include the [com.cognitect/transit-cljs "0.8.256"] cljs dependency!
The example did warn:
https://github.com/ptaoussanis/sente/blob/master/example-project/src/example/client.cljs#L47
Not exactly an answer, but we gotta see your code for that.
The error "Invalid event" is generated here:
(defn validate-event
"Returns nil if given argument is a valid [ev-id ?ev-data] form. Otherwise
returns a map of validation errors like `{:wrong-type {:expected _ :actual _}}`."
[x]
(cond
(not (vector? x)) {:wrong-type (expected :vector x)}
(not (#{1 2} (count x))) {:wrong-length (expected #{1 2} x)}
:else
(let [[ev-id _] x]
(cond
(not (keyword? ev-id)) {:wrong-id-type (expected :keyword ev-id)}
(not (namespace ev-id)) {:unnamespaced-id (expected :namespaced-keyword ev-id)}
:else nil))))
```

Using trace in Typed Racket

I'm having difficulty getting the trace module set up when using Typed Racket - my attempt is the following in a REPL:
#lang typed/racket
(require/typed racket/trace
[trace (Symbol * -> Void)])
(define (add-four [num : Number])
(+ 4 num))
(trace add-four)
(add-four 3)
This is from following along the trace and type annotation docs, but I'm getting the error trace: bad syntax in: trace in the trace type annotation when importing - not sure where I've gone wrong!

edebug-trace ceased to exist

In Emacs 25.2, suddenly the variable edebug-trace ceased to exist. When I set it with setq, it has no effect (the trace buffer does not appear). What could have happened and how can I fix it?
In the meanwhile, is there another way to know which function gets called when I click on an org-mode link
You could use trace.el to trace all org functions like so (I suggest not evaluating this until you're ready to click the link).
(mapatoms
(lambda (sym)
(and (fboundp sym)
(string-prefix-p "org-" (symbol-name sym))
(trace-function-foreground sym))))
Afterwards, you can remove the traces with:
M-x untrace-all RET
Edit: We could also convert that into a command ala elp-instrument-package:
(defun my-trace-package (prefix)
"Trace all functions which start with PREFIX.
For example, to trace all ELP functions, do the following:
\\[my-trace-package] RET elp- RET"
(interactive ;; derived from `elp-instrument-package'.
(list (completing-read "Prefix of package to trace: "
obarray 'my-traceable-p)))
(if (zerop (length prefix))
(error "Tracing all Emacs functions would render Emacs unusable"))
(mapc (lambda (name)
(trace-function-foreground (intern name)))
(all-completions prefix obarray 'my-traceable-p))
(message "Use %s to cease tracing."
(substitute-command-keys "\\[untrace-all]")))
(defun my-traceable-p (fun)
"Predicate for `my-trace-package'."
(or (functionp fun) (macrop fun)))

Clojure compile-time escape mechanism

The language Forth offers a "compile-time" escape mechanism where code can be executed immediately, while the compiler is running (not at run-time). You can include print statements, for example, to debug tricky syntax or type errors).
Does Clojure have anything similar? I am getting a compile-time IllegalArgumentException in one of my function calls and would like to add a compile-time print statement to determine the argument type ((.getClass)).
Thanks.
UPDATE: Here is the complete defn that is failing compilation:
(ns my.ns.name
(:gen-class
:main true)
(:use
[clojure.contrib.str-utils2 :only (join)])
(:import
[java.io PrintWriter]
[java.net URL]
[java.util.concurrent Executors]
[java.util.jar Manifest]
[org.apache.commons.cli CommandLine HelpFormatter Options Option ParseException PosixParser]))
(defn set-version
"Set the version variable to the build number."
[]
(def version
(-> (str "jar:" (.. my.ns.name (getProtectionDomain)
(getCodeSource)
(getLocation))
"!/META-INF/MANIFEST.MF")
(URL.)
(.openStream)
(Manifest.)
(.. getMainAttributes)
(.getValue "Build-number"))))
This defn works:
(defn set-version
"Set the version variable to the build number."
[]
(println (str (.getClass my.ns.name)))
(def version
(-> (str "jar:" (-> my.ns.name (.getProtectionDomain)
(.getCodeSource)
(.getLocation))
"!/META-INF/MANIFEST.MF")
(URL.)
(.openStream)
(Manifest.)
(.. getMainAttributes)
(.getValue "Build-number"))))
Printing the class of things during compilation is pretty restricted to special cases. You will mostly get Symbols and Seqs. Only literals have a meaningful type during compilation. You can execute arbitrary code during compilation via macros.
(defmacro debug-type
[x]
(println (type x))
x)
However as I said: this will normally not be very helpful. And no: in general you cannot wrap x in an eval, eg. if x is a symbol refering to a let-local.
EDIT: Update for updated question.
(def version
(-> (str "jar:" (-> *ns* (.getProtectionDomain)
(.getCodeSource)
(.getLocation))
"!/META-INF/MANIFEST.MF")
(URL.)
(.openStream)
(Manifest.)
(.getMainAttributes)
(.getValue "Build-number")))
Try this. There is no need for a function. def inside defn should ring alarm bells.

Resources