aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChloe Kudryavtsev <code@toast.bunkerlabs.net>2023-07-02 09:45:00 +0200
committerChloe Kudryavtsev <code@toast.bunkerlabs.net>2023-07-02 09:45:00 +0200
commit53775bcf6140282a1653e74d6a66f83d21b457e0 (patch)
tree4371f695daedb656a3a6db1abbc1bdbbafe41182 /src
parentprepare 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.
Diffstat (limited to 'src')
-rw-r--r--src/jurl.h17
-rw-r--r--src/polyfill.c38
2 files changed, 45 insertions, 10 deletions
diff --git a/src/jurl.h b/src/jurl.h
index 5a318f6..83a0a22 100644
--- a/src/jurl.h
+++ b/src/jurl.h
@@ -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;
}