Niewłasciwa wartość zmiennej

1

Jaka może być przyczyna takiej sytuacji? Jest to kod działający na STM32, więc może jakiś wyciek pamięci w przerwaniu. Chociaż to jednak mało prawdopodobne by w tak krótkim czasie między deklaracją zmiennej single_ack_message_length do breakpoint'u trafiło akurat jakieś przerwanie. Cały kod debugowany przy optymalizacji O1, jedynie ta funkcja ma zmienioną optymalizację w celu dokładniejszej analizy, standard kompilatora GNU11.

#pragma GCC push_options
#pragma GCC optimize ("O0")
MonitoringParseMessStatus monitoring_ack_message(char *msg, uint16_t length)
{

	MonitoringParseMessStatus res = M_BAD_MESS;
	uint16_t single_ack_message_length = 18; // minimum len
	if(length < single_ack_message_length)
		return M_NAK;

	uint8_t len_mess = strlen(msg);
	char single_message[len_mess + 1];


	while(length >= len_mess && length >= single_ack_message_length)
	{
		memset(&single_message[0], 0, sizeof(single_message));
		memcpy(&single_message[0], msg, single_ack_message_length);

		msg += len_mess + 1;
		length -= len_mess;
		len_mess = strlen(msg);

		char * ack_ptr = strstr(single_message, "\"ACK\"");
		if(ack_ptr == NULL)
		{
			ack_ptr = strstr(single_message, "\"NAK\"");
			if(ack_ptr != NULL)
			{
				return M_NAK;

			}

			res = M_BAD_MESS;
			continue;
		}
		else
			res = M_ACK;

		char *seq_ptr = ack_ptr + strlen("\"ACK\"");
		int seq = atoi(seq_ptr);

		for(int i = 0; i < QUEUE_SIZE; i++)
		{
			if(monitoring_queue[i].set == false)
				continue;

			if(monitoring_queue[i].sequence != seq)
				continue;

			monitoring_queue[i].set = false;
			monitoring_connected_set(monitoring_queue[i].monitoring_num, true);
			monitoring_send_earliest_event();
			break;
		}
	}
	return res;
}
#pragma GCC pop_options

Kiedy zatrzymuję kod na linii uint8_t len_mess = strlen(msg); widze, że wartość single_ack_message_length wynosi 65441

screenshot-20220325112650.png

0

A modyfikujesz gdzies zawartosc tej zmiennej? Nie masz przeciez gwarancji, ze to pierwsza instrukcja po zadeklarowaniu :)

0

@stivens: Niezbyt rozumiem co masz na myśli. Przecież ta zmienna jest tworzona za każdym razem po wywołaniu funkcji na stosie. Funkcja zostaje tutaj wywołana pierwszy raz, bo od razu po zresetowaniu systemu mam ustawionego breakpoint'a. W return wyzej też nie wpada, tam jeszcze wartość jest prawidłowa.
Jedynie podejrzenie jakie na razie mam to że z jakiegoś powodu stos zapisywany jest na niedozwolony obszar w pamięci, gdzie zapisywany jest np. jakiś rejestr mikrokontrolera (wartość ta musi być bardzo często zapisywana zeby w tak krótkim czasie doszło do jej nadpisania).

2

Debugujesz z włączonymi optymalizacjami czy bez?
Być może kompilator coś zoptymalizował i stąd dziwna wartość.
Podejrzyj co dzieje się w debugerze ale assemblera (o ile środowisko, które używasz to wspiera)

0

Uzupełniłem braki i mam coś takiego: https://godbolt.org/z/rq54GseK8

Na razie nie widzę wyjaśnienia, czemu niby debugger pokazuje złą wartość.

1

Co się stanie jeśli single_ack_message_length zdefiniujesz jako const albo #define?

const uint16_t single_ack_message_length = 18;
// ..........
#define single_ack_message_length 18
0

@danielbr3:
Podaj kompilator i jego ustawienia.
Czy na pewno w kodzie masz

#pragma GCC push_options
#pragma GCC optimize ("O0")

czy dodałeś to na wyrost?

Gdyby były jakieś optymalizację to można wyjaśnić czemu debuger cię kłamie. Z wymuszonym -O0 to nie rozumie skąd ten problem.

0

Udało mi się jeszcze coś takiego złapać jak zmieniłem typ tej zmiennej single_ack_message_length na static żeby już ona zaczęła działać. To tez wygląda trochę dziwnie. Sorry że na zdjęciu ale ciężko byłoby to inaczej pokazać

screenshot-20220325131448.png

0
danielbr3 napisał(a):

Udało mi się jeszcze coś takiego złapać jak zmieniłem typ tej zmiennej single_ack_message_length na static żeby już ona zaczęła działać.

Programowanie permutacyjne jest BARDZO ZŁĄ PRAKTYKĄ!

3

Chwila chwila, teraz pojechałeś debugerem dalej i to poniżej miejsca gdzie masz undefined behavior z buffer overflow, ukryte w ciekawy sposób.

Na dodatek z tego co widzę z ostatniego screenshota msg zawiera dane binarne, a ty robisz na nich strlen!
I masz jeszcze argument, który sugeruje, że rozmiar wiadomości jest zero, ale ty mimo wszystko używasz strlen.
strlen na czymś co nie jest napisem zakończonym zerem to kolejne UB.

2

Po komentarzach MarkR22 się przypatrzyłem się wyraźniej niż rzu okiem i faktycznie tu UB nie w jednym miejscu.
Proponuję do takiej funkcji podejść inaczej. Zrób unit testy. To C i stm32 więc może spróbuj czegoś takiego
http://www.throwtheswitch.org/unity
Napisz tą funkcję używając UT najpierw. łatwiej ci to będzie sprawdzać. Później wleź tym na stm32. Zauważ ta funkcja operuje w zasadzie na czystym C a nie na jakiś mambo jambo z stm32 więc powinno to być łatwe do przetestowania.

0

Wygląda wstępnie, że gdzieś wyjeżdzasz poza zakres. Dalej mi się analizować nie chce za bardzo ;)
zobacz z włączonym sanitizerem: https://godbolt.org/z/o86W5TTPb

1 użytkowników online, w tym zalogowanych: 0, gości: 1