www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Using FFI to write a std::string to a buffer passed in from D

reply Troy <tmj9001 gmail.com> writes:
I have a weird issue I've been running into while trying to write 
D bindings to some C++ code.  I'm trying to call some C++ 
functions that take in a std::string but don't make a copy of it. 
  To do this, I want to write a std::string to a buffer passed in 
from D so I can keep it from being destructed.

However, I'm getting a segfault when I attempt to write to the 
buffer I pass in despite supposedly allocating enough memory to 
store a std::string.  Even stranger, when I allocate 488 instead 
of 32, the segfault goes away.

Below, I've created a minimal example that illustrates my problem:
**main.d**
```d
import core.stdc.stdlib;

extern(C++) {
void create(void*);
void display(void*);
}

void main() {
	void* buf = malloc(32);// The size of a std::string on my 
platform is 32.
	//^--strangely, below segfault doesn't happen when 488 is 
allocated instead
	create(buf);
	display(buf);
}
```

**dothings.cpp**
```c++
#include <string>
#include <fstream>

void create(void* b) {
	std::string s = "engineer again";
	*(std::string*)(b) = s;// Segfault here
}

void display(void* b) {
	std::string s = *(std::string*)(b);
	std::ofstream file;
	file.open("imwishing");
	file << s << "\n";
	file.close();
}
```
(To build, I call "gdc main.d dothings.cpp -lstdc++ -g")

I suspect I'm making some false assumptions somewhere along the 
line, so please feel free to ask if you'd like to know more about 
what I'm doing here.
Jul 21
parent reply Johan <j j.nl> writes:
On Sunday, 21 July 2024 at 13:35:46 UTC, Troy wrote:
 void create(void* b) {
 	std::string s = "engineer again";
 	*(std::string*)(b) = s;// Segfault here
 }
You have to construct an empty string object first in location `b` (emplacement new). Then you can assign to it as you do. The `=` calls `operator=` which assumes that both operands (`b` and `s`) are both fully constructed and valid `std::string` objects. Without emplacement new, `b` is not a valid `std::string` object (random byte buffer returned by `malloc`). Hope that works, Johan
Jul 21
parent Troy <tmj9001 gmail.com> writes:
On Sunday, 21 July 2024 at 15:31:47 UTC, Johan wrote:
 On Sunday, 21 July 2024 at 13:35:46 UTC, Troy wrote:
 void create(void* b) {
 	std::string s = "engineer again";
 	*(std::string*)(b) = s;// Segfault here
 }
You have to construct an empty string object first in location `b` (emplacement new). Then you can assign to it as you do. The `=` calls `operator=` which assumes that both operands (`b` and `s`) are both fully constructed and valid `std::string` objects. Without emplacement new, `b` is not a valid `std::string` object (random byte buffer returned by `malloc`). Hope that works, Johan
Using placement new like you suggested seems to have solved my issue perfectly. I would never have never thought of that on my own. Thanks for the suggestion!
Jul 21