Skip to content

Commit 5e47c06

Browse files
authored
Merge pull request #27 from callisto-lang/SafeStack
make callisto safe
2 parents 9a193a5 + 1708649 commit 5e47c06

File tree

10 files changed

+675
-45
lines changed

10 files changed

+675
-45
lines changed

editors/micro_callisto.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ rules:
77
- statement: "\\b(func|end|begin|asm|include|inline|if|then|elseif|else|while|do)\\b"
88
- statement: "\\b(let|enable|requires|struct|version|return|const|enum|restrict)\\b"
99
- statement: "\\b(continue|break|union|alias|overwrite|error|extern|call|raw)\\b"
10-
- statement: "\\b(implement|as|try|catch|throw)\\b"
10+
- statement: "\\b(implement|as|try|catch|throw|unsafe|man)\\b"
1111
- type: "\\b(addr|void|u8|i8|u16|i16|u32|i32|u64|i64|size|usize|cell|array)\\b"
1212

1313
- constant.string:

source/app.d

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import std.algorithm;
99
import callisto.error;
1010
import callisto.compiler;
1111
import callisto.language;
12+
import callisto.stackCheck;
1213
import callisto.codeRemover;
1314
import callisto.preprocessor;
1415
import callisto.backends.lua;
@@ -17,6 +18,8 @@ import callisto.backends.rm86;
1718
import callisto.backends.arm64;
1819
import callisto.backends.x86_64;
1920

