Strange symbols when i'm trying to get char array from structure - c++

I'm working with libuv (https://github.com/joyent/libuv) and nodejs v12. I I write native module, in this module i have struct:
struct Work_req
{
const char *data;
size_t data_length;
Isolate* isolate;
unsigned int callback_id;
Persistent<Function> callback;
};
Then i try to pass this structure to work:
Work_req* request = new Work_req;
request->data = buf->base;
request->data_length = (size_t)nread;
request->isolate = env->isolate();
request->callback_id = callback_id->ToNumber()->Value();
uv_work_t *req = new uv_work_t;
req->data = request;
uv_queue_work(env->event_loop(), req, findCallback, after_findCallback);
In the end of this code i passed work to loop and all is ok.
But when i'm trying to read data from uv_work_t *req in findCallback function, i get strange symbols there:
Work_req *s = ((struct Work_req*)req->data);
printf(s>data); //print char array from structure here
I see something like this:
����g�Kack_id":1,"error":null,"response":{"type":"test"}}�����
How i can fix it?
Thanks a lot.

Related

Working with Node::Buffers in C++ Node Addons

I'm working on a Node addon that encrypts data using Windows DPAPI. I'm passing two Javascript Uint8Array to the C++ code using NAN.
This is what the typescript interface looks like:
export interface DpapiBindings{
protectData(dataToEncrypt: Uint8Array, optionalEntropy: Uint8Array, scope: string): Uint8Array
}
I'd like to then create a Node::Buffer in the C++ code:
void ProtectData( Nan::NAN_METHOD_ARGS_TYPE info)
{
v8::Isolate* isolate = info.GetIsolate();
//
auto buffer = node::Buffer::Data(info[0]);
auto len = node::Buffer::Length(info[0]);
DATA_BLOB entropyBlob;
entropyBlob.pbData = nullptr;
if (!info[1]->IsNull())
{
entropyBlob.pbData = reinterpret_cast<BYTE*>(node::Buffer::Data(info[1]));
entropyBlob.cbData = node::Buffer::Length(info[1]);
}
DATA_BLOB dataIn;
DATA_BLOB dataOut;
// initialize input data
dataIn.pbData = reinterpret_cast<BYTE*>(buffer);
dataIn.cbData = len;
success = CryptProtectData(
&dataIn,
nullptr,
entropyBlob.pbData ? &entropyBlob : nullptr,
nullptr,
nullptr,
flags,
&dataOut);
auto returnBuffer = Nan::CopyBuffer(reinterpret_cast<const char*>(dataOut.pbData), dataOut.cbData).ToLocalChecked();
LocalFree(dataOut.pbData);
info.GetReturnValue().Set(returnBuffer);
}
I'm new to C++, my question is: When working with node::Buffer::Data and node::Buffer::Length in C++ code, and calling into CryptProtectData, do I need to worry about buffer overflows? If so, how do I protect against it? Should I be appending a null char to buffer and len?
No, you don't need to worry about overflow. The dataIn and dataOut structures are pointers with a length.
BufferCopy is not what you want to use though. You want to use: Nan::MaybeLocal<v8::Object> Nan::NewBuffer(char* data, uint32_t size).
https://github.com/nodejs/nan/blob/master/doc/buffers.md#api_nan_new_buffer
and make sure you free the dataOut.pbData memory when you're done (i see you are with the LocalFree call.) the reason it can't overflow is that CryptProtectData allocates that buffer based on the size it needs.

C++ from linux to windows: 'does not evaluate to a constant'

I am trying to port this function from Linux to windows:
template<class TDescriptor, class F>
bool TemplatedVocabulary<TDescriptor,F>::loadFromBinaryFile(const std::string &filename) {
fstream f;
f.open(filename.c_str(), ios_base::in|ios::binary);
unsigned int nb_nodes, size_node;
f.read((char*)&nb_nodes, sizeof(nb_nodes));
f.read((char*)&size_node, sizeof(size_node));
f.read((char*)&m_k, sizeof(m_k));
f.read((char*)&m_L, sizeof(m_L));
f.read((char*)&m_scoring, sizeof(m_scoring));
f.read((char*)&m_weighting, sizeof(m_weighting));
createScoringObject();
m_words.clear();
m_words.reserve(pow((double)m_k, (double)m_L + 1));
m_nodes.clear();
m_nodes.resize(nb_nodes+1);
m_nodes[0].id = 0;
char buf[size_node];// fails
int nid = 1;
while (!f.eof()) {
f.read(buf, size_node);
m_nodes[nid].id = nid;
// FIXME
const int* ptr=(int*)buf;
m_nodes[nid].parent = *ptr;
//m_nodes[nid].parent = *(const int*)buf;
m_nodes[m_nodes[nid].parent].children.push_back(nid);
m_nodes[nid].descriptor = cv::Mat(1, F::L, CV_8U);
memcpy(m_nodes[nid].descriptor.data, buf+4, F::L);
m_nodes[nid].weight = *(float*)(buf+4+F::L);
if (buf[8+F::L]) { // is leaf
int wid = m_words.size();
m_words.resize(wid+1);
m_nodes[nid].word_id = wid;
m_words[wid] = &m_nodes[nid];
}
else
m_nodes[nid].children.reserve(m_k);
nid+=1;
}
f.close();
return true;
}
This line:
char buf[size_node];
will not compile, giving the error:
expression did not evaluate to a constant.
I have tried using:
std::vector<char> buf(size_node)
and:
char buf[size_node] = new char[];
but I see the same error. It seems like this is related to a run time constant vs compile time constant, as stated in the answer here:
Tuple std::get() Not Working for Variable-Defined Constant
But I am not sure how to get around it in this case. Thank you.
It should be
char *buf = new char[size_node];
Remember to delete the memory after use.
Or, just use std::vector. It's much safer.
std::vector<char> buf(size_node);
Then you'd have to change how buf is used. For example:
f.read(buf, size_node);
should become
f.read(buf.data(), size_node); //Only C++11

How to get a Java string from a char pointer in C++

