diff options
| author | 2023-07-02 09:45:00 +0200 | |
|---|---|---|
| committer | 2023-07-02 09:45:00 +0200 | |
| commit | 53775bcf6140282a1653e74d6a66f83d21b457e0 (patch) | |
| tree | 4371f695daedb656a3a6db1abbc1bdbbafe41182 | |
| parent | prepare for 1.4.1 tag (diff) | |
patch against getcbytes bug, to be tested on linux
I didn't catch this in development because macos helpfully zeroes out
all malloc pages on allocation, so my buffers *were* \0-terminated.
Getcbytes is called in a few spots, namely in setopt, and 4 mime
functions.
We only ever call setopt using the partial `pt`, so we can just `comp`
it with `freeze`.
As for mime, we insert a `freeze` in each of the 4 handlers.
Either way, also backport the new getcbytes, which still has the failure
condition, but only under very specific circumstances.
| -rw-r--r-- | jurl/init.janet | 6 | ||||
| -rw-r--r-- | jurl/mime.janet | 8 | ||||
| -rw-r--r-- | src/jurl.h | 17 | ||||
| -rw-r--r-- | src/polyfill.c | 38 |
4 files changed, 52 insertions, 17 deletions
diff --git a/jurl/init.janet b/jurl/init.janet index f95a39d..31d23b5 100644 --- a/jurl/init.janet +++ b/jurl/init.janet @@ -197,7 +197,7 @@ (eachp [k v] *default-options* (put h k v)) h))) - (def pt (partial put handle)) + (def pt (comp freeze (partial put handle))) (var url url) (when parts (each part parts @@ -471,7 +471,7 @@ or a non-2xx HTTP response code. Can also take the following named parameters: - * opts: Options to intelligently merge with the resulting query. + * opts: Options to intelligently merge with the resulting query. To see what can go into opts, see the docs for `request`. ``` [url &named opts] @@ -490,7 +490,7 @@ Can also take the following named parameters: * content-type: The content type to set. Defaults to `text/plain`. - * opts: Options to intelligently merge with the resulting query. + * opts: Options to intelligently merge with the resulting query. To see what can go into opts, see the docs for `request`. ``` [url body &named content-type opts] diff --git a/jurl/mime.janet b/jurl/mime.janet index 8f05ac3..1308e89 100644 --- a/jurl/mime.janet +++ b/jurl/mime.janet @@ -20,7 +20,7 @@ [:bytes b] (:data handle b) # to differentiate against bytes, pass tuple starting with :file - [:file fname] (:filedata handle fname) + [:file fname] (:filedata handle (freeze fname)) # to differentiate against bytes, pass tuple starting with :mime [:mime amime] (:subparts handle amime) @@ -34,9 +34,9 @@ (error "mime data may only be bytes, jurl-mime, [:bytes bytes], [:file filename], [:mime jurl-mime], or [size callback]")) - (when name (:name handle name)) - (when filename (:filename handle filename)) - (when mimetype (:type handle mimetype)) + (when name (:name handle (freeze name))) + (when filename (:filename handle (freeze filename))) + (when mimetype (:type handle (freeze mimetype))) (when encoder (:encoder handle encoder)) (when headers (:headers handle (->> headers @@ -4,12 +4,21 @@ // = polyfills #if JANET_VERSION_MAJOR < 2 && JANET_VERSION_MINOR < 28 -#define POLYFILL_CBYTES +#define POLYFILL_GETCBYTES +#define POLYFILL_OPTCBYTES +#elif JANET_VERSION_MAJOR < 2 && JANET_VERSION_MINOR < 30 && JANET_VERSION_PATCH < 2 +// TODO: consider making this unconditional, see polyfill.c for details +#define POLYFILL_GETCBYTES #endif -#ifdef POLYFILL_CBYTES -const char *janet_getcbytes(const Janet *argv, int32_t n); -const char *janet_optcbytes(const Janet *argv, int32_t argc, int32_t n, const char *dflt); +#ifdef POLYFILL_GETCBYTES +const char *poly_getcbytes(const Janet *argv, int32_t n); +#define janet_getcbytes poly_getcbytes +#endif + +#ifdef POLYFILL_OPTCBYTES +const char *poly_optcbytes(const Janet *argv, int32_t argc, int32_t n, const char *dflt); +#define janet_optcbytes poly_optcbytes #endif // = structures diff --git a/src/polyfill.c b/src/polyfill.c index f7db312..c7d3172 100644 --- a/src/polyfill.c +++ b/src/polyfill.c @@ -1,16 +1,42 @@ #include "jurl.h" -#ifdef POLYFILL_CBYTES -const char* janet_getcbytes(const Janet *argv, int32_t n) { +#ifdef POLYFILL_GETCBYTES +const char *poly_getcbytes(const Janet *argv, int32_t n) { + /* Ensure buffer 0-padded */ + if (janet_checktype(argv[n], JANET_BUFFER)) { + JanetBuffer *b = janet_unwrap_buffer(argv[n]); + if ((b->gc.flags & JANET_BUFFER_FLAG_NO_REALLOC) && b->count == b->capacity) { + /* Make a copy with janet_smalloc in the rare case we have a buffer that + * cannot be realloced and pushing a 0 byte would panic. */ + + /* FIXME: This will fail under jurl, since jurl pre-supposes that the + * lifetime of a getcbytes call string is equivalent to the lifetime + * of the given Janet value. Maybe manually garbage collect? */ + char *new_string = janet_smalloc(b->count + 1); + memcpy(new_string, b->data, b->count); + new_string[b->count] = 0; + if (strlen(new_string) != (size_t) b->count) goto badzeros; + return new_string; + } else { + /* Ensure trailing 0 */ + janet_buffer_push_u8(b, 0); + b->count--; + if (strlen((char *)b->data) != (size_t) b->count) goto badzeros; + return (const char *) b->data; + } + } JanetByteView view = janet_getbytes(argv, n); const char *cstr = (const char *)view.bytes; - if (strlen(cstr) != (size_t) view.len) { - janet_panic("bytes contain embedded 0s"); - } + if (strlen(cstr) != (size_t) view.len) goto badzeros; return cstr; + +badzeros: + janet_panic("bytes contain embedded 0s"); } +#endif -const char *janet_optcbytes(const Janet *argv, int32_t argc, int32_t n, const char *dflt) { +#ifdef POLYFILL_OPTCBYTES +const char *poly_optcbytes(const Janet *argv, int32_t argc, int32_t n, const char *dflt) { if (n >= argc || janet_checktype(argv[n], JANET_NIL)) { return dflt; } |
