C probleme mit malloc in while

BLACKDIAMONT

Lt. Commander
Registriert
Nov. 2012
Beiträge
1.471
Moinsen,

Haben wir bei CB ein paar C Gurus? Hintergrund ist folgender:

ich hatte vor einigen Jahren mal mit C angefangen, hatte damals aber schon probleme mit malloc und es beseite geschoben.

Jetzt habe ich das ganze mal wieder angefangen und mein matrix-bot-script von PHP in C gebastelt.
Es funktioniert solang einmal das Script läuft ... allerdings sobald es im loop läuft gibt es div malloc fehler ..

malloc(): invalid size (unsorted)

oder

corrupted size vs. prev_size

sind das Hauptproblem und treibt mich zur Verzweifelung :D

Ohne jetzt hunderte Codezeilen hier zu Posten ... ein Beispiel:

C:
void blubb(void) {
    char *retdata = malloc(1);
    size_t nbsize;
   
    while(true) {
        nbsize = snprintf(NULL, 0, "sync?timeout=30000&since=%s&filter=1&", next_batch);
        tmp = realloc(tmp, nbsize+1);
        sprintf(tmp, "sync?timeout=30000&since=%s&filter=1&", next_batch);
        retdata = getdata(tmp, botid);
    }
}

Das realloc wird angemeckert .. das hatte ich erst als malloc, aber das wirft nach dem zweiten loop "corrupted size ..."
Mit realloc eben das invalid sitze (unsorted) ...:grr:

Allerdings tritt das nicht jedesmal auf:freak:

Google quäle ich ständig ... #pragma war ein Vorschlag was irgendwie gar nix bringt (evtl mach ichs falsch).
Den Vorschlag mit "nimm doch C++" is für mich nicht die Lösung^^

Debug flags sind aktiv für gcc und ich nutze GDB so wie valgrind, was mir wenig hilft aktuell ...

#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1 0x00007ffff7c70537 in __GI_abort () at abort.c:79
#2 0x00007ffff7cc9768 in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff7de73a5 "%s\n") at ../sysdeps/posix/libc_fatal.c:155
#3 0x00007ffff7cd0a5a in malloc_printerr (str=str@entry=0x7ffff7de9b70 "malloc(): invalid size (unsorted)") at malloc.c:5347
#4 0x00007ffff7cd3b3c in _int_malloc (av=av@entry=0x7ffff7e1db80 <main_arena>, bytes=bytes@entry=241) at malloc.c:3736
#5 0x00007ffff7cd486e in _int_realloc (av=av@entry=0x7ffff7e1db80 <main_arena>, oldp=oldp@entry=0x55555555d9c0, oldsize=oldsize@entry=32, nb=256) at malloc.c:4600
#6 0x00007ffff7cd5c56 in __GI___libc_realloc (oldmem=0x55555555d9d0, bytes=238) at malloc.c:3235
#7 0x000055555555882c in start_bot (botid=0) at bot.c:318
#8 0x00005555555570a2 in main (argc=1, argv=0x7fffffffe0a8) at main.c:267

Hab mir schon einige Tutorials zu malloc und realloc angeschaut, aber so wirklich helfen tut das alles nich :/

Wer kann mich vor der totalen Verzweiflung bewaren? :daumen:
 
Zuletzt bearbeitet:
nbsize scheint ein string zu sein.
Mach doch einfach sowas

Code:
int nbsize = 2;
...
while(true) {

        tmp = realloc(tmp, nbsize++);
        sprintf(tmp, "sync?timeout=30000&since=%s&filter=1&", next_batch);
        retdata = getdata(tmp, botid);
    }

Was dein snprintf in der Schleife soll ist mir nicht klar
 
  • Gefällt mir
Reaktionen: madmax2010
Habs ergänzt :)
C:
size_t nbsize;

Das snprintf gibt soweit ich das verstanden habe, die bytes zurück die es benötigt um in eine Variable zu speichern. Das gibt mir die info für malloc, da die String größe dynamisch ist.
 
