Contexte
- Débogage logiciel, peu de code est écrit, sans débogage, vous pouvez savoir où se trouve le problème, en particulier l'assertion RT_ASSERT.
- Il y a plus de fonctions. Après l'apparition de l'assertion RT_ASSERT, il est difficile de comprendre immédiatement ce qui n'a pas fonctionné, comme l'assertion rt_free. D'où l'appel à rt_free l'a-t-il causé?
- Comment utiliser Keil MDK5 Debug pour affirmer rapidement la vraie position de l'assertion et déboguer le logiciel?
étude de cas
- J'ai écrit un programme BUG avant pour tester l'utilisation de la boîte aux lettres RT-Thread, et je dois maintenant affirmer: rt_free, car l'application et la libération de la mémoire dynamique sont utilisées.
- Tout d'abord, nous devons localiser le problème, nous ne pouvons pas dire qu'il y a un problème avec la fonction rt-thread rt_free! ! Cela devrait être causé par une utilisation incorrecte.
- Keil MDK5 est en mode Débogage, vous pouvez trouver la relation d'appel des fonctions, telles que l'appelant, dans la fenêtre de débogage [Call Stack], fenêtre de pile d'appels.
- Grâce à [suivez la vigne], trouvez la véritable fonction d'appel: l'emplacement du problème! !
Dépannage
- Le problème avec cette routine est causé par le pointeur nul rt_free, il doit donc être causé par l'opération de paire incorrecte d'application et de libération de mémoire.
- Comme je n’ai pas trouvé le problème tout de suite, j’ai défini un point d’arrêt à l’emplacement du code du problème et j’ai constaté qu’il y avait un problème avec le pointeur rt_free lors de la deuxième exécution, ou qu’il s’agissait d’un pointeur sauvage.
- Quote: extern void list_mem (void); Ajouter pour imprimer et constater que la mémoire devient de plus en plus! ! (Beaucoup de versions de rt_free !!)
- La partie du code qui a mal tourné est la suivante:
struct mb_msg
{
rt_uint8_t *data_ptr;
rt_uint32_t data_size;
};
static void thread1_entry(void *param)
{
struct mb_msg *msg_recv_ptr1;
struct mb_msg *msg_send_ptr1;
char sbuf[6] = {'T', 'a', 's', 'k', '1', '.'};
msg_send_ptr1 = (struct mb_msg *)rt_malloc(sizeof(struct mb_msg)); /* !!!! 申请内存的位置放错了!!!*/
while(1)
{
if (rt_mb_recv(&t1_mb, (rt_ubase_t *)&msg_recv_ptr1, RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("thread 1:[recv=%s], print 1.\n", msg_recv_ptr1->data_ptr);
rt_thread_mdelay(10);
rt_free(msg_recv_ptr1->data_ptr);
rt_free(msg_recv_ptr1);
rt_thread_mdelay(500);
msg_send_ptr1->data_size = sizeof(sbuf);
msg_send_ptr1->data_ptr = (rt_uint8_t *)rt_malloc(msg_send_ptr1->data_size);
rt_memcpy(msg_send_ptr1->data_ptr, sbuf, sizeof(sbuf));
rt_kprintf("thread 1:[send=%s]\n", msg_send_ptr1->data_ptr);
rt_mb_send(&t2_mb, (rt_uint32_t)msg_send_ptr1);
}
}
}
- Il s'est avéré qu'un endroit où la mémoire a été demandée était mal placé, ce qui fait que cette fonction ne s'applique qu'une seule fois pour la mémoire lors de l'initialisation. Lorsqu'elle est utilisée, c'est un pointeur sauvage.
- Solution: placez le morceau de code qui s'applique pour la mémoire dans la boucle while (1) et appliquez pour la mémoire pour chaque opération! !
static void thread1_entry(void *param)
{
struct mb_msg *msg_recv_ptr1;
struct mb_msg *msg_send_ptr1;
char sbuf[6] = {'T', 'a', 's', 'k', '1', '.'};
while(1)
{
if (rt_mb_recv(&t1_mb, (rt_ubase_t *)&msg_recv_ptr1, RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("thread 1:[recv=%s], print 1.\n", msg_recv_ptr1->data_ptr);
rt_thread_mdelay(10);
rt_free(msg_recv_ptr1->data_ptr);
list_mem();
rt_free(msg_recv_ptr1);
list_mem();
rt_thread_mdelay(500);
msg_send_ptr1 = (struct mb_msg *)rt_malloc(sizeof(struct mb_msg));
msg_send_ptr1->data_size = sizeof(sbuf);
msg_send_ptr1->data_ptr = (rt_uint8_t *)rt_malloc(msg_send_ptr1->data_size);
rt_memcpy(msg_send_ptr1->data_ptr, sbuf, sizeof(sbuf));
rt_kprintf("thread 1:[send=%s]\n", msg_send_ptr1->data_ptr);
rt_mb_send(&t2_mb, (rt_uint32_t)msg_send_ptr1);
}
}
}
Pour résumer
- RT_ASSERT est encore relativement facile à utiliser, faites attention aux points d'arrêt corrects, au débogage, très efficace.
- Résumez plus de méthodes de débogage pour résoudre les problèmes réels.