ldc icon indicating copy to clipboard operation
ldc copied to clipboard

Memset is not typechecked, leads to "not enough arguments on the stack for drop" error

Open andy-hanson opened this issue 4 years ago • 2 comments

To reproduce, put this content in a.d:

struct A {
	this(long[9] x_) { x = x_; }
	long[9] x;
}

extern(C) void _start() {
	A a = A([0, 0, 0, 0, 0, 0, 0, 0, 0]);
}

extern(C) @system pure void memset(scope ubyte* s, immutable int c, immutable size_t n) {
	foreach (immutable size_t i; 0 .. n)
		s[i] = cast(ubyte) c;
}

extern (C) @system pure void* memcpy(return scope ubyte* s1, scope const ubyte* s2, immutable size_t n) {
	foreach (immutable size_t i; 0 .. n)
		s1[i] = s2[i];
	return s1;
}

Then run:

ldc2 -mtriple=wasm32-unknown-unknown-wasm a.d
node -p "WebAssembly.instantiate(require('fs').readFileSync('a.wasm'), {}).catch(console.error)"

The output is:

Promise { <pending> }
[CompileError: WebAssembly.instantiate(): Compiling function #2:"_start" failed: not enough arguments on the stack for drop, expected 1 more @+480]

The error is that memset returned void instead of void*.

Tested with ldc 1.27.1, based on DMD v2.097.2 and LLVM 12.0.1; and node 16.6.2.

andy-hanson avatar Oct 03 '21 16:10 andy-hanson

I believe your issue is not solvable by the D compiler. memset is not a reserved or special function from a D language point of view. So if you want to write a memset function that returns void or a float you are free to do so.

JohanEngelen avatar Oct 03 '21 19:10 JohanEngelen

A similar issue: In optimized builds only, the compiler may insert a call to memset into the implementation of memset, leading to an infinite recursion.

extern(C) void _start() {}

ubyte[65] someBytes;
extern(C) void callMemset() {
	memset(someBytes.ptr, 42, 65);
}

extern(C) ubyte* memset(ubyte* dest, immutable int c, immutable size_t n) {
	return helper(dest, c, n);
}

ubyte* helper(ubyte* dest, immutable int c, immutable size_t n) {
	foreach (immutable size_t i; 0 .. n)
		dest[i] = cast(ubyte) c;
	return dest;
}
$ ldc2 -ofa.wasm -mtriple=wasm32-unknown-unknown-wasm -betterC -O1 a.d && node -p "WebAssembly.instantiate(require('fs').readFileSync('a.wasm'), {}).then(x => x.instance.exports.callMemset()).catch(console.error)"
Promise { <pending> }
RangeError: Maximum call stack size exceeded
    at memset (wasm://wasm/cd74f04a:wasm-function[2]:0xaa)
    at _D1a6helperFNaMNkPhyiykZQh (wasm://wasm/cd74f04a:wasm-function[3]:0xc7)
    at memset (wasm://wasm/cd74f04a:wasm-function[2]:0xb1)
    at _D1a6helperFNaMNkPhyiykZQh (wasm://wasm/cd74f04a:wasm-function[3]:0xc7)
    at memset (wasm://wasm/cd74f04a:wasm-function[2]:0xb1)
    at _D1a6helperFNaMNkPhyiykZQh (wasm://wasm/cd74f04a:wasm-function[3]:0xc7)
    at memset (wasm://wasm/cd74f04a:wasm-function[2]:0xb1)
    at _D1a6helperFNaMNkPhyiykZQh (wasm://wasm/cd74f04a:wasm-function[3]:0xc7)
    at memset (wasm://wasm/cd74f04a:wasm-function[2]:0xb1)
    at _D1a6helperFNaMNkPhyiykZQh (wasm://wasm/cd74f04a:wasm-function[3]:0xc7)

andy-hanson avatar Dec 22 '21 03:12 andy-hanson