Thread overview
where is the memory corruption?
Dec 09, 2020
Jack
Dec 09, 2020
Dukc
Dec 09, 2020
ag0aep6g
Dec 09, 2020
Paul Backus
Dec 10, 2020
Patrick Schluter
December 09, 2020
I'm on linux/opensuse, trying to pass a wchar_* from C to D but I'm getting only the first letter of that string. Could someone help figure out why?

this is the piece of D code:

extern(C) export
void sayHello(const (wchar) *s)
{
	import std.stdio : writeln;
	import std.conv : to;

	import core.runtime : rt_init, rt_term;
	rt_init();
	scope(exit) rt_term();

	writeln("+sayHello()");
	auto s2 = to!string(s);
	writeln("s2 = ", s2);
	writeln("-sayHello()");
}

build with dub, using "targetType": "dynamicLibrary" in dub.json.

and below the piece of C code where I call the lib's function, compiled with clang -std=c11 -m64 dll.c -ldl


  const char *libpath = "path/to/library.so";
  void *lh = dlopen(libpath, RTLD_LAZY);
  if(!lh) {
    fprintf(stderr, "dlopen error: %s\n", dlerror());
    return EXIT_FAILURE;
  }

  const wchar_t *s2 = L"hello!";
  void (*fp)(const wchar_t*) = dlsym(lh, "sayHello");
  char *de = dlerror();
  if(de) {
    fprintf(stderr, "slsym error:%s\n", de);
    return EXIT_FAILURE;
  }
  fp(s2);

the output is "h" rather "hello". What am I missing?
December 09, 2020
On Wednesday, 9 December 2020 at 20:35:21 UTC, Jack wrote:
> the output is "h" rather "hello". What am I missing?

In the sayHello function, you are converting a pointer to utf16 character into utf8 string, not utf16 string to utf8 string. Convert the C wstring to a D `wstring` first (std.string.fromStringz).

December 09, 2020
On 09.12.20 21:35, Jack wrote:
> I'm on linux/opensuse, trying to pass a wchar_* from C to D but I'm getting only the first letter of that string. Could someone help figure out why?
> 
> this is the piece of D code:
> 
> extern(C) export
> void sayHello(const (wchar) *s)
[...]
> and below the piece of C code where I call the lib's function, compiled with clang -std=c11 -m64 dll.c -ldl
[...]
>    const wchar_t *s2 = L"hello!";
>    void (*fp)(const wchar_t*) = dlsym(lh, "sayHello");
>    char *de = dlerror();
>    if(de) {
>      fprintf(stderr, "slsym error:%s\n", de);
>      return EXIT_FAILURE;
>    }
>    fp(s2);
> 
> the output is "h" rather "hello". What am I missing?

D's wchar is not C's wchar_t. D's wchar is 16 bits wide. The width of C's wchar_t is implementation-defined. In your case it's probably 32 bits.

Because of that size mismatch, sayHello sees your L"hello!" string as "h\0e\0l\0l\0o\0!\0"w. And the conversion correctly stops at the first null character.

My C isn't very good, but I think char_16t is the correct analog to D's wchar. https://en.cppreference.com/w/c/string/multibyte/char16_t
December 09, 2020
On Wednesday, 9 December 2020 at 21:21:58 UTC, ag0aep6g wrote:
>
> D's wchar is not C's wchar_t. D's wchar is 16 bits wide. The width of C's wchar_t is implementation-defined. In your case it's probably 32 bits.

In D, C's wchar_t is available as `core.stdc.stddef.wchar_t`.

http://dpldocs.info/experimental-docs/core.stdc.stddef.wchar_t.1.html
December 10, 2020
On Wednesday, 9 December 2020 at 21:28:04 UTC, Paul Backus wrote:
> On Wednesday, 9 December 2020 at 21:21:58 UTC, ag0aep6g wrote:
>>
>> D's wchar is not C's wchar_t. D's wchar is 16 bits wide. The width of C's wchar_t is implementation-defined. In your case it's probably 32 bits.
>
> In D, C's wchar_t is available as `core.stdc.stddef.wchar_t`.
>
> http://dpldocs.info/experimental-docs/core.stdc.stddef.wchar_t.1.html

Don't use wchar_t in C. It has variable size depending of implementation. On Posix machines (Linux, BSD etc.) it's 32 bit wide UTF-32, on Windows it 16 bit UTF-16.


December 10, 2020
On Wednesday, 9 December 2020 at 20:35:21 UTC, Jack wrote:
> I'm on linux/opensuse, trying to pass a wchar_* from C to D but I'm getting only the first letter of that string. Could someone help figure out why?
>
> [...]


May be this help to you:

	auto s2 = to!string(s);
to
	auto s2 = fromWChar( s );

wstring fromWChar( const wchar* s )
{
    import std.conv : to;
    return s[ 0 .. wcslen( s ) ].to!wstring;
}


Example: https://run.dlang.io/is/PkCeTZ