Ich glaube, dass du tmp noch initialisieren und auf NULL zeigen lassen musst.
C:
void blubb(void) {
    char *retdata = malloc(1);
    char *tmp = NULL;
    size_t nbsize;
 
    while(true) {
        nbsize = snprintf(NULL, 0, "sync?timeout=30000&since=%s&filter=1&", next_batch);
        tmp = realloc(tmp, nbsize+1);
        sprintf(tmp, "sync?timeout=30000&since=%s&filter=1&", next_batch);
        retdata = getdata(tmp, botid);
    }
}
 
  • Gefällt mir
Reaktionen: TomH22, cloudman und aroxx
Stimmt hatte ich vergessen dass snprintf die bytes liefert.

Klar muss realloc einen initialisieren Zeiger bekommen. Laut
https://en.cppreference.com/w/c/memory/realloc ist null nicht zulässig sondern der Speicher muss vorher mit malloc angefordert werden

Oh man bin ich froh mit C++ arbeiten zu dürfen
std::unique_ptr und ähnliches macht den Speicher Kram sehr viel angenehmer 😀
 
  • Gefällt mir
Reaktionen: Marco01_809
Also wenn mit Speicher so umgegangen wird, dass er eh nicht mehr freigegeben wird, dann frage ich mich: Wäre es nicht sinnvoll auf dem Stack ein verschwenderisch großer Speicherbereich zu definieren?

Also ist bekannt, wie groß next_batch denn sein kann? Also wie groß kann die Variable denn sein? Ich nehme an es geht um eine URL? Sind da nicht Grenzen von etwa 1000 Bytes? Also warum überhaupt mit dynamischem Speicher hier arbeiten?

Und ja, du sprichst von einem Beispiel, dennoch glaube ich, dass es um das Bauen einer URL geht.
 
  • Gefällt mir
Reaktionen: cloudman
Kampfkeks94 schrieb:
Ich glaube, dass du tmp noch initialisieren und auf NULL zeigen lassen musst.
Steht im Code, hatte ich nur vergessen reinzupacken :D
C:
char *tmp = malloc(1)
@tollertyp Das mit dem freigeben funktioniert nicht wirklich :/
Also ich hatte am Ende der while schleife free(retdata) etc stehen, gibt aber auch Fehler im loop :(

Bin mir nicht sicher wie groß next_batch werden kann, Aktuell steht z.b. das drin:
"s34815_3143682_26_5948_9988_25_340_192_2"
Was auch immer das in bytes ist :D

Ich schaue mal das ich das ins github hochlade.

@cloudman
Wie macht man das in einer Schleife? :)
 
  • Gefällt mir
Reaktionen: tollertyp
Ich hab nicht richtig gelesen.
Also du allokierst zeurst retdate, tmp ist null, und dann willst du realloc auf tmp machen, was mit einer festen Größe viel besser wäre?
In welchem Zusammenhang stehen denn die vorgesehenen Größen von tmp und retdata? Was macht "getdata" konkret? Vermutlich einen Service aufrufen und irgendwas mit vorher unbekannter Größe abrufen, mit nbsize dürfte das aber wohl wenig zu tun haben?

Edit: okay, das malloc für tmp fehlte einfach, dann nehme ich an, dass retdata in getdata allokiert wird. Warum es davor dann bereits allokiert wird, ist mir auch ein Rätsel...

Edit2: wenn ich das sehe, muss ich halt leider die Frage stellen, ob es wirklich C sein muss, oder ob eine andere Sprache da nicht besser geeignet wäre.
 
Zuletzt bearbeitet:
In der Schleife nur die bytes berechnen und anschließend in einem Rutsch allokieren

Realloc kann viel Zeit verbraten weil ggf. der Speicher Inhalt kopiert werden muss. Bei embedded kommt noch Speicherfragmentierung dazu
 
BLACKDIAMONT schrieb:
Was auch immer das in bytes ist :D
Nicht abschätzen können wie groß "s34815_3143682_26_5948_9988_25_340_192_2" in Bytes ist aber mit dynamischer Speicherverwaltung arbeiten? Ergibt Sinn.
Ergänzung ()

cloudman schrieb:
Bei embedded kommt noch Speicherfragmentierung dazu
Gerade bei embedded versucht man eine dynamische Speicherverwaltung zu vermeiden aus den von dir genannten Gründen, und weil es dort aufgrund des häufig knappen Speichers auch keine Garantien gibt, ob der Speicher dann während der Laufzeit auch wirklich zur Verfügung steht - was durch Fragmenitierung ja noch gefördert wird.
 
