[Ovmsdev] Strange crashes when logging additional info in can logs

Ludovic LANGE ll-ovmsdev at lange.nom.fr
Sat Nov 19 04:44:45 HKT 2022


Michael,

You're right, that's the best approach ; thanks for sharing it with me.

Here is a PR : 
https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/pull/777 
for review.

(I also converted the second parameter - metric name - but you can 
remove this commit if you prefer)

Regards,

Le 18/11/2022 à 14:51, Michael Balzer a écrit :
> Ludovic,
>
> there is an even better variant of your second approach, that's 
> changing MetricCallbackEntry.m_caller to a std::string.
>
> That's the same scheme EventCallbackEntry already uses, and m_caller 
> is only used to identiy the registrant, so that's straight forward.
>
> Regards,
> Michael
>
>
> Am 18.11.22 um 01:49 schrieb Ludovic LANGE:
>> Some news...
>>
>> My issue was caused because of course I made a mistake with the way 
>> of registering my metrics Listener.
>>
>> I used the following code (see my previous post) in the constructor:
>>
>> + MyMetrics.RegisterListener(IDTAG.c_str(), "*", 
>> std::bind(&canlog::MetricListener, this, _1));
>>
>> and for the destructor:
>> + MyMetrics.DeregisterListener(IDTAG.c_str());
>>
>> I had to use IDTAG because this class has multiple instances.
>>
>> The issue is passing IDTAG.c_str() as a parameter ; 
>> becauseMyMetrics.RegisterListener stores the value of this const 
>> char* parameter and uses it 1) as an immutable parameter and 2) as a 
>> value.
>>
>> Of course this does not work with my first way to call 
>> MyMetrics.RegisterListener :
>>
>>   * the memory buffer returned by IDTAG.c_str() has no more existence
>>     after exiting the constructor, so this lead to memory corruption.
>>   * when calling IDTAG.c_str() again in the destructor, there is
>>     absolutely no chance that this c_str() call returns the same
>>     memory address as the call in the constructor, so the value
>>     comparison will never work.
>>
>>
>> I rewrote the code this way by adding a new member (m_idtag) to the 
>> class:
>>
>> @ vehicle/OVMS.V3/components/can/src/canlog.cpp:352 @ 
>> canlog::canlog(const char* type, std::string format, 
>> canformat::canformat_serve_
>>    m_dropcount = 0;
>>    m_filtercount = 0;
>>
>> +  m_idtag = strdup(IDTAG.c_str());
>> +
>>    using std::placeholders::_1;
>>    using std::placeholders::_2;
>>    MyEvents.RegisterEvent(IDTAG, "*", 
>> std::bind(&canlog::EventListener, this, _1, _2));
>> +  if (NULL != m_idtag)
>> +    {
>> +    MyMetrics.RegisterListener(m_idtag, "*", 
>> std::bind(&canlog::MetricListener, this, _1));
>> +    }
>> +  else
>> +    {
>> +    ESP_LOGE(TAG,"Cannot allocate memory - not registering metrics 
>> listener");
>> +    }
>>
>>    int queuesize = MyConfig.GetParamValueInt("can", "log.queuesize",100);
>>    m_queue = xQueueCreate(queuesize, sizeof(CAN_log_message_t));
>> @ vehicle/OVMS.V3/components/can/src/canlog.cpp:374 @ 
>> canlog::canlog(const char* type, std::string format, 
>> canformat::canformat_serve_
>>  canlog::~canlog()
>>    {
>>    MyEvents.DeregisterEvent(IDTAG);
>> +  if (NULL != m_idtag)
>> +    {
>> +    MyMetrics.DeregisterListener(m_idtag);
>> +    free((void*)m_idtag);
>> +    }
>>
>>    if (m_task)
>>      {
>>
>>
>> Another option is to change MyMetrics.RegisterListener so that it 
>> store *a copy* of the parameter, and does string comparison instead 
>> of a value comparison:
>>
>> modified: vehicle/OVMS.V3/main/ovms_metrics.cpp
>> ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
>> @ vehicle/OVMS.V3/main/ovms_metrics.cpp:1019 @ void 
>> OvmsMetrics::RegisterListener(const char* caller, const char* name, 
>> MetricC
>>      return;
>>      }
>>
>> +  const char * caller_copy = (const char *)strdup(caller);
>> +
>> +  if (NULL == caller_copy)
>> +    {
>> +    ESP_LOGE(TAG, "Problem registering metric %s for caller %s - 
>> insufficient memory",name,caller);
>> +    return;
>> +    }
>> +
>>    MetricCallbackList *ml = k->second;
>> -  ml->push_back(new MetricCallbackEntry(caller,callback));
>> +  ml->push_back(new MetricCallbackEntry(caller_copy,callback));
>>    }
>>
>>  void OvmsMetrics::DeregisterListener(const char* caller)
>> @ vehicle/OVMS.V3/main/ovms_metrics.cpp:1041 @ void 
>> OvmsMetrics::DeregisterListener(const char* caller)
>>      while (itc!=ml->end())
>>        {
>>        MetricCallbackEntry* ec = *itc;
>> -      if (ec->m_caller == caller)
>> +      if (strcmp(ec->m_caller, caller) == 0)
>>          {
>> +        free((char *)ec->m_caller);
>>          itc = ml->erase(itc);
>>          delete ec;
>>          }
>>
>>
>> I've tested both approaches and they both solve my issue : no more 
>> crashes and memory corruption.
>>
>> The second one is more "risky" (as it potentially impacts everyone) 
>> but I think that it should not cause much regression.
>>
>> Let me know what you think - should I make a PR for this second 
>> approach ?
>>
>> Regards,
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openvehicles.com/pipermail/ovmsdev/attachments/20221118/64f2c69d/attachment.htm>


More information about the OvmsDev mailing list