diff options
Diffstat (limited to 'tests/programs')
| -rw-r--r-- | tests/programs/capture_long.zc | 26 | ||||
| -rw-r--r-- | tests/programs/struct_static_call.zc | 31 | ||||
| -rw-r--r-- | tests/programs/void_main.zc | 8 |
3 files changed, 65 insertions, 0 deletions
diff --git a/tests/programs/capture_long.zc b/tests/programs/capture_long.zc new file mode 100644 index 0000000..52736a4 --- /dev/null +++ b/tests/programs/capture_long.zc @@ -0,0 +1,26 @@ +namespace; +include rt, std; + +// a capture holds 256 characters and drops the rest. end() must still put its +// 0 inside the buffer, even when the capture was full: the length is 256 and the +// last kept character is the 256th one written (index 255, 'a' + 255 % 26 = 'v'). +// a block allocated right after the buffer is checked afterwards: a 0 written one +// word past the buffer would land in its header and read as a bad or freed block. +memdebug on; // header checks make a write into a neighbouring block visible +fn capture_long() { + let buf = std.capture.start(); + int* next = rt.new(8); + int i = 0; + while (i < 300) { rt.put_c('a' + i % 26); i++; } + std.capture.end(buf); + next[0] = 7; // stops with "bad heap pointer" if its header was overwritten + rt.put_n(next[0]); rt.put_c(10); // 7 + return buf; +} +memdebug off; // the header check only searches 64 words back, so the long buffer is read unchecked +fn main() { + char* buf = capture_long(); + rt.put_n(rt.len_w(buf)); rt.put_c(10); // 256 + rt.put_c(buf[255]); rt.put_c(10); // v + return 0; +} diff --git a/tests/programs/struct_static_call.zc b/tests/programs/struct_static_call.zc new file mode 100644 index 0000000..73fc0fc --- /dev/null +++ b/tests/programs/struct_static_call.zc @@ -0,0 +1,31 @@ +namespace; +include rt; + +// a static function of a struct can be called by its bare name inside the struct's +// methods and static functions, as a struct constant can. the struct's own function +// wins over a top-level one of the same name; outside the struct only S.name reaches it. +int lim() { return 100; } +int base() { return 7; } + +struct S { + int v; + static int lim() { return 3; } + static int twice(int x) { return x * 2; } + static int both() { return lim() + twice(4); } + int get() { return lim() + this.v; } + int scaled() { return twice(this.v) + later(); } + int top() { return base(); } + static int later() { return 1000; } +} + +int main() { + S s; + s.v = 5; + rt.put_n(S.lim()); rt.put_c(32); // 3 + rt.put_n(lim()); rt.put_c(32); // 100, the global one + rt.put_n(S.both()); rt.put_c(32); // 3 + 8 + rt.put_n(s.get()); rt.put_c(32); // 3 + 5 + rt.put_n(s.scaled()); rt.put_c(32); // 10 + 1000, a static function declared later + rt.put_n(s.top()); rt.put_c(10); // 7, a global that the struct has no member of + return 0; +} diff --git a/tests/programs/void_main.zc b/tests/programs/void_main.zc new file mode 100644 index 0000000..b4fde70 --- /dev/null +++ b/tests/programs/void_main.zc @@ -0,0 +1,8 @@ +namespace; +include rt; + +// main may be declared void: the runtime ignores what main returns (docs/SPEC.md 5.2.5, 8.1.3), +// so a run-only image, whose run.zc declares int main();, accepts it as zy does. +void main() { + rt.put_s("void main"); rt.put_c(10); +} |
