Fun 0.41.5
The programming language that makes You have fun
Loading...
Searching...
No Matches
random_number.c
Go to the documentation of this file.
1/*
2 * This file is part of the Fun programming language.
3 * https://fun-lang.xyz/
4 *
5 * Copyright 2025 Johannes Findeisen <you@hanez.org>
6 * Licensed under the terms of the Apache-2.0 license.
7 * https://opensource.org/license/apache-2-0
8 */
9
23
24#include <inttypes.h>
25#include <stdint.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30/* Platform-specific headers guarded per OS to avoid leaking problematic macros */
31#if defined(_WIN32) || defined(_WIN64)
32#include <bcrypt.h>
33#include <windows.h>
34#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
35#include <stdlib.h>
36#include <sys/random.h>
37/* On some BSDs, arc4random_buf might be hidden by _POSIX_C_SOURCE. */
38void arc4random_buf(void *, size_t);
39#elif defined(__unix__)
40#if __has_include(<sys/random.h>)
41#include <sys/random.h>
42#endif
43#include <fcntl.h>
44#include <unistd.h>
45#endif
46
48 /* pop requested raw byte length */
49 Value lv = pop_value(vm);
50 if (lv.type != VAL_INT) {
51 fprintf(stderr, "Runtime type error: random_number(len) expects integer length\n");
52 free_value(lv);
53 /* For safety, push empty string so callers expecting a value won't underflow */
54 push_value(vm, make_string(""));
55 break;
56 }
57 int64_t len = lv.i;
58 if (len < 0) {
59 fprintf(stderr, "random_number error: negative length (%" PRId64 ")\n", len);
60 free_value(lv);
61 push_value(vm, make_string(""));
62 break;
63 }
64 if (len == 0) {
65 free_value(lv);
66 push_value(vm, make_string(""));
67 break;
68 }
69
70 /* Cap to prevent excessive allocations (max 1 MiB raw -> 2 MiB hex) */
71 const int64_t MAX_RAW = (1LL << 20);
72 if (len > MAX_RAW) {
73 fprintf(stderr, "random_number error: requested length too large (%" PRId64 ", max %" PRId64 ")\n", len, MAX_RAW);
74 free_value(lv);
75 push_value(vm, make_string(""));
76 break;
77 }
78
79 unsigned char *raw = (unsigned char *)malloc((size_t)len);
80 char *hex = (char *)malloc((size_t)len * 2 + 1);
81 if (!raw || !hex) {
82 if (raw) free(raw);
83 if (hex) free(hex);
84 free_value(lv);
85 fprintf(stderr, "Out of memory in random_number\n");
86 exit(1);
87 }
88
89 int ok = 0;
90
91 /* --- Fill raw with cryptographically secure random bytes from the OS --- */
92#if defined(_WIN32) || defined(_WIN64)
93 {
94 /* Windows: use BCryptGenRandom */
95 NTSTATUS st = BCryptGenRandom(NULL, raw, (ULONG)len, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
96 ok = (st == 0);
97 }
98#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
99 {
100 arc4random_buf(raw, (size_t)len);
101 ok = 1;
102 }
103#elif defined(__unix__)
104 {
105/* Prefer getrandom if available, otherwise /dev/urandom */
106#if __has_include(<sys/random.h>)
107 ssize_t n = getrandom(raw, (size_t)len, 0);
108 ok = (n == (ssize_t)len);
109#else
110 ok = 0;
111#endif
112 if (!ok) {
113 int fd = open("/dev/urandom", O_RDONLY);
114 if (fd >= 0) {
115 size_t off = 0;
116 ssize_t n;
117 while (off < (size_t)len && (n = read(fd, raw + off, (size_t)len - off)) > 0)
118 off += (size_t)n;
119 close(fd);
120 ok = (off == (size_t)len);
121 }
122 }
123 }
124#else
125 ok = 0;
126#endif
127
128 if (!ok) {
129 free(raw);
130 free(hex);
131 free_value(lv);
132 fprintf(stderr, "random_number error: OS RNG unavailable or failed\n");
133 exit(1);
134 }
135
136 /* hex encode */
137 static const char hexdig[] = "0123456789abcdef";
138 for (int64_t i = 0; i < len; ++i) {
139 unsigned char b = raw[i];
140 hex[2 * i] = hexdig[(b >> 4) & 0xF];
141 hex[2 * i + 1] = hexdig[b & 0xF];
142 }
143 hex[len * 2] = '\0';
144
150 break;
151}
uint32_t b
Definition band.c:32
@ OP_RANDOM_NUMBER
Definition bytecode.h:154
int ok
Definition contains.c:38
size_t len
Definition input_line.c:102
int n
Definition insert.c:41
char * hex
Definition md5.c:39
free_value(lv)
free(raw)
unsigned char * raw
const int64_t MAX_RAW
push_value(vm, s)
uint32_t s
Definition rol.c:31
int fd
Definition serial_open.c:92
Tagged union representing a Fun value.
Definition value.h:68
int64_t i
Definition value.h:71
ValueType type
Definition value.h:69
Value make_string(const char *s)
Construct a string Value by duplicating the given C string.
Definition value.c:95
@ VAL_INT
Definition value.h:51
#define fprintf
Definition vm.c:200
#define exit(code)
Definition vm.c:230