Files
scriptc/tests/library-mode/cstrings/probe.c
T
Chris Tate 370bf5962d Add the cstring class to library profiles
Library exports and callbacks passed text only as a pointer and length.
profile_format 2 adds the cstring class, a NUL-terminated `const char *`
(an i32 pointer in Wasm reactors), for export parameters, export results
and callback parameters. Parameters are copied in and decoded as UTF-8,
with U+FFFD for malformed bytes; a NULL pointer is the SC4012
host-contract trap. Results live in the result arena like string
results. A result or callback argument containing U+0000 traps instead
of being truncated.

Closes #615
Co-authored-by: ailuoku6 <23209876+ailuoku6@users.noreply.github.com>
2026-10-17 23:40:06 -05:00

77 lines
2.7 KiB
C

/* cstring probe, mode-selected by argv[1]:
* ok — cstring parameters copy in (UTF-8, U+FFFD for malformed
* bytes), cstring results are NUL-terminated arena copies,
* and a cstring callback argument arrives NUL-terminated
* nullarg — a NULL cstring parameter is the SC4012 host-contract trap
* nulresult — a result holding U+0000 traps instead of truncating
* nularg — a callback argument holding U+0000 traps the same way
*/
#include <setjmp.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
extern void kc_init(void);
extern void kc_set_panic_sink(void (*fn)(void *, const uint8_t *, size_t, uint64_t), void *ctx);
extern void kc_collect(void);
extern int32_t kc_set_callback(const char *name, void (*fn)(void), void *ctx);
extern const char *kc_greet(const char *name);
extern double kc_length(const char *text);
extern double kc_echo(const char *text);
extern const char *kc_with_nul(void);
extern double kc_echo_nul(void);
static jmp_buf trap_jmp;
static void sink(void *ctx, const uint8_t *msg, size_t len, uint64_t addr) {
(void)ctx; (void)addr;
/* structured: 0x01 text 0x1F code 0x1F symbol */
const uint8_t *p = msg + 1, *end = msg + len;
const char *names[3] = {"text", "code", "symbol"};
for (int field = 0; field < 3 && p <= end; field++) {
const uint8_t *sep = memchr(p, 0x1f, (size_t)(end - p));
const uint8_t *stop = sep != NULL ? sep : end;
printf("%s=[%.*s]\n", names[field], (int)(stop - p), (const char *)p);
if (sep == NULL) break;
p = sep + 1;
}
longjmp(trap_jmp, 1);
}
static void on_log(void *ctx, const char *text, double n) {
(void)ctx;
printf("log: %s (strlen %zu, n %.0f)\n", text, strlen(text), n);
}
int main(int argc, char **argv) {
const char *mode = argc > 1 ? argv[1] : "ok";
kc_set_panic_sink(sink, NULL);
kc_init();
printf("register: %d\n", (int)kc_set_callback("log", (void (*)(void))on_log, NULL));
if (setjmp(trap_jmp) != 0) {
printf("trapped\n");
return 0;
}
if (strcmp(mode, "ok") == 0) {
const char *g = kc_greet("w\xC3\xB6rld");
printf("greet: %s (strlen %zu)\n", g, strlen(g));
printf("length ascii: %.0f\n", kc_length("abc"));
printf("length utf8: %.0f\n", kc_length("caf\xC3\xA9"));
printf("length malformed: %.0f\n", kc_length("a\xFF" "b"));
printf("length empty: %.0f\n", kc_length(""));
printf("echo: %.0f\n", kc_echo("quiet"));
kc_collect();
printf("done\n");
} else if (strcmp(mode, "nullarg") == 0) {
kc_length(NULL);
printf("UNREACHABLE\n");
} else if (strcmp(mode, "nulresult") == 0) {
kc_with_nul();
printf("UNREACHABLE\n");
} else if (strcmp(mode, "nularg") == 0) {
kc_echo_nul();
printf("UNREACHABLE\n");
}
return 0;
}