HEAP CORRUPTION DETECTED in C - c

I am having some problems with my program and getting this error :
HEAP CORRUPTION DETECTED: before Normal block (#9873672) at 0x00968988.
CRT detected that the application wrote to memory before start of heap buffer.
I have tried to look for fixes but I can't figure out what it wrong with my program, what to fix and where :(
Here is the function I'm using and that is causing me problems :
What I am doing is basically look into a file for a specific keyword (argument of the function getText) and printing its matching value.
Sorry if most of the variables are in French, it's a project for school and our teacher require us to use French names >_<
#include "getText.h"
#include "main.h"
#include <stdlib.h>
texteLangue* ressourcesTexteLangue = NULL;
int compteur = 0;
char* getText(char* clef)
{
char* texte = NULL;
texte = clef; //clef is the keyword passed in the function as argument
texteLangue temp;
temp.clef = clef;
texteLangue* resultat = (texteLangue*) bsearch(&temp, ressourcesTexteLangue, compteur, sizeof(texteLangue), comparerClef); //returns the value associated with the key
if (clef != NULL)
{
if (resultat != NULL)
texte = resultat->valeur;
}
return texte;
}
void lectureTexte(char* langue)
{
char nomFichierRessources[64];
sprintf(nomFichierRessources, "ressources_%s.txt", langue); //give the file name a specific ending depending on the language chosen
FILE* FichierRessources = fopen(nomFichierRessources, "r");
if (FichierRessources == NULL)
{
system("cls");
perror("The following error occured ");
system("PAUSE");
exit(42);
}
//allocates memory for the language resources
int taille = 10;
ressourcesTexteLangue = (texteLangue *) calloc(taille, sizeof(texteLangue));
if (ressourcesTexteLangue == NULL)
printf("Pas assez de place mémoire pour les ressources texte");
//gives a value to TextResource.key and TextResource.value for each line of the file
char* ligne;
while ((ligne = lectureLigne(FichierRessources)))
{
if (strlen(ligne) > 0)
{
if (compteur == taille)
{
taille += 10;
ressourcesTexteLangue = (texteLangue *) realloc(ressourcesTexteLangue, taille * sizeof(texteLangue));
}
ressourcesTexteLangue[compteur].clef = ligne;
while (*ligne != '=')
{
ligne++;
}
*ligne = '\0';
ligne++;
ressourcesTexteLangue[compteur].valeur = ligne;
compteur++;
}
}
//sorts out the values of TextResource obtained
qsort(ressourcesTexteLangue, compteur, sizeof(texteLangue), comparerClef);
fclose(FichierRessources);
}
//reads a line and returns it
char* lectureLigne(FILE *fichier)
{
int longeur = 10, i = 0, c = 0;
char* ligne = (char*) calloc(longeur, sizeof(char));
if (fichier)
{
c = fgetc(fichier);
while (c != EOF)
{
if (i == longeur)
{
longeur += 10;
ligne = (char*) realloc(ligne, longeur * sizeof(char));
}
ligne[i++] = c;
c = fgetc(fichier);
if ((c == '\n') || (c == '\r'))
break;
}
ligne[i] = '\0';
while ((c == '\n') || (c == '\r'))
c = fgetc(fichier);
if (c != EOF)
ungetc(c,fichier);
if ((strlen(ligne) == 0) && (c == EOF))
{
free(ligne);
ligne = NULL;
}
}
return ligne;
}
//frees the TextRessources
void libererTexte()
{
if (ressourcesTexteLangue != NULL)
{
while (compteur--)
{
free(ressourcesTexteLangue[compteur].clef);
}
free(ressourcesTexteLangue);
}
}
//compares the keys
int comparerClef(const void* e1, const void* e2)
{
return strcmp(((texteLangue*) e1)->clef, ((texteLangue*) e2)->clef);
}
the structure of RessourceTextelangue (TextResources) look like this :
typedef struct texteLangue {
char* clef;
char* valeur;
} texteLangue;

There are several potential problems with your code that could be causing the error report you see.
Here is one:
if (i == longeur)
should be:
if ((i+1) == longeur)
otherwise,
ligne[i] = '\0';
can occur in conditions when
ligne[i++] = c;
has caused i to become equal to longeur.
Here is another:
while (*ligne != '=')
{
ligne++;
}
*ligne = '\0';
the above code should be:
while (*ligne != '=' && *ligne != '\0')
{
ligne++;
}
*ligne = '\0';
otherwise, you will corrupt memory in the case when there is no '=' to be found in the string.
Although either of these could cause the symptom you report, I see some other oddities that make me think there is more wrong than I have seen so far. Nevertheless, fixing those two problems will at least reduce the number of possibilities you have to consider.

Is your input guaranteed to contain a '=' in each line?
while (*ligne != '=') // if not, this will fly off the end of your buffer...
{
ligne++;
}
*ligne = '\0'; // ...and write to unallocated heap memory
Edit
Given #Heath's comment, if your input contains a blank line (including ending with a single blank line) then the above would most certainly be triggered.
c = fgetc(fichier); // reads '\n'
while (c != EOF)
{
...
ligne[i++] = c;
...
ligne[i] = '\0';
ligne now contains "\n" and is returned. later it is used:
if (strlen(ligne) > 0) // strlen("\n") is greater than 0
{
...
while (*ligne != '=') // oops! loop until we find a '=' somewhere
// in the heap or crash trying.
{
ligne++;
}
*ligne = '\0'; // corrupt the heap here

Related

C Best way to read series of characters without known length

I've to read a series of characters that must be brackets but I don't know how many characters the user type. So I think to use realloc each time I've to add the input.
I have to use scanf to read the characters
I wrote this code that works but I want to know if there's a way more secure or simply better.
char* read(void)
{
int count = 0,
valid = 1;
char *str = NULL,
*tmp = NULL;
char input;
printf("Digita sequenza di parentesi da analizzare: ");
do
{
scanf("%c", &input);
tmp = (char *)realloc(str, (++count) * sizeof(char));
if(tmp != NULL)
{
str = tmp;
str[count-1] = input;
/* check sul carattere letto verificando che sia una parentesi (escluso ENTER) */
if((input != '(' &&
input != ')' &&
input != '[' &&
input != ']' &&
input != '{' &&
input != '}' &&
input != '\n') ||
((count == 1) &&
(input == '\n')))
valid = 0;
}
else
{
valid = 0;
free(str);
}
} while(input != '\n');
/* TODO */
/* str[count] = '\0'; */
return (valid) ? str : NULL;
}
I would not suggest doing a realloc at every iteration. Rather use some optimal size buffer at the beginning and then do a realloc only if this size is crossed. Something as below:
#define DEFAULT_STEP_SIZE 64
char* read(void)
{
int count = 0,
valid = 1,
num_alloc = 0;
char *str = NULL,
*tmp = NULL;
char input;
str = malloc(DEFAULT_STEP_SIZE * sizeof(char));
if(str == NULL){
return NULL;
}
num_alloc = 1;
printf("Digita sequenza di parentesi da analizzare: ");
do
{
scanf("%c", &input);
if(count > num_alloc * DEFAULT_STEP_SIZE){
++num_alloc;
tmp = (char *)realloc(str, (num_alloc * DEFAULT_STEP_SIZE) * sizeof(char));
if(tmp == NULL){
free(str);
return NULL;
}else{
str = tmp;
}
}
count++;
str[count-1] = input;
/* check sul carattere letto verificando che sia una parentesi (escluso ENTER) */
if((input != '(' &&
input != ')' &&
input != '[' &&
input != ']' &&
input != '{' &&
input != '}' &&
input != '\n') ||
((count == 1) &&
(input == '\n')))
valid = 0;
} while(input != '\n');
/* TODO */
/* str[count] = '\0'; */
return (valid) ? str : NULL;
}

What's wrong with strtol?

I have this code, which should run fine, but for some reason, the loop would cycle through when I free the string before the conditional check of the loop. And the only way to get out from the loop is by giving integer with more than 3 digits (input > 99 || input < -99).
I'm using gcc to compile this code with code::blocks as IDE.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* createString(void);
int main() {
int temp = 0;
char* string = 0;
char* error = 0;
do {
printf("\n Integer: ");
string = createString();
temp = strtol(string, &error, 10);
if (*error != '\n' && *error != '\0') printf("\n Input is not an integer");
free(string);
string = 0;
} while (*error != '\n' && *error != '\0');
free(error);
error = 0;
return 0;
}
char* createString() {
char* string = 0;
size_t size = 0;
size_t index = 0;
int ch = EOF;
do {
ch = getc(stdin);
if (ch == EOF || ch == '\n') ch = 0;
if (size <= index) string = (char*) realloc(string, size += 5);
if (!string) {
perror("realloc");
exit(EXIT_FAILURE);
}
string[index++] = ch;
} while(ch);
return string;
}
I did a work-around it by moving the free-ing process to the beginning of the loop cycle and after the loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* createString(void);
int main() {
int temp = 0;
char* string = 0;
char* error = 0;
do {
free(string);
string = 0;
printf("\n Integer: ");
string = createString();
temp = strtol(string, &error, 10);
if (*error != '\n' && *error != '\0') printf("\n Input is not an integer");
} while (*error != '\n' && *error != '\0');
free(string);
string = 0;
free(error);
error = 0;
return 0;
}
char* createString() {
char* string = 0;
size_t size = 0;
size_t index = 0;
int ch = EOF;
do {
ch = getc(stdin);
if (ch == EOF || ch == '\n') ch = 0;
if (size <= index) string = (char*) realloc(string, size += 5);
if (!string) {
perror("realloc");
exit(EXIT_FAILURE);
}
string[index++] = ch;
} while(ch);
return string;
}
The code works fine now, but I'm wondering what is strtol doing.
free(error);
Remove it. error is not allocated in strtol or anywhere else. It is a pointer that points to the middle of string. Freeing it is UB.
You say:
for some reason, the loop would cycle through when I free the string before the conditional check of the loop
Keep in mind that with the call strtol(string, &error, 10); the pointer error will point into the string string. So if you free string before doing this:
if (*error != '\n' && *error != '\0') printf("\n Input is not an integer");
or this:
while (*error != '\n' && *error != '\0')
You'll invoke undefined behavior because error will be pointing to freed memory.

filling a Char array with scanf in C

How can I fill an empty Char Array with keyboard?
something like
char a_string[];
while("if not Q")
{
printf("Enter a number: ");
scanf("%c", a_string);
}
I know this is wrong
I just want to know how to give values to my a_string[], without limiting the size.
so the size will vary depend on how many keys i'm gonna enter from keyboard.
Thanks!
If you will know at the start of runtime how many keys you'll enter, you can have it ask first for the number of keys and then for the individual characters, as in the untested snippet below.
Otherwise, you have to set some real-world maximum (e.g. 10000) that will never be reached, or, if that's not possible, set a per-array maximum and make provisions for rollover into a new array. That last option really is the same (eventually bounded by memory) but gives you a larger maximum.
char *mychars;
int numchars;
printf("Please enter the total number of characters:\n");
if (scanf("%d", &numchars) == NULL) {
printf("couldn't read the input; exiting\n");
exit(EXIT_FAILURE);
}
if (numchars <= 0) {
printf("this input must be positive; exiting\n");
exit(EXIT_FAILURE);
}
mychars = (char *) malloc (numchars * sizeof(char));
int current_pos = 0;
printf("Enter a digit and hit return:\n");
while (scanf("%c", &mychars[current_pos]) != NULL && current_pos < numchars) {
current_pos++;
printf("Enter a digit and hit return:\n");
}
Try this:
#include <stdlib.h>
#include <stdio.h>
int main() {
char *string = NULL;
char *newstring = NULL;
char c = '\0';
unsigned int count = 0;
while(c != 'Q'){
c = getc(stdin);
if(string == NULL){
string = (char *) malloc(sizeof(char)); // remember to include stdlib.h
string[0] = c;
}
else{
newstring = (char *) realloc(string, sizeof(char)*count);
string = newstring;
string[count] = c;
}
count++;
}
string[count-1] = '\0'; // remove the Q character
fprintf(stderr,"here you are: %s",string);
free(string); // remember this!
return 0;
}
Repetitive calls to realloc() will meet the need.
Double realloc() size as needed to avoid O(n) calls.
char *GetQLessString(void) {
size_t size_alloc = 1;
size_t size_used = size_alloc;
char *a_string = malloc(size_alloc);
if (a_string == NULL) {
return NULL; // Out of memory
}
char ch;
while(scanf("%c", &ch) == 1 && (ch != 'Q')) {
size_used++;
if (size_used > size_alloc) {
if (size_alloc > SIZE_MAX/2) {
free(a_string);
return NULL; // Too big - been typing a long time
}
size_alloc *= 2;
char *new_str = realloc(a_string, size_alloc);
if (new_str == NULL) {
free(a_string);
return NULL; // Out of memory
}
a_string = new_str;
}
a_string[size_used - 2] = ch;
}
a_string[size_used - 1] = '\0';
return a_string;
}
Code could do a final realloc(a_string, size_used) to trim excess memory allocation.
Calling routine needs to call free() when done with the buffer.
The following would be cleaner.
int ch;
while((ch = fgetc(stdin)) != EOF && (ch != 'Q')) {

Valgrind reports "conditional jump depends on uninitialized value"; professor says should check strings

When valgrind runs this program (implementing a simple type of data compression), it reports "Conditional jump depends on uninitialized value." It also occasionally segfaults. Problem is, I can't seem to pinpoint which variable is not initialized. My CS professor mentioned that "your code doesn't make sure that the strings are properly null-terminated" but I can't see where.
https://gist.github.com/anonymous/9f6c87fb33985606a297
(edit - added the actual code here:)
#include &ltstdio.h>
#include &ltstdlib.h>
#include &ltstring.h>
#define WORDLIM 128
#define REPEAT for(;;)
struct word {
char *cont;
char *wsp;
int ctr;
};
char peekchar(void)
{
char c;
c = getchar();
if(c != EOF)
ungetc(c, stdin);
/* puts it back */
return c;
}
struct word *getword()
{
char cont[WORDLIM];
char wsp[WORDLIM];
cont[0] = '\0';
wsp[0] = '\0';
if (peekchar() == EOF)
{
return NULL;
}
REPEAT{
char c = getchar();
char buf[2];
buf[0]=c;
buf[1]='\0';
if (c == '\n' || c == ' ' || c == EOF)
{
if (c != EOF)
strcat(wsp, buf);
if (peekchar() != '\n' && peekchar() != ' ')
{
struct word *toret;
toret = malloc(sizeof(struct word));
toret->cont = malloc(strlen(cont) + 1);
strcpy(toret->cont, cont);
toret->wsp = malloc(strlen(wsp) + 1);
strcpy(toret->wsp, wsp);
toret->ctr = -1;
return toret;
}
continue;
}
else {
strcat(cont, buf);
continue;
}
}
printf("PANIC PANIC PANIC THIS IS GOING WROOOOONG!!!!!\n");
}
void numbrify(struct word **wordlist)
{
int oc = 0;
int roc = oc;
struct word *w;
while ((w = wordlist[oc]) != NULL){
int ic;
if (w->ctr == -1){
for (ic = oc + 1; wordlist[ic] != NULL; ic++){
if (!strcmp(wordlist[ic]->cont, w->cont)){
//printf("**found match between %s and %s**\n", wordlist[ic]->cont, w->cont);
wordlist[ic]->ctr = roc;
}
}
if (w->cont[0]!='\0')
roc++;
}
oc++;
}
}
int main(void){
struct word *wlist[4096];
int i = 0;
struct word *w;
for (i = 0; (w = getword()) != NULL; i++){
wlist[i]=w;
}
wlist[i+1] = NULL;
numbrify(wlist);
i = 0;
for (i = 0; wlist[i]!=NULL; i++){
if (wlist[i]->ctr == -1)
printf("%s%s", wlist[i]->cont, wlist[i]->wsp);
else
printf("%d%s", wlist[i]->ctr, wlist[i]->wsp);
//printf("'%s'\t'%s'\t%d\n", wlist[i]->cont, wlist[i]->wsp, wlist[i]->ctr);
}
return 0;
}
At line 85 of your program:
wlist[i+1] = NULL;
i already points to an unused entry in the array, so assigning NULL to wlist[i+1] leaves an undefined value before the end.
I determined this by running the Clang static analyzer*, which identified this issue in the first two diagnostics (as well as an unrelated, harmless error as the third one):
14968829.c:62:12: warning: Assigned value is garbage or undefined
while ((w = wordlist[oc]) != NULL){
^ ~~~~~~~~~~~~
14968829.c:65:35: warning: The left operand of '!=' is a garbage value
for (ic = oc + 1; wordlist[ic] != NULL; ic++){
~~~~~~~~~~~~ ^
14968829.c:87:2: warning: Value stored to 'i' is never read
i = 0;
^ ~
Correcting the issue (by changing wlist[i+1] to wlist[i]) caused the two Clang diagnostics to disappear, as well as the Valgrind errors.
*: Command line: clang --analyze -Wall 14968829.c -o 14968829

Dynamic memory allocation in C using realloc

I have read the other SO question about using realloc to get a new pointer to the beginning of a bigger memory address space but I cant figure out what I am doing wrong. It prints a backtrace and memory dump. I later try to access strhldr but I dont think it even gets that far.
char *strhldr = (char *)malloc(strsize);
int chrctr = 0;
if(chrctr == strsize - 3){ // when you get close
strsize = strsize*2; //double size
char *temp = realloc(strhldr, strsize); //make more room
if(temp == NULL)
printf("reallocate failed\n");
else{
strhldr = temp;
free(temp); // removed same issue
}
}
// Later attempt to add it to an array
cmdargs[i] = strhldr;
This is all within a while loop where chrctr and strsize get incremented
complete code
int argctr = 64;
char **cmdargs = (char **) malloc(argctr * sizeof(char*));
char c = getchar();
int i = 0;
while(c != '\n' && c != EOF){ //read through a String of stdin
int strsize = 32;
char *strhldr = (char *)malloc(strsize);
char *strstarthldr = strhldr;
if(c == ' ')
c = getchar();
while(c != ' ' && c != '\n' && c != EOF){
int chrctr = 0;
if(chrctr == strsize - 3){ // when you get close
strsize = strsize*2; //double size
char *temp = realloc(strhldr, strsize); //make more room
if(temp == NULL)
printf("reallocate failed\n");
else
strhldr = temp;
} //add that word to the array of strings
strhldr[chrctr] = c;
chrctr++;
c = getchar();
}
strhldr[charctr] = '\0';
//strhldr = strstarthldr;
cmdargs[i] = strhldr;
i++;
}
On success, realloc will free its argument if needed. So remove the call to free(temp).
It's not very clear to me what you are trying to do but I believe free(temp); invalidates strhldr and future read/write access to it will cause you trouble.
Second problem - your value charctr (not chrctr) is not set. Here is a version of your loop. I haven't tested it but it should be close.
if(c == ' ') {
c = getchar();
}
int chrctr = 0;
while(c != ' ' && c != '\n' && c != EOF){
if(chrctr == strsize - 3){ // when you get close
strsize = strsize*2; //double size
char *temp = realloc(strhldr, strsize); //make more room
if(temp == NULL) {
printf("reallocate failed\n");
break;
}
else {
strhldr = temp;
}
}
strhldr[chrctr] = c;
chrctr++;
c = getchar();
}
strhldr[chrctr] = 0;

Resources