I am porting the openvr sample to jogl, after we created the binding with jna.
Almost at the end (before rendering the controllers and the tracking base stations), I got stuck trying to translate a char pointer in C to a String in Java.
C++ code here:
//-----------------------------------------------------------------------------
// Purpose: Helper to get a string from a tracked device property and turn it
// into a std::string
//-----------------------------------------------------------------------------
std::string GetTrackedDeviceString( vr::IVRSystem *pHmd, vr::TrackedDeviceIndex_t unDevice, vr::TrackedDeviceProperty prop, vr::TrackedPropertyError *peError = NULL )
{
uint32_t unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty( unDevice, prop, NULL, 0, peError );
if( unRequiredBufferLen == 0 )
return "";
char *pchBuffer = new char[ unRequiredBufferLen ];
unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty( unDevice, prop, pchBuffer, unRequiredBufferLen, peError );
std::string sResult = pchBuffer;
delete [] pchBuffer;
return sResult;
}
GetStringTrackedDeviceProperty here:
/** Returns a string property. If the device index is not valid or the property is not a string type this function will
* return 0. Otherwise it returns the length of the number of bytes necessary to hold this string including the trailing
* null. Strings will generally fit in buffers of k_unTrackingStringSize characters. */
virtual uint32_t GetStringTrackedDeviceProperty( vr::TrackedDeviceIndex_t unDeviceIndex, ETrackedDeviceProperty prop, VR_OUT_STRING() char *pchValue, uint32_t unBufferSize, ETrackedPropertyError *pError = 0L ) = 0;
Where VR_OUT_STRING() is defined here as:
# define VR_CLANG_ATTR(ATTR)
#define VR_OUT_STRING() VR_CLANG_ATTR( "out_string: ;" )
I have already done something similar where I had to call a function that expect the pointer to an array of TrackedDevicePose_t structures:
private TrackedDevicePose_t.ByReference trackedDevicePosesReference = new TrackedDevicePose_t.ByReference();
public TrackedDevicePose_t[] trackedDevicePose
= (TrackedDevicePose_t[]) trackedDevicePosesReference.toArray(VR.k_unMaxTrackedDeviceCount);
I created first the reference and then from it the actual array.
But here I can't have a class extending the char array..
private String getTrackedDeviceString(IVRSystem hmd, int device, int prop, IntBuffer propError) {
int requiredBufferLen = hmd.GetStringTrackedDeviceProperty.apply(device, prop, Pointer.NULL, 0, propError);
if(requiredBufferLen == 0) {
return "";
}
CharArray.ByReference charArrayReference = new CharArray.ByReference();
char[] cs = charArrayReference.toArray(requiredBufferLen);
return null;
}
Where apply (here) is:
public interface GetStringTrackedDeviceProperty_callback extends Callback {
int apply(int unDeviceIndex, int prop, Pointer pchValue, int unBufferSize, IntBuffer pError);
};
CharArray class, crap attempt here
Any ideas?
I've done some porting of C and C++ code to Java, and while it's probably horribly hacky, the best I've come up with to solve cases where a pointer to an int primitive or a char*/String is needed for a function call, is to create a small wrapper class with a single property, pass that object into the function, change the property as needed, and retrieve the new value after the function call. So something like:
public class StringPointer {
public String value = "";
}
StringPointer pchBuffer = new StringPointer();
unRequiredBufferLen = pHmd.GetStringTrackedDeviceProperty( unDevice, prop, pchBuffer, unRequiredBufferLen, peError );
String sResult = pchBuffer.value;
and inside GetStringTrackedDeviceProperty()
...
pchValue.value = "some string";
...
In this case, you can use a String, since that's what your code is doing with the char* after the function call, but if it actually really needs to be a char[], you can just create char[] pchBuffer = new char[unRequiredBufferLen]; and pass that into the function. It will be just like you were using a char* in C++, and any changes you make inside the array will be visible after the function ends, and you can even do String sResult = new String(pchBuffer);.

Pass Node.js Buffer to C++ addon

test.js
buf = new Buffer(100);
for (var i = 0; i < 100; i++) buf[i] = i
addon.myFync(buf);
addon.cpp
Handle<Value> set(const Arguments& args) {
char *buf = SOMETHING(args[0]);
return Undefined();
}
How to get the pointer to a data of the buffer inside the C++ function?
What should I write in place of SOMETHING(args[0])?
I have node_buffer.h opened in my editor, but I cannot figure out.
Node version = v0.10.29
You can do:
char* buf = node::Buffer::Data(args[0]);
to directly access the bytes of a Buffer.
According to the node.js node binding documentation the 'arg[0]' value argument can be accessed as:
String::AsciiValue v(args[0]->ToString());

Cast an unsigned short/int to char *

I have a function like this
void UnitTestWorker::constructTestPayload(QByteArray &payload)
{
QString List = "127.0.0.1";
unsigned short Port = 12344;
unsigned int RequestId = 1;
memcpy(payload.data(),reinterpret_cast<char*>Port,sizeof(Port));
memcpy(payload.data()+sizeof(Port),reinterpret_cast<char*>RequestId ,sizeof(RequestId ));
}
But I am getting access violation error, it seems like I can't do something like reinterpret_cast<char*>Port or reinterpret_cast<char*>RequestId.
You have to ensure that QByteArray &payload has a sufficient size to receive the data you byte copy to it:
if (payload.size()<sizeof(Port)+sizeof(RequestId))
throw exception ("Ouch !! payload too small");
memcpy(payload.data(),reinterpret_cast<char*>(&Port),sizeof(Port));
memcpy(payload.data()+sizeof(Port),reinterpret_cast<char*>(&RequestId) ,sizeof(RequestId ));