Verstaendnissfrage bzgl. dynam. Speicherallozierung im Hinblik auf Kernelprogrammieru

D

das.chaos

Guest
Verstaendnissfrage bzgl. dynam. Speicherallozierung im Hinblik auf Kernelprogrammierung

Hi,

da ich mir (in einem Anfall von Groeszenwahn *g*) versuche Kernelprogrammierung beizubringen, ein paar kleine, elementare Verstaendnissfragen bzgl. Autodidaktik...

Ich benutze zur Zeit FreeBSD 8.x. Folgendes Szenario ist gegeben (bei grober Betrachtung, es funktioniert):

Eine Prozedur welche bspw. einem dl_rahmen abgekapselten ppp_pr_paket extrahierte Information bzgl. ppp_pr_opt (siehe bspw. RFC1661, Seite 38)
Code:
0                   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Type      |    Length     |    Data ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |
                |--> ppp_opt_xyz_subnode_info()
                |
                ^
            curr_pos: fr_off
als String auswertet (weil sich diese Prozedur auf eine ppp_pr_opt xyz bezieht wo definitiv zu erwarten ist, dasz ein String die uebermittelte Information stellt) und diese bspw. LOG(9) uebergibt:
Code:
void 
ppp_opt_xyz_subnode_info(fr_prm_t *frcb, u_char *fr, pppoe_t *phcb)
{	 
	struct msg_len_s { 
		uint8_t val; 
	};
		
	struct msg_len_s *dt_len = (struct msg_len_s *)(fr + frcb->fr_off); 
		
	frcb->fr_off += sizeof(struct msg_len_s);

	if (dt_len->val != DT_EMPTY) {	   /* #define DT_EMPTY 0x00 */
		struct raw_dt_s { 
			u_char b_str[dt_len->val]; 
		}; 
			
		struct raw_dt_s *dt = (struct raw_dt_s *)(fr + frcb->fr_off);
			
		frcb->fr_off += sizeof(struct raw_dt_s);
	
	   struct msg_s {
		   u_char info_str[dt_len->val + 1];
		}; 
		   
		struct msg_s *msg; 
		   
		if ((msg = (struct msg_s *)malloc(sizeof(struct msg_s), M_TEMP, M_ZERO)) == NULL) {
			dt = NULL;
		  	dt_len = NULL;
		  	
		  	return;
		}
		  	
		(void)sprintf(msg->info_str, "%s%c", dt->b_str, '\0');	
		log(LOG_PRINTF, "blablubb: %s", msg->info_str); 
		
		free((void *)msg, M_TEMP);
		
		dt = NULL;
	}
		
	dt_len = NULL;
}
Da ich getrieben von staendiger Angst vor einem sogenannten Memory Leak oder Aehnlichem bin *heul*, beziehen sich meine Fragen u.a. auf folgendes Codefragment:
Code:
struct msg_s {
   u_char info_str[dt_len->val + 1];
}; 
		   
struct msg_s *msg; 
		   
if ((msg = (struct msg_s *)malloc(sizeof(struct msg_s), M_TEMP, M_ZERO)) == NULL) {
	dt = NULL;
   dt_len = NULL;
		  	
	return;
}
		  	
(void)sprintf(msg->info_str, "%s%c", dt->b_str, '\0');	
log(LOG_PRINTF, "blablubb: %s", msg->info_str);
		
free((void *)msg, M_TEMP);
Waere das ein korrekter Gebrauch von MALLOC(9) innerhalb diesem Zusammenhang bzw. ist die Speicherallozierung bzgl.
Code:
struct msg_s {
   u_char info_str[dt_len->val + 1];
};
notwendig? Kann ich anstatt o.g. Fragment bzw.
Code:
struct msg_s {
   u_char info_str[dt_len->val + 1];
}; 
		   
struct msg_s msg; 
		   		  	
(void)sprintf(msg->info_str, "%s%c", dt->b_str, '\0');	
log(LOG_PRINTF, "blablubb: %s", msg->info_str);
verwenden, also ist hier MALLOC(9) in diesem Zusammenhang notwendig? Wenn nicht, der Interesse halt halber, warum (was eigendlich die Kernfrage ist, mir ist bewusst, dasz man die dynam. Speicherverwaltung in C immer im Blickfeld haben musz)? Sind die Anweisungen der Art 'ptr = NULL;' bzgl. den Zeigern: 'dt_len' und 'dt' ueberfluessig? Oder wenn diese nicht ueberfluessig sind und nicht gegeben seien, koennen sich diese dann als sogennante 'wilde Pointer' ihr dasein entfalten?