Off topic: ich habe ein paar commits fur esphome gemacht - ganz ohne dynamischen Speicher geht leider nicht immer - aber im Vergleich zu anderen Chips haben die esps zumindest nicht ganz so knapp bemessen Speicher.
std:unique_ptr ist dort mittlerweile vorgeschrieben um leaks zu verhindern.
 
Du meinst wegen solchen Leaks? :-)
Code:
void blubb(void) {
    char *retdata = malloc(1);
 ...
    while(true) {
...
        retdata = getdata(tmp, botid);
    }
}
 
  • Gefällt mir
Reaktionen: Marco01_809
Ach die paar bytes 😀
Wie ich es gehasst habe memory leaks zu debuggen.

Ich muß endlich mal Rust lernen
 
  • Gefällt mir
Reaktionen: tollertyp
Okay, damit es sollte es besser zu erkennen sein ;)
@cloudman Also malloc statt realloc in der Schleife?
 
Nein in der Schleife am besten nur berechnen wie viele bytes du brauchst wenn möglich (hab mir den Code nicht im Detail angeschaut)
Dann nach der Schleife einmal malloc
 
Okay, damit ich dich richtig verstehe :D
Ich nehm einfach mal mein beispiel:

C:
void blubb(void) {
    char *retdata = malloc(1);
    size_t nbsize;
 
    while(true) {
        nbsize = snprintf(NULL, 0, "sync?timeout=30000&since=%s&filter=1&", next_batch);
        sprintf(tmp, "sync?timeout=30000&since=%s&filter=1&", next_batch);
        retdata = getdata(tmp, botid);
    }
}
tmp = malloc(nbsize);
:confused_alt:
 
Ich kann nur wiederholen: Nimm eine Sprache, die besser zu deinem Problem passt.

Du hast im Übrigen noch nicht ein Argument geliefert, warum tmp mit malloc/realloc allokiert werden sollte. Und was getdata macht, ist immer noch unbekannt... warum wird retdata überhaupt einmal mit einem Byte allokiert?

Fragen über Fragen.

Edit: Okay, der github-Link beantwortet einige - aber nicht auf erfreuliche Art. Eher, dass man den Eindruck bekommt, dass konzeptlos irgendwelche Beispiel-Snippets zusammenkopiert wurden.
 
Zuletzt bearbeitet:
Nö wenn dann nbsize += snprint(
Ich mag mir jetzt nicht den github Code am Handy ansehen aber while(true) ist natürlich eine endlos Schleife
Wenn das so sein soll dann eher

C:
void blubb(void) {
    char *retdata = malloc(1);
    char *tmp = NULL;
    size_t nbsize;
 
    while(true) {
        nbsize = snprintf(NULL, 0, "sync?timeout=30000&since=%s&filter=1&", next_batch);
        tmp = malloc(nbsize+1);
        if (tmp) {
        sprintf(tmp, "sync?timeout=30000&since=%s&filter=1&", next_batch);
        retdata = getdata(tmp, botid);
        free(tmp) ;
     } else {. Error out of memory... } 
    }
}

@tollertyp hat sich den Code wohl etwas genauer angesehen und ich denke er hat mit seiner Analyse recht.
Sieht sehr zusammen kopiert aus - und sorry ohne wirkliche C skills.
Wenn man die Speicherverwaltung nicht wirklich versteht sind bugs vorprogrammiert 😉
 
  • Gefällt mir
Reaktionen: LencoX2
Was ist denn so schlimm an C?

Wie ich schon geschrieben hatte im ersten Post ... hab ich mehr oder minder mein php Script übernommen.

curl habe ich das beispiel genommen und angepasst ... json-c ist auch nach dem Beispiel gebaut.

Und nein Konzeptlos is das nicht wirklich ... ich progge nur Hobbymäßig also bin ich über Beispiele etc immer froh.

@cloudman Der bot läuft halt solange bis er gestoppt wird. Wüsste jetz nicht wie es besser geht :)
 
Zurück
Oben