Fun
0.41.5
The programming language that makes You have fun
Main Page
Data Structures
Files
File List
Globals
Loading...
Searching...
No Matches
src
vm
os
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. */
38
void
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
47
case
OP_RANDOM_NUMBER
: {
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
145
Value
s
=
make_string
(
hex
);
146
free
(
raw
);
147
free
(
hex
);
148
free_value
(lv);
149
push_value
(vm,
s
);
150
break
;
151
}
b
uint32_t b
Definition
band.c:32
OP_RANDOM_NUMBER
@ OP_RANDOM_NUMBER
Definition
bytecode.h:154
ok
int ok
Definition
contains.c:38
len
size_t len
Definition
input_line.c:102
n
int n
Definition
insert.c:41
hex
char * hex
Definition
md5.c:39
free_value
free_value(lv)
free
free(raw)
raw
unsigned char * raw
Definition
random_number.c:79
MAX_RAW
const int64_t MAX_RAW
Definition
random_number.c:71
push_value
push_value(vm, s)
s
uint32_t s
Definition
rol.c:31
fd
int fd
Definition
serial_open.c:92
Value
Tagged union representing a Fun value.
Definition
value.h:68
Value::i
int64_t i
Definition
value.h:71
Value::type
ValueType type
Definition
value.h:69
make_string
Value make_string(const char *s)
Construct a string Value by duplicating the given C string.
Definition
value.c:95
VAL_INT
@ VAL_INT
Definition
value.h:51
fprintf
#define fprintf
Definition
vm.c:200
exit
#define exit(code)
Definition
vm.c:230
Generated on
for Fun by
1.16.1