Ferner, sei es als Alternative zu o.g. empfehlenswert auf "struct msg_s" zu verzichten (man musz ja das Rad nicht neu erfinden) und mittels Funktionen bzgl. SBUF(9) Informationen aufzubereiten und dann LOG(9) zu uebergeben?

mfg

das.chaos
 
In C kannst Du im Prinzip nur solche Variablen auf den Stack legen, deren Größe der Compiler auflösen kann.

Deine zweite Variante kann funktionieren, dazu müsstest Du allerdings erstmal alle "->" Operatoren auf der msg Variable durch einfache Punkte (".") ersetzen. Unabhängig davon müsstest Du dafür sorgen, dass der Compiler die Größe der struct msg_s auflösen kann. Dieser Code hier funktioniert daher in C nicht:

Code:
struct msg_s {
   u_char info_str[dt_len->val + 1];
};

Möglicherweise funktioniert's in C++ wenn dt_len->val zur Compilezeit auf einen konstanten Wert aufgelöst werden kann. Bin mir aber auch hier nicht sicher ob das geht.
 
Sind die Anweisungen der Art 'ptr = NULL;' bzgl. den Zeigern: 'dt_len' und 'dt' ueberfluessig? Oder wenn diese nicht ueberfluessig sind und nicht gegeben seien, koennen sich diese dann als sogennante 'wilde Pointer' ihr dasein entfalten?

Du weißt aber, dass wenn du die Zeiger auf NULL setzt, der Speicher, auf den sie gezeigt haben, nicht automatisch freigegeben wird, oder (in diesem Fall wurst, aber immer im Kopf behalten)? Auf NULL setzen ist nur nötig, wenn du die Zeiger später noch weiterverwenden willst, also z.B. an eine andere Funktion übergibst, etc.. Dann wiederum solltest du jedesmal vorher prüfen, ob sie NULL sind oder nicht.

structs sollten eigentlich außerhalb der Funktionen definiert werden... ich frag mich auch, warum du alles in ein struct packen willst. Du benutzt doch eh pointer und die structs enthalten nur ein member, da kannst du auch gleich auf das member zeigen, ohne struct (also dt und msg als char*, dt_len als uint8_t*).

Code:
sprintf(msg->info_str, "%s%c", dt->b_str, '\0');

wenn dt->b_str ein string ist, dann ist er auch null-terminiert. dann brauchst du kein extra \0 anhängen. Ist er nicht null-terminiert, wird sprintf nicht funktionieren. In dem Fall solltest du evtl. memcpy benutzen und abschließend das ende durch \0 setzen.
 
@all_of_thread: Erst mal ein dickes Dankeschoen! Weil ich jetzt die richtige autodidaktische Denkrichtung erfahren habe.

Bzgl des Komponentenaddressierungsoperators "->" aus Fragment:
Code:
struct msg_s {
   u_char info_str[dt_len->val + 1];
}; 
		   
struct msg_s msg; 
		   		  	
(void)sprintf(msg->info_str, "%s%c", dt->b_str, '\0');	
log(LOG_PRINTF, "blablubb: %s", msg->info_str);
Da hat sich der Fehlerteufel (aufgrund copy-and-paste) eingeschlichen, ja da sollte definitiv ein "." hin, Asche auf mein Haupt *g*.

Zitat onenone:
structs sollten eigentlich außerhalb der Funktionen definiert werden... ich frag mich auch, warum du alles in ein struct packen willst. Du benutzt doch eh pointer und die structs enthalten nur ein member, da kannst du auch gleich auf das member zeigen, ohne struct (also dt und msg als char*, dt_len als uint8_t*).

Nun... ich hatte diese structs intern dieser Prozedur definiert, weil ich dachte, es sei der Datenkapselung dienlich (???). Wie auch immer, werde diese structs verwerfen und ihre (jetzt ehemaligen) Komponenten mit entsprechenden Zeigern referenzieren (sowie die Restliche, von hier nicht erwaehnten Quellcode, laut diesem Kriterium ueberarbeiten).

dt->b_str ist leider kein null-terminierter String (da die dem ppp_pr_paket zu extrahierenden Informationen bzw. das der dort enthaltenen ppp_opt zugewiesenen Informationen innnerhalb des Datenfeldes als Rohdaten vorliegen) und werde dann wohl mich naeher mit memcpy auseinandersetzen :-)

Bzgl. Zeiger auf NULL setzen... dann kann ich ja im gesamten Code entsprechend einige ueberfluessige Anweisungen (aufgrund inflationaeren Gebrauch dieser) entfernen, danke.
 
Zurück
Oben