Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RPC_Response, Dangling Reference #189

Closed
brhmrsln opened this issue Feb 1, 2024 · 2 comments · Fixed by #180
Closed

RPC_Response, Dangling Reference #189

brhmrsln opened this issue Feb 1, 2024 · 2 comments · Fixed by #180

Comments

@brhmrsln
Copy link

brhmrsln commented Feb 1, 2024

Hello all,
"process_rpc_message" is calling the callback function "processTemperatureChange". The callback function must return RPC_Response object.
Now lets consider the example [0010-esp8266_esp32_rpc].
İn 0010-esp8266_esp32_rpc.ino file, function loop() we are registering the callback functions:

    const std::array<RPC_Callback, 2U> callbacks = {
      RPC_Callback{ RPC_TEMPERATURE_METHOD,    processTemperatureChange },
      RPC_Callback{ RPC_SWITCH_METHOD,         processSwitchChange }
    };
    // Perform a subscription. All consequent data processing will happen in
    // processTemperatureChange() and processSwitchChange() functions,
    // as denoted by callbacks array.
    if (!tb.RPC_Subscribe(callbacks.cbegin(), callbacks.cend())) {
#if THINGSBOARD_ENABLE_PROGMEM
      Serial.println(F("Failed to subscribe for RPC"));
#else
      Serial.println("Failed to subscribe for RPC");
#endif
      return;
    }

and one of the callback function is :

RPC_Response processTemperatureChange(const RPC_Data &data) {
#if THINGSBOARD_ENABLE_PROGMEM
  Serial.println(F("Received the set temperature RPC method"));
#else
  Serial.println("Received the set temperature RPC method");
#endif

  // Process data
  const float example_temperature = data[RPC_TEMPERATURE_KEY];

#if THINGSBOARD_ENABLE_PROGMEM
  Serial.print(F("Example temperature: "));
#else
  Serial.print("Example temperature: ");
#endif
  Serial.println(example_temperature);

  // Just an response example
  StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
  doc[RPC_RESPONSE_KEY] = 42;
  return RPC_Response(doc);
}

In the callback function 'processTemperatureChange', The 'StaticJsonDocument' object is created locally and passed as an argument to RPC_Response constructor. The called RPC_Response constructor is the one with the parameter JsonVariant.

explicit RPC_Response(JsonVariant variant);

Now the local 'StaticJsonDocument' object is impilicitly converted to 'JsonVariant', which means 'JsonVariant' is referencing the local 'StaticJsonDocument' object.
The 'process_rpc_message' gets the callback function's("processTemperatureChange") return value as a response.

RPC_Response response;
...
response = rpc.Call_Callback<Logger>(param);

As soon as callback function is finished, local object 'StaticJsonDocument' lifetime is over and the returned value RPC_Response is now referencing a released source 'StaticJsonDocument'. Undefined behaviour.
The solution can be:
RPC_Response class can store the JsonDocument so that we can move the locally created 'StaticJsonDocument' object and then use it when sending the response to the server.
Thanks in advance.

@MathewHDYT
Copy link
Contributor

Already known thanks to issue #167, is fixed in the aforementioned pull request. As soon as it has been merged the issue will be resolved.

@brhmrsln
Copy link
Author

brhmrsln commented Feb 1, 2024

Thank you for the quick response.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants