Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I don't understand why the callback lambda passed to c_style_callback does not access to the correct values of callback and key. How to get these 2 to be available from the lambda?
I tried with explicit copy [callback=callback, key=key], didn't help.
This is a C++ wrapper implementation of a C method called subscribe.
I think the following code covers my issue, let me know if anything else needed.
Wrapper, the issue is located here. Please check the comments at the end of the lines:
std::function<void()> AWS::subscribe(const std::string &topic, std::function<void(const std::string&)> callback, QoS qos) {
ESP_LOGI(TAG, "subscribe: %s", topic.c_str());
std::string key("Test...");
auto task = c_style_callback(
[=] (AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen, IoT_Publish_Message_Params *params) {
std::string json;
json.assign((char *)params->payload, (size_t)params->payloadLen);
ESP_LOGI(TAG, "subscribe cb payload=%s", json.c_str()); // works
ESP_LOGI(TAG, "key '%s'", key.c_str()); // undefined behaviour
callback(json);// error, exit
}
);
m_error = ::aws_iot_mqtt_subscribe(
&m_client,
key.c_str(),
key.length(),
qos,
task.get_callback<AWS_IoT_Client*, char*, uint16_t, IoT_Publish_Message_Params*>(),
task.get_pvoid()
);
if (m_error != SUCCESS) {
ESP_LOGD(TAG, "subscribe: error=%d", m_error);
return nullptr;
}
return [=] () {
ESP_LOGI(TAG, "unsubscribe %s", key.c_str()); // works
callback(key); // works
};
} // subscribe
c_style_callback utility function:
template<class F>
struct c_style_callback_t {
F f;
template<class...Args>
static void(*get_callback())(Args..., void*) {
return [](Args...args, void* fptr)->void {
(*static_cast<F*>(fptr))(std::forward<Args>(args)...);
};
}
void* get_pvoid() {
return std::addressof(f);
}
};
template<class F>
c_style_callback_t< std::decay_t<F> >
c_style_callback( F&& f ) { return {std::forward<F>(f)}; }
Main task where the subscribe wrapper is being called - this is only for giving context to the example, how I try to use the C++ wrapper of subscribe:
{
...
aws->subscribe(
topic,
[] (const std::string &json) -> void {
ESP_LOGI(TAG, "got json: %s", json.c_str());
}
);
...
}
Update:
More about aws_iot_mqtt_subscribe:
/**
* #brief Subscribe to an MQTT topic.
*
* Called to send a subscribe message to the broker requesting a subscription
* to an MQTT topic.
* #note Call is blocking. The call returns after the receipt of the SUBACK control packet.
*
* #param pClient Reference to the IoT Client
* #param pTopicName Topic Name to publish to
* #param topicNameLen Length of the topic name
* #param pApplicationHandler_t Reference to the handler function for this subscription
* #param pApplicationHandlerData Data to be passed as argument to the application handler callback
*
* #return An IoT Error Type defining successful/failed subscription
*/
IoT_Error_t aws_iot_mqtt_subscribe(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
QoS qos, pApplicationHandler_t pApplicationHandler, void *pApplicationHandlerData);
I assume aws_iot_mqtt_subscribe stores its arguments for latter reference - to call, in response to some event at some later point in time, the function passed as its next-to-last argument, with the pointer passed as its last argument.
The pointer obtained with task.get_pvoid() points to a data member of task. In turn, task is a local variable - it's destroyed when subscribe returns, together with its data member, whereupon that pointer becomes dangling.
Later, the function manufactured by c_style_callback_t::get_callback receives that no-longer-valid pointer and attempts to dereference it. Thereby the program exhibits undefined behavior, by way of accessing an object after its lifetime has ended.
Related
The ENet library has packets that can be send, and includes a callback function once it has finished sending that specific packet.
http://enet.bespin.org/structENetPacket.html#ad602d6b6b35ef88b2b2e080fa5c9dc3d
typedef struct _ENetPacket
{
size_t referenceCount; /**< internal use only */
enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */
enet_uint8 * data; /**< allocated data for packet */
size_t dataLength; /**< length of data */
ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */
void * userData; /**< application private data, may be freely modified */
} ENetPacket;
The callback itself:
typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *);
Now I want to create a class that holds the host used to send those packets, and also to keep track how many packets were successfully sent.
template<typename T>
class Sender {
public:
explicit Sender() { }
void send(T* data, int32_t length)
{
ENetPacket* packet = enet_packet_create(data, length, ENET_PACKET_FLAG_RELIABLE);
packet->freeCallback = callbackPacket;
enet_host_broadcast(m_server, 0, packet);
}
void callbackPacket(ENetPacket* packet)
{
--m_counter_packets_active;
}
};
This does not compile: Error C3867 Sender<int32_t>::callbackPacket': non-standard syntax; use '&' to create a pointer to member
When I try
packet->freeCallback = &this->callbackPacket;
I get Error C2440 '=': cannot convert from 'void (Sender<int32_t>::* )(ENetPacket *)' to 'ENetPacketFreeCallback'
I just don't understand what the proper code would be for the packet calling the Sender object's method when the packet is done with.
Okay, this is pretty common. First, you can't call a non-static member method this way, not directly. Pain in the ass.
But that callback structure has a userData field. And that's what we're going to use.
void send(T* data, int32_t length) {
ENetPacket* packet = enet_packet_create(data, length, ENET_PACKET_FLAG_RELIABLE);
packet->freeCallback = &Sender::myStaticMethod;
packet->userData = this; // This is part of the magic
enet_host_broadcast(m_server, 0, packet);
}
static void myStaticMethod(ENetPacket * packet) {
Sender * sender = static_cast<Sender *>(packet->userData);
sender-> callbackPacket(packet);
}
In other words -- store this as your user data. Use a static method for the callback, and have him turn it around to call your real callback.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I Need to perform a unit test on AddToDB() API. Below is my Attemp but i get error when i create a callback with notify type 2 mention below
typedef std::function<bool(std::string)> strnotify;
typedef std::function<void(strnotify &)> notify;
bool AddToDB(notify data);
// callback for typedef std::function<bool(std::string)> strnotify;
bool StringNotify(std::string){
std::cout<<"String success";
return true;
}
// callback for typedef std::function<void(strnotify &)> notify;
void StringObject(strnotify & obj){ // i get error here as type is not allowed
std::cout<<"string obj success";
}
//Call to API
AddToDB(StringObject)
I get error as type is not allowed.
Yes, your code is work well, like say Chris Dodd, but only AddToBase function. You cannot create function for std::function<void(strnotify &)> notify, because you use reference to std::functions<Type> object.
This code work fine:
using strnotify = std::function<bool(std::string)>;
using notify = std::function<void(strnotify& )>;
bool AddToDB(notify data) {
// do something...
return true;
}
int main() {
auto fun = [](strnotify& s) -> void { /*do something */};
auto fun2 = [](std::string s) -> bool {};
//fun(fun2); // now work :(
AddToDB(fun); // work!
return 0;
}
But if you uncomment line in main function, you get error:
gcc 10.2:
48:13:
no match for call to '(main()::<lambda(strnotify&)>) (main()::<lambda(std::string)>&)'
So, how we can fix that? I have two ways for you:
do not use reference: std::function<void(strnotify)> notify;
firstly create strnotify object and use into function. Example in godbolt.
And use using preferred than typedef please! Good luck!
Still many C++ codes are so difficult for me to understand..
Below is a code snippet from dlib (http://dlib.net file : dlib/external/pybind11/include/pybind11/pybind11.h)
It's a member function definition of class cpp_function and I didn't try to understand the code(no time to do that..that's sad..). I can't understand the syntax in the line I put *** this line! comment at below. I understand the lambda function(unnamed function), so is it assigning a function pointer to rec->impl, the function taking function_call &call as argument and returning handle? So, it looks like defining a function and at the same time assigning the function pointer to a variable. Having asked it, it looks so now.. Please someone confirm this.
void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) {
using namespace detail;
struct capture { remove_reference_t<Func> f; };
...
rec->impl = [](function_call &call) -> handle { // <=== *** this line!
cast_in args_converter;
/* Try to cast the function arguments into the C++ domain */
if (!args_converter.load_args(call))
return PYBIND11_TRY_NEXT_OVERLOAD;
/* Invoke call policy pre-call hook */
process_attributes<Extra...>::precall(call);
/* Get a pointer to the capture object */
auto data = (sizeof(capture) <= sizeof(call.func.data)
? &call.func.data : call.func.data[0]);
capture *cap = const_cast<capture *>(reinterpret_cast<const capture *>(data));
/* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */
const auto policy = return_value_policy_override<Return>::policy(call.func.policy);
/* Function scope guard -- defaults to the compile-to-nothing `void_type` */
using Guard = extract_guard_t<Extra...>;
/* Perform the function call */
handle result = cast_out::cast(
std::move(args_converter).template call<Return, Guard>(cap->f), policy, call.parent);
/* Invoke call policy post-call hook */
process_attributes<Extra...>::postcall(call, result);
return result;
};
...
using FunctionType = Return (*)(Args...);
constexpr bool is_function_ptr =
std::is_convertible<Func, FunctionType>::value &&
sizeof(capture) == sizeof(void *);
if (is_function_ptr) {
rec->is_stateless = true;
rec->data[1] = const_cast<void *>(reinterpret_cast<const void *>(&typeid(FunctionType)));
}
}
rec->impl = [](function_call &call) -> handle
creates a lambda which takes one argument of type function_call and returns a handle, then assigns it to rec->impl.
As lambdas are basically unnamed structs, they also have unnamed types. Since rec->impl obviously exists already and is thus not templatized on the lambda type, the lambda gets converted to some other type during the assignment. (Note: there could however be a templatized and overloaded operator= here)
Typically such types which can take lambdas are either std::function or function pointers as stateless lambdas can be converted to function pointers.
I have a C++ S-Function that handles a set of threaded operations through std::thread, std::async and callbacks.
The thing is that one of the callbacks is an S-function that has a buffer in the capture list. This buffer is in the PWork of the Simulink model. However, it seems that Matlab crashes as soon as I try to write to it.
Below is a minimal crashing example of my S-Function (only the mdlStart function), which contains the relevant code:
static void mdlStart(SimStruct *S)
{
ssGetPWork(S)[0] = (void *) new ThreadedDataServer();
ssGetPWork(S)[1] = (void *) new DatagramAssembler();
ssGetPWork(S)[2] = (void *) new MyBufferType(); // actually an std::array<char, LARGENUMBER>
auto server = (ThreadedDataServer *) ssGetPWork(S)[0];
auto assembler = (DatagramAssembler*) ssGetPWork(S)[1];
auto copy_buffer_ptr = (MyBufferType *) ssGetPWork(S)[2];
server->attachDataHandler([©_buffer_ptr, &assembler](const ThreadedDataServer::buffer_t & buffer, size_t num_bytes)
{
/* Minimal crashing action */
copy_buffer_ptr->at(5) = 'b'; // Any index != 0
/* Original code */
//std::copy(buffer.begin(), buffer.begin() + num_bytes, copy_buffer_ptr->data());
//assembler->feedData(*copy_buffer_ptr, num_bytes);
});
}
The handler is invoked from the data server worker thread (different from Simulink main thread). Other actions inside the callback function work smoothly (reading parameters, doing other operations...).
Any hint why this happens? The same code was working in an independent executeble before integrating it in Simulink.
You are capturing copy_buffer_ptr (a stack-local variable) by reference. That reference will be dangling as soon as mdlStart returns, after which invoking the lambda is undefined behavior. (This also applies to assembler).
The fix is to simply capture copy_buffer_ptr and assembler by value (they are simple pointers, you can just copy them without issue):
server->attachDataHandler([copy_buffer_ptr, assembler](const ThreadedDataServer::buffer_t & buffer, size_t num_bytes)
{
/* etc. */
});
If you have a lambda that will outlive the current scope, think long and hard before capturing anything by reference - if it's stack-local, you're probably about to get burnt.
Thanks to #max-langhof answer (dangling pointer) and some additional work, I finally reached a solution:
static void mdlStart(SimStruct *S)
{
ssGetPWork(S)[0] = (void *) new ThreadedDataServer();
ssGetPWork(S)[1] = (void *) new DatagramAssembler();
ssGetPWork(S)[2] = (void *) new MyBufferType(); // actually an std::array<char, LARGENUMBER>
ssGetPWork(S)[3] = (void *) new std::mutex();
auto server = (ThreadedDataServer *) ssGetPWork(S)[0];
auto assembler = (DatagramAssembler*) ssGetPWork(S)[1];
auto copy_buffer_ptr = (MyBufferType *) ssGetPWork(S)[2];
auto assembly_mutex = (std::mutex *) ssGetPWork(S)[3];
server->attachDataHandler([copy_buffer_ptr, assembler, assembly_mtx](const ThreadedDataServer::buffer_t & buffer, size_t num_bytes)
{
// Mutex scoped lock
{
std::lock_guard<std::mutex> lckg(assembly_mutex);
std::copy(buffer.begin(), buffer.begin() + num_bytes, copy_buffer_ptr.data());
assembler.feedData(copy_buffer_ptr, num_bytes);
}
});
This implementation solves two problems:
Variables in capture list were reference to pointer-in-the-stack, which ended as dangling pointers and caused a crash.
Several calls to data handler were accessing the buffer and the Assembler object concurrently, apparently causing a different Access Violation.
It's working now :-)
I want to pass a string "Device Name" to a void * pointer argument of a method and retrieve it to a character array later.
For this I've done as shown below.
Here I have created an action to achieve this.
ACTION_P(SetArg2ToChar, value) {*static_cast<char*>(arg2) = *value; }
Actual method to be called/mocked
bool getDictItem(WORD wIndex, BYTE bSubIndex, void * pObjData, DWORD dwLength, CSdo& sdo)
My mock method
MOCK_METHOD5(getDictItem,
bool(WORD wIndex, BYTE bSubIndex, void * pObjData, DWORD dwLength, CSdo& sdo));
in code it is called as
if( !can.getDictItem(wIndex, bSubIndex, pObjData, dwLength, tSdo) )
I want to pass a string to this pObjData (3rd argument in the list).
In my google tests, I'm doing like this.
char szDeviceName[30]= {0};
snprintf(szDeviceName, sizeof(szDeviceName), "%s", "Device Name" );
EXPECT_CALL( mockCan, getDictItem(_,_,_,_,_) )
.WillOnce(DoAll(SetArg2ToChar(szDeviceName),
Return(true)))
.RetiresOnSaturation();
/* Call a real method within which this mock method is called */
If I try to set this argument(pObjData) using "SetArgPointee<2>" directly, I get the below error.
error: 'void' is not a pointer-to-object type*
Hence I'm trying with ACTION_P
Now with this implementation, I only get the first letter of the szDeviceName variable (into this pObjData) i.e., "D" followed by 29 0's in the real code flow after this mock object is called.
I want to get the full string name set into this void * arguement.
I refered to this below question and was able progress this far. But I'm not able to pass the full string. How to set, in google mock, a void* argument to a set of values?
Any information regarding this will be helpful.
Rather then doing that, you could invoke a function (or a method) and copy the parameter.
Something like this in the source file where the test is :
int invokedPObjData;
bool FakeGetDictItem(WORD wIndex, BYTE bSubIndex, void * pObjData, DWORD dwLength, CSdo& sdo)
{
// copy data. here I assumed it is an int
invokedPObjData = *static_cast< int* >( pObjData );
return true; // or whatever makes sense
}
in test :
EXPECT_CALL( mockCan, getDictItem(_,_,_,_,_) )
.WillOnce(Call(FakeGetDictItem))
.RetiresOnSaturation();
then later in test check what needs to be checked.
The ACTION_P approach is basically OK. But as you are dealing with a C string, you can't just use the assignment operation (which just copies the first character) but instead you should use a string copy function like ACTION_P(SetArg2ToCharWithSizeArg3, value) { strcpy_s(static_cast<char*>(arg2), arg3, value); } (I couldn't resist to slightly rename the action).
I recently had a similar need and came up with this as a generic solution. It's based on the built-in SetArgPointee and has the same syntax:
template <size_t N, typename A>
class SetArgumentPointeeVoidAction {
public:
explicit SetArgumentPointeeVoidAction(const A& value) : value_(value) {}
void operator=(SetArgumentPointeeVoidAction const&) = delete;
template <typename Result, typename ArgumentTuple>
void Perform(const ArgumentTuple& args) const
{
::testing::StaticAssertTypeEq<void, Result>();
::testing::StaticAssertTypeEq<void*,
std::decay<decltype(::testing::get<N>(args))>::type>();
*static_cast<A*>(::testing::get<N>(args)) = value_;
}
private:
const A value_;
};
/**
* \brief Sets a \c void* output argument to the contents of the
* supplied object. It's on you to ensure this is safe.
* \tparam N The argument index.
* \tparam T The real argument type.
* \param x The argument to assign to the output argument.
* \return A GMock Action that performs the requested assignment.
* \note Use \c SetArgPointee when it's not a \c void*.
*/
template <size_t N, typename T>
::testing::PolymorphicAction< SetArgumentPointeeVoidAction<N, T> >
SetArgPointeeVoid(const T& x)
{
return ::testing::MakePolymorphicAction(
SetArgumentPointeeVoidAction<N, T>(x));
}
It will give you a compile error if you try to use this on an argument that isn't a void*, so it should be relatively safe as long as you ensure you supply the correct argument.
It's also possible to implement this using ACTION_TEMPLATE, which is a bit shorter, but it generates unused argument warnings, which can be irritating.
(In older versions of GMock you might have to use ::std::tr1::get instead of ::testing::get.)
Left as an exercise for the reader: it's possible to enhance this with perfect forwarding to allow this to move-construct and move-assign for a slight efficiency boost. Although if you're passing anything other than PODs around as void*s then you're probably doing it wrong.
Here is an example using ACTION_TEMPLATE allowing a string to be assigned to a void *, for reference...
ACTION_TEMPLATE(StrCpyArgToVoidPointer,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_2_VALUE_PARAMS(value, size))
{
strncpy(static_cast<char *>(::testing::get<k>(args)), value, size);
return;
}
Please find the steps to set Void Pointer variable in class using invoke Method.
//Actual Function under Test
void testFunction(void)
{
uint16 Frequency;
uint8 PwmId;
uint8 DutyCycle;
Frequency = PORTEXTENDER_ZERO;
PwmId = PORTEXTENDER_ZERO;
DutyCycle = PORTEXTENDER_ZERO;
//for this mock is available and we need to set value of Ex. PwmId
IncCom_ReceiveSignal(SCC_PORT_EXTENDER_PWM_C_SET_PWM_Id, &PwmId);
if((PwmId <= PORTEXTENDER_NUM_PWM_CHANNELS) && (DutyCycle <= 100))
{
}
// Actual Defination of mock ..where we have to set void pointer
void mock_defination(PortExtender_C_SignalId_e SignalId, void* SignalDataPtr)
{
}
//cpp Test class
class testClass : public :: testing :: Test
{
protected:
/* Fixture tear down */
virtual void TearDown()
{
}
uint8 testval1{1};
public:
void setTestvalue(uint8 val) // if we want to set multiple time
{
testval1= val;
}
void test1(PortExtender_C_SignalId_e SignalId, void* SignalDataPtr) //this is method to invoke from test_F
{
* (uint8*)SignalDataPtr =testval1;
}
}
//Test Case
TEST_F(testClass,
testcase_PortExtender_CompStatusResponse_ifConditionSatisfied)
{
setTestvalue(1); //To Set Value
EXPECT_CALL(m_portExtender_SomeIpMock,m_C_Signal(SCC_PORT_EXTENDER_C_COMPONENT_STATUS_HostApplStat,_))
.WillOnce(Invoke(this,&testClass::test1));
}