21+
const static string appVersion = "Beta 0.11.0";
22+
2023
const static string usage = "
2124
Callisto Compiler
2225
=================
@@ -43,6 +46,8 @@ Flags:
4346
-ka - Keeps the generated assembly
4447
-al - Prints assembly line numbers for Callisto nodes
4548
-os OS - Sets the operating system for the backend (see below)
49+
-sc - Stop after stack check
50+
-scf - Show functions in stack checker
4651
--help - Shows this help text
4752
4853
Backends and their operating systems:
@@ -88,6 +93,9 @@ int main(string[] args) {
8893
bool keepAssembly;
8994
bool assemblyLines;
9095
string os = "DEFAULT";
96+
bool onlyStackCheck = false;
97+
bool noStackCheck;
98+
bool stackCheckerFunctions = false;
9199

92100
// choose default backend
93101
version (X86_64) {
@@ -198,7 +206,8 @@ int main(string[] args) {
198206
break;
199207
}
200208
case "--version": {
201-
writeln("Callisto compiler beta 0.10.1");
209+
writeln("The Glorious Callisto Compilation System");
210+
writeln(appVersion);
202211
return 0;
203212
}
204213
case "-a": {
@@ -284,6 +293,18 @@ int main(string[] args) {
284293
os = args[i];
285294
break;
286295
}
296+
case "-sc": {
297+
onlyStackCheck = true;
298+
break;
299+
}
300+
case "-nsc": {
301+
noStackCheck = true;
302+
break;
303+
}
304+
case "-scf": {
305+
stackCheckerFunctions = true;
306+
break;
307+
}
287308
case "--help": {
288309
writeln(usage.strip());
289310
return 0;
@@ -391,6 +412,35 @@ int main(string[] args) {
391412
if (!codeRemover.success) return 1;
392413
}
393414

415+
auto stackChecker = new StackChecker();
416+
try {
417+
if (!noStackCheck) stackChecker.Evaluate(nodes);
418+
}
419+
catch (StackCheckerError) {
420+
if (stackCheckerFunctions) {
421+
stackChecker.DumpFunctions();
422+
}
423+
return 1;
424+
}
425+
426+
if (stackChecker.stack.length > 0) {
427+
try {
428+
stackChecker.StackOverflow(nodes[$ - 1], 0);
429+
}
430+
catch (StackCheckerError) {
431+
return 1;
432+
}
433+
}
434+
435+
if (stackCheckerFunctions) {
436+
stackChecker.DumpFunctions();
437+
}
438+
439+
if (onlyStackCheck) {
440+
writeln("no errors");
441+
return 0;
442+
}
443+
394444
compiler.versions = preproc.versions;
395445

396446
compiler.Compile(nodes);

source/backends/arm64.d

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ private struct Word {
2525
bool inline;
2626
Node[] inlineNodes;
2727
bool error;
28+
Type[] params;
2829

2930
// for C words
30-
Type[] params;
3131
Type ret;
3232
bool isVoid;
3333
string symbolName;
@@ -507,6 +507,16 @@ class BackendARM64 : CompilerBackend {
507507

508508
thisFunc = node.name;
509509

510+
Type[] params;
511+
512+
foreach (ref type ; node.paramTypes) {
513+
if (!TypeExists(type)) {
514+
Error(node.error, "Type '%s' doesn't exist", type);
515+
}
516+
517+
params ~= GetType(type);
518+
}
519+
510520
if (node.inline) {
511521
if (node.errors) {
512522
LoadAddress("x9", "__global_" ~ Sanitise("_cal_exception"));
@@ -515,15 +525,16 @@ class BackendARM64 : CompilerBackend {
515525
}
516526

517527
words[node.name] = Word(
518-
WordType.Callisto, true, node.nodes
528+
WordType.Callisto, true, node.nodes, node.errors, params
519529
);
520530
}
521531
else {
522532
assert(!inScope);
523533
inScope = true;
524534

525535
words[node.name] = Word(
526-
node.raw? WordType.Raw : WordType.Callisto , false, [], node.errors
536+
node.raw? WordType.Raw : WordType.Callisto , false, [], node.errors,
537+
params
527538
);
528539

529540
string symbol =
@@ -552,7 +563,7 @@ class BackendARM64 : CompilerBackend {
552563
Error(node.error, "Structures cannot be used in function parameters");
553564
}
554565
}
555-
if (paramSize > 0) {
566+
if ((paramSize > 0) && !node.manual) {
556567
output ~= format("sub x20, x20, #%d\n", paramSize);
557568
foreach (ref var ; variables) {
558569
var.offset += paramSize;
@@ -1150,6 +1161,14 @@ class BackendARM64 : CompilerBackend {
11501161
Error(node.error, "Non-callisto functions can't throw");
11511162
}
11521163

1164+
if (word.params.length > 0) {
1165+
output ~= format("sub x21, x19, #%d\n", word.params.length * 8);
1166+
output ~= "str x21, [x20, #-8]!\n";
1167+
}
1168+
else {
1169+
output ~= "str x19, [x20, #-8]!\n";
1170+
}
1171+
11531172
if (word.inline) {
11541173
foreach (inode ; word.inlineNodes) {
11551174
compiler.CompileNode(inode);
@@ -1159,12 +1178,15 @@ class BackendARM64 : CompilerBackend {
11591178
output ~= format("bl __func__%s\n", node.func.Sanitise());
11601179
}
11611180

1181+
output ~= "ldr x21, [x20], #8\n";
1182+
11621183
++ blockCounter;
11631184

11641185
LoadAddress("x9", "__global_" ~ Sanitise("_cal_exception"));
11651186
output ~= "ldr x9, [x9]\n";
11661187
output ~= "cmp x9, #0\n";
11671188
output ~= format("beq __catch_%d_end\n", blockCounter);
1189+
output ~= "mov x19, x21\n";
11681190

11691191
// create scope
11701192
auto oldVars = variables.dup;

source/backends/lua.d

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,19 @@ private struct Word {
3232
bool inline;
3333
Node[] inlineNodes;
3434
bool error;
35+
Type[] params;
3536
}
3637

3738
class BackendLua : CompilerBackend {
38-
Word[string] words;
39-
string thisFunc;
40-
bool inScope;
41-
uint blockCounter;
42-
bool inWhile;
43-
uint currentLoop;
44-
bool useLibc;
45-
ulong globalStack = 524288;
46-
ulong arrayStack = 524287;
39+
Word[string] words;
40+
string thisFunc;
41+
bool inScope;
42+
uint blockCounter;
43+
bool inWhile;
44+
uint currentLoop;
45+
bool useLibc;
46+
ulong globalStack = 524288;
47+
ulong arrayStack = 524287;
4748

4849
this() {
4950
// built in integer types
@@ -106,6 +107,7 @@ class BackendLua : CompilerBackend {
106107
output ~= "gsp = 524288;\n";
107108
output ~= "regA = 0;\n";
108109
output ~= "regB = 0;\n";
110+
output ~= "dspBackup = 0;\n";
109111

110112
output ~= "
111113
function cal_pop()
@@ -275,17 +277,29 @@ class BackendLua : CompilerBackend {
275277

276278
thisFunc = node.name;
277279

280+
Type[] params;
281+
282+
foreach (ref type ; node.paramTypes) {
283+
if (!TypeExists(type)) {
284+
Error(node.error, "Type '%s' doesn't exist", type);
285+
}
286+
287+
params ~= GetType(type);
288+
}
289+
278290
if (node.inline) {
279291
auto globalExtra = cast(GlobalExtra*) GetGlobal("_cal_exception").extra;
280292
output ~= format("mem[%d] = 0\n", globalExtra.addr);
281293

282-
words[node.name] = Word(WordType.Callisto, true, node.nodes, node.errors);
294+
words[node.name] = Word(
295+
WordType.Callisto, true, node.nodes, node.errors, params
296+
);
283297
}
284298
else {
285299
assert(!inScope);
286300
inScope = true;
287301

288-
words[node.name] = Word(WordType.Callisto, false, [], node.errors);
302+
words[node.name] = Word(WordType.Callisto, false, [], node.errors, params);
289303

290304
output ~= format("function func__%s()\n", node.name.Sanitise());
291305

@@ -302,7 +316,7 @@ class BackendLua : CompilerBackend {
302316
Error(node.error, "Structures cannot be used in function parameters");
303317
}
304318
}
305-
if (paramSize > 0) {
319+
if ((paramSize > 0) && !node.manual) {
306320
output ~= format("vsp = vsp - %d\n", paramSize);
307321
foreach (ref var ; variables) {
308322
var.offset += paramSize;
@@ -849,6 +863,9 @@ class BackendLua : CompilerBackend {
849863
Error(node.error, "Non-callisto functions can't throw");
850864
}
851865

866+
output ~= "vsp = vsp - 1\n";
867+
output ~= format("mem[vsp] = dsp - %d\n", word.params.length);
868+
852869
if (word.inline) {
853870
foreach (inode ; word.inlineNodes) {
854871
compiler.CompileNode(inode);
@@ -858,6 +875,9 @@ class BackendLua : CompilerBackend {
858875
output ~= format("func__%s()\n", node.func.Sanitise());
859876
}
860877

878+
output ~= "dspBackup = mem[vsp]\n";
879+
output ~= "vsp = vsp + 1\n";
880+
861881
++ blockCounter;
862882

863883
auto global = GetGlobal("_cal_exception");
@@ -866,6 +886,7 @@ class BackendLua : CompilerBackend {
866886
output ~= format("if mem[%d] == 0 then\n", globalExtra.addr);
867887
output ~= format("goto catch_%d_end\n", blockCounter);
868888
output ~= "end\n";
889+
output ~= "dsp = dspBackup\n";
869890

870891
// create scope
871892
auto oldVars = variables.dup;

source/backends/rm86.d

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ private struct Word {
1616
bool inline;
1717
Node[] inlineNodes;
1818
bool error;
19+
Type[] params;
1920
}
2021

2122
private struct RM86Opts {
@@ -67,11 +68,6 @@ class BackendRM86 : CompilerBackend {
6768
NewConst(format("%s.sizeof", type.name), cast(long) type.size);
6869
}
6970

70-
if (!opts.noDos) { // TODO: remove this
71-
globals ~= Global("__rm86_argv", GetType("addr"), false, 0);
72-
globals ~= Global("__rm86_arglen", GetType("cell"), false, 0);
73-
}
74-
7571
globals ~= Global("_cal_exception", GetType("Exception"), false, 0);
7672
}
7773

@@ -359,18 +355,28 @@ class BackendRM86 : CompilerBackend {
359355

360356
thisFunc = node.name;
361357

358+
Type[] params;
359+
360+
foreach (ref type ; node.paramTypes) {
361+
if (!TypeExists(type)) {
362+
Error(node.error, "Type '%s' doesn't exist", type);
363+
}
364+
365+
params ~= GetType(type);
366+
}
367+
362368
if (node.inline) {
363369
if (node.errors) {
364370
output ~= format("mov word [__global_%s], 0\n", Sanitise("_cal_exception"));
365371
}
366372

367-
words[node.name] = Word(false, true, node.nodes, node.errors);
373+
words[node.name] = Word(false, true, node.nodes, node.errors, params);
368374
}
369375
else {
370376
assert(!inScope);
371377
inScope = true;
372378

373-
words[node.name] = Word(node.raw, false, [], node.errors);
379+
words[node.name] = Word(node.raw, false, [], node.errors, params);
374380

375381
string symbol =
376382
node.raw? node.name : format("__func__%s", node.name.Sanitise());
@@ -391,7 +397,7 @@ class BackendRM86 : CompilerBackend {
391397
Error(node.error, "Structures cannot be used in function parameters");
392398
}
393399
}
394-
if (paramSize > 0) {
400+
if ((paramSize > 0) && !node.manual) {
395401
output ~= format("sub sp, %d\n", paramSize);
396402
foreach (ref var ; variables) {
397403
var.offset += paramSize;
@@ -980,6 +986,16 @@ class BackendRM86 : CompilerBackend {
980986
Error(node.error, "Non-callisto functions can't throw");
981987
}
982988

989+
if (word.params.length > 0) {
990+
output ~= format("lea di, [si - %d]\n", word.params.length * 2);
991+
output ~= "push di\n";
992+
}
993+
else {
994+
output ~= "push si\n";
995+
}
996+
997+
++ blockCounter;
998+
983999
if (word.inline) {
9841000
foreach (inode ; word.inlineNodes) {
9851001
compiler.CompileNode(inode);
@@ -989,11 +1005,12 @@ class BackendRM86 : CompilerBackend {
9891005
output ~= format("call __func__%s\n", node.func.Sanitise());
9901006
}
9911007

992-
++ blockCounter;
1008+
output ~= "pop di\n";
9931009

9941010
output ~= format("mov ax, [__global_%s]\n", Sanitise("_cal_exception"));
9951011
output ~= "cmp ax, 0\n";
9961012
output ~= format("je __catch_%d_end\n", blockCounter);
1013+
output ~= "mov si, di\n";
9971014

9981015
// create scope
9991016
auto oldVars = variables.dup;

0 commit comments

Comments
 (0)