gah. after being bitten by this for the n-th time: When (define
-ing inside a macro one has to be really bleeding careful about identifiers (or rather their scopes i suppose);
I don’t suppose there’s some way to hint at this particular footgun?
Uh, how do you mean? Hygienic macros should avoid certain issues, but maybe you’re talking about something else?
(define-syntax (a-definer stx)
(syntax-parse stx
[(_ x:string)
(with-syntax [(X (string->symbol (syntax->datum #'x)))]
#'(begin
(define (X) (displayln "foo"))
(X)))]))
(a-definer "foo")
defines foo
inside the scope of the macro (and, crucially, not outside)
You need to use format-id
when introducing new identifiers, and give it the ‘scope’ in which it is defined via the first context argument: #lang racket
(require (for-syntax syntax/parse
racket/syntax))
(define-syntax (a-definer stx)
(syntax-parse stx
[(_ x:string)
(with-syntax ([X (format-id stx "~a" (syntax->datum #'x))])
#'(begin
(define (X) (displayln "foo"))
(X)))
]))
(a-definer "you")
(you)
you can use string->symbol
, but then you need to create an actual syntax object from this datum with the right context with datum->syntax
, which is basically what format-id
does
Is there a way to break the hygene of the macros? Eg is there a way to put the name x in a particular scope:
> (define-syntax (let-x=1 stx)
(syntax-case stx ()
[(_ body ...)
(with-syntax ([x-name (datum->syntax #f 'x)])
#'(let ([x-name 1]) body ...))]))
> (let-x=1 x)
; x: undefined;
; cannot reference an identifier before its definition
; in module: top-level
; [,bt for context]
#lang racket
(define-syntax (let-x=1 stx)
(syntax-case stx ()
[(_ body ...)
(with-syntax ([x-name (datum->syntax stx 'x)])
#'(let ([x-name 1])
body ...))]))
(let-x=1 (+ x 2))
ah
why did that work and #f
didnt?
If you want to be explicit, that the newly introduced x is in scope in body
, then you can write: #lang racket
(define-syntax (let-x=1 stx)
(syntax-case stx ()
[(_ . body)
(with-syntax ([x-name (datum->syntax #'body 'x)])
#'(let ([x-name 1])
. body))]))
(let-x=1 (+ x 2))
The documentation has the following to say about the case, where the context ctxt
is #f
: > Any of _ctxt_, _srcloc_, or _prop_ can be #f, in which case the resulting syntax > has no lexical context, source information, and/or new properties.
That is, used #f
as the context means won’t give the identifier a scope where it can be seen from body.
so if (datum->syntax #f 'x)
will make a symbol that won’t be dereferenced in any context
Except for cases like this > (define-syntax (quote-x stx) (syntax-case stx () [(_) (with-syntax ([x-name (datum->syntax #f 'x)]) #'(quote x-name))]))
> (quote-x)
'x
you’re in the interpreter here, so be careful, as such tricky bits may not apply within an actual module
You mean it’s not necessary that the symbol will be named x
and that I might get something like LISP’s gensym
or that it might throw an error
?
The scope of an identifier is important when you reference the identifier. In your example, you are using the name of the identifier only - you are inserting the name into a datum.
No scope is involved.
I meant that, in general, we should not try to understand how/why macros work from within the interpreter, as the behaviour within the interpreter can be different than from within a module (and the latter is usually considered “the right way”). In the words of mflatt: “The top-level is hopeless” (https://gist.github.com/samth/3083053)
You are making a symbol 'x
not an identifier x
to be referenced.
Thanks! My misunderstanding was rooted in my common lisp mental baggage.
That there is a difference between an identifier and a symbol is something to get used to, when coming from Common Lisp.
my question was about discovering/displaying the scope of the defined identifier better
I am mystified about this every time I do it wrong (so, usually when I start a new piece of code without copying)
@greg Now I am using borg to manage all my emacs packages. I’ve found that I have to manually load racket-unicode-input-method
. What are the extra steps that package.el
does when racket-mode is installed via “melpa”?
does package.el simply load every .el(c) file in racket-mode?
It also installs the dependencies but that’s pretty much it
Also I don’t think it installs it from melpa, if you go M-x straight-get-recipe
it tells you recipe that points to github
I’m not sure but probably something with the standard Emacs package.el generating autoloads.
Thanks for the pointers!
I also see a borg-update-autoloads
as a low level function but I don’t know how the pieces fit together, or if/how/where you might need to use that (vs. it happening automatically).
Isn’t the scope explicitly defined/displayed by the with-syntax
expression?
Here I’ve been using Emacs for 36 years and only today do I hear about borg
…
Well first commit for borg is Jan 2018 and straight.el is Jan 2017.
Both are barely old enough to drink. And on an Emacs time scale, positively newborn. :slightly_smiling_face:
GEE WHIZ…. TIL that macro transformers merge syntax properties. How long has that been the case? I want to say that the stepper has been around since before that change, but MAN it created some weird weird weird behavior while I was debugging today.
Sorry I forgot the #extreme-old-timers tag on that comment.
Today, we had problems with the handin client on macOS connecting to our handin server, signed with a Let’s Encrypt cert, using a CA cert that expired today. This shouldn’t have been a problem if openssl version >= 1.1.0 , as apparently they have multiple CAs, and only one expired, but old versions of openssl didn’t handle this properly: https://letsencrypt.org/docs/dst-root-ca-x3-expiration-september-2021/
Anyone know why this would affect Racket 8.1 on macOS? Looks to me like Racket ships with a new enough openssl.
We had to switch out the certs with a self-signed one, which worked fine, but it means now I can’t really reproduce the problem.
The OpenSSL build with Mac OS Racket is 1.1.1g.
FWIW, Eli encountered trouble in the last week with a non-self-signed certificate, too. His conclusion was that it had to do with a fullchain file and SSL_CTX_load_verify_locations
in newer OpenSSL version being unhappy with that. That information doesn’t clearly line up with what you report, but maybe there’s some connection.
Thanks! I’m seeing something similar. I’m able to reproduce the issue with the old keys. If you run this server and client on a modern linux machine, it connects fine. But on macOS, it complains. Seems to have to do with verification in the client
Looks like my linux machine is on 1.1.1k.
How would I rebuild the ssl library for macOS, to test whether that’s at fault?
I’m not sure if this is related, but ~every~ many packages in https://pkgs.racket-lang.org currently fails with ssl-connect: connect failed (error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed)
If you rebuild, you should be able to drop a replacement libssl.1.1.dylib
and libcrypto.1.1.dylib
in place in you Racket installation’s lib
directory.
If you want to rebuild exactly as in the pre-built executable package, see https://github.com/racket/racket/blob/master/racket/src/native-libs/README.txt
@sorawee that is related. Looks like that package is hosted at http://www.neilvandyke.org:443\|www.neilvandyke.org:443, which is also using a Let’s Encrypt cert with the same expired root CA
I can connect on linux fine using openssl s_client -connect <http://www.neilvandyke.org:443\|www.neilvandyke.org:443>
but not on my mac
It looks like I can connect with that command on Mac OS 11.5.2, but trying on 10.14.6 ends with “(certificate has expired)”
hm. what openssl versions?
2.8.3 on 11.5.2, 2.6.5 on 10.14.6
From my memory (>= 2016) it has always been the case. The synrtax property’s values can be arbitrary cons trees due to merging
Oh, that’s LibreSSL, though.. not sure how that relates.
grand. still, Racket is only using the packaged version right? Does that example I posted work on your mac 11.5.2?
Yes, Racket is using its own version. I get “bad certificate” when I try to run “server.rkt”.
If the server continues to run, that’s probaby from it launching the browser.
The browser won’t connect because of the hostname issue. You should run racket client.rkt
. That client doesnt’ check the hostname, but does check the chain.
Ok. I get “certificate verify” from “client.rkt” on both Mac versions using Racket
okay. I’m guessing this is an openssl bug then. If the CLI can connect, then it’s probably not related to the trust store on your machine.
And the chain isn’t actually faulty
I tried OpenSSL 1.1.1l and I still get the same result
.. huh
racket on linux uses the system openssl right?
Yes.
FWIW, I also tried OpenSSL 3.0.0, and the result was the same.
okay. then… I have no idea.
You’re sure you got the ssl versions setup right? I just installed OpenSSL 3 on my mac and it seems to connect fine, while the system openssl (libreSSL 2.6.5) doesn’t
This is just using CLI; I haven’t figured out how to compile the libraries for Racket. I’m using Neil’s site as a test.
yeah this has been the case for at least 15 years
I didn’t try command-line openssl
. I was using Racket with 1.1.1l and 3.0.0 .
I tried dropping the binaries libssl.1.1.dylib
and libcrypto.1.1.dylib
in /Application/Racket v8.1/lib
and racket just segfaults when I require openssl
There can bbe all sorts of signing issues. What kind of Mac and which OS version?
macbook air 10.14.6 mojave
I got the binaries from the homebrew install
The reference in libssl1.1.dylib may be directly to the installed libcrypto.1.1.dylib, which would cause problems. A soft link instead of copying might avoid the problems.
that fixed it
still getting the problem with client.rkt
though…
maybe it’s the use of the ssl API that’s at fault…
.. no but it works on my linux machine.
Is the package server on a mac?
If I delete the last certificate in “fullchain.pem” (so, not a full chain), then “client.rkt” works for me.
The package server is on Linux
But it’s also experiencing this problem.. what version of openssl?
Deleting the last cert sort of makes sense. That’s the one involving the expired root CA.
But if I’m understanding these posts from Let’s Encrypt, openssl should basically ignore that last cert, since the second cert is in the trust store. I’ve verified that ISRG Root X1 is in my mac’s trust store…
http://pkgs.racket-lang.org\|pkgs.racket-lang.org is using 1.0.2g and seems to be able to connect to http://www.neilvandyke.org:443\|www.neilvandyke.org:443
http://pkg-build.racket-lang.org\|pkg-build.racket-lang.org is using 1.0.2k-fips and reports “certificate has expired”
Both are EC2 instances.
Is the ISRG Root trusted? *ls* /etc/ca-certificates/extracted/cadir/ISRG_Root_X1.pem
(wouldn’t surprised me if the path was different from my machine)
I see “ISRG Root X1” in “/etc/pki/tls/certs/ca-bundle.crt”
What about DST_Root_CA_X3
Yes
on both?
Yes
Looks like pkgs is Ubuntu, while pkg-build is RedHat.
Removing the DST Root CA X3 on pkg-build allows connecting to http://www.neilvandyke.org:443\|www.neilvandyke.org:443
strange.. I have it on my linux machine, and can connect, but don’t have it on my mac, and can’t
well I’m out of ideas and need dinner. will try something else later.
There’s an old open issue that looks related: https://github.com/racket/racket/issues/2184
And a Twitter thread with debug info about other folks dealing with that Let’s Encrypt fallout https://twitter.com/FiloSottile/status/1443750571064836101?s=20\|https://twitter.com/FiloSottile/status/1443750571064836101?s=20
i get an error using both racket (calling get
from net/http-easy
) and wget on my laptop when connecting to https://expired-r3-test.scotthelme.co.uk/
Is there a canonical way to do hash-ref of a hasheq of two values?
Currently I have:
(define table (make-hash))
(define ref (make-hasheq))
(define (my-ref x y)
(define a (hash-ref! ref x gensym))
(define b (hash-ref! ref y gensym))
(hash-ref! table (cons a b) ...))