www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - where is the memory corruption?

reply Jack <jckj33 gmail.com> writes:
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?
Dec 09 2020
next sibling parent Dukc <ajieskola gmail.com> writes:
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).
Dec 09 2020
prev sibling next sibling parent reply ag0aep6g <anonymous example.com> writes:
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
Dec 09 2020
parent reply Paul Backus <snarwin gmail.com> writes:
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
Dec 09 2020
parent Patrick Schluter <Patrick.Schluter bbox.fr> writes:
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.
Dec 10 2020
prev sibling parent =?UTF-8?B?0JLQuNGC0LDQu9C40Lkg0KTQsNC0?= =?UTF-8?B?0LXQtdCy?= writes:
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
Dec 10 2020