Search code examples
caddress-sanitizerjansson

Why does my code stop crashing after adding aSan library?


I am currently debugging a C code. This is basically a client from a data collection platform and I was getting weird bugs reading from a linked list. The problem basically is that the "next" pointer of the last item changes in some unknown point from NULL to 0xFFFFFFFFF. Then I tried to compile my library with address sanitizer in order to find where the bug bug could be and the bug disappeared, or it would be better to say that the bug is currently hidden. Is it possible? How can Asan library affect to the code to make not crash? thanks in advance.

EDIT: Sorry for the poor description, I will try to go deeper. I have been debugging the code and I have found where the problem is. It is in a parsing function from a json configuration file (I use jansson library for this purpose). The json format is like this:

{
...
"version": {
            "software": "0.2",
            "firmware": "0.2"
        },     
"system": ["system_A", "system_B"],
...
"internal_devices : [
         {
             ...
             "version": {
                 "software": "0.2",
                 "firmware": "0.2"
             },     
             "system": ["system_B"],
             ...
             },
             ...
             "version" : {
                 "software": "0.2",
                 "firmware": "0.2"
              },     
              "system": ["system_A"],
               ...
               }
           ]
      }
}   

And I have a struct like this to store this data

typedef struct XXX_NODE {
    mqtt_client_t * client;
    XXX_Device devices[XXX_MAX_DEVICES];
    size_t num_devices;
    XXX_operation_mode mode;
    pthread_mutex_t callback_lock;
    pthread_mutex_t registration_lock;
    pthread_cond_t registration_condition;
}XXX_NODE;

typedef struct XXX_id {
    ...
    struct XXX_parent parent_unit;
    // char parent_fin[64];
    int internal_level_tree;
    XXX_version version;
    List XXX_systems;
    List extended_topics;
    bool registered;
}XXX_id;

The real problem is in List XXX_systems. I have a List per device, and I can have several devices in the same struct, where the first element (in the XXX_Device devices array) is the main unit. And it is in this device where I loose information. The parsing function looks work properly. At the end of the function, the struct has rights values, but when I free json "objects", I loose the reference of the XXX_systems->next, but the weird thing is if I don't free some json "objects", everything works...

So, in this case, I loose information:

json_decref(internal_list);
json_decref(unit);
json_decref(root);
return 0;

But if I comment json_decref like this

json_decref(internal_list);
//json_decref(unit);
json_decref(root);
return 0; 

everything works...


Solution

  • From your description it looks like the call to json_decref() leads to corrupting your data. Apparently some piece of data identified by the unit variable gets destroyed, and then you're trying to use it, possibly from some separate piece of code.

    I can see two most probable scenarios:

    • Either you have more than one 'user' of some data and you might not care to properly identify the 'owner' among 'users', so somone decides to remove data still in use;
    • Or, you forgot to identify some users, so a data object appears unused at some point and gets deleted while someone still refers to it.

    I know nothing about the underlying Jansson matters, but I've simply asked Google about json_decref and it found the Jansson library description. See the section on reference counting:

    https://jansson.readthedocs.io/en/2.8/apiref.html#reference-count

    It's clearly stated there the json_decref() decrements a reference count and deletes an object if the count drops to zero. The following note describes creating so-called borrowed references and points out the holder of such reference must call json_incref(). This prevents the object from being deleted while in use. As soon as the value is no longer needed, json_decref() should be called to release the reference (and, possibly, to delete the data object).

    The conclusion is you most probably missed json_incref() in some piece of code that stores a reference for future use. As a result the reference count is too low and gets zeroed too soon, causing premature deletion. Which is a scenario number two.

    Scan your code and data structures for stored references to Json data objects and make sure every time a non-empty reference is stored you call json_incref() on it, and every time a non-empty reference gets overwritten or goes out of scope you call json_decref().

    NOTE:
    Distinguish carefully between a borrowed reference and a stolen reference – the latter is described in the linked doc page, too.

    P.S.
    It appears your problem has nothing to do with the C language, but rather with improper use of the Jansson library. Please consider removing the unnecessary tag.