I am concatenating few strings using a custom function. The functions works correctly and I get the proper values but after few statements the values in the char pointers gets corrupted. I do not understand the reason behind this. Below is the part of a larger function. I am just providing the code till where the corruption happens
char* my_strcpy(char*dest, const char* src, int hasLen, int length) {
if (!hasLen) {
while ((*dest = *src++))
++dest;
} else {
while (length-- && (*dest = *src++))
++dest;
}
return dest;
}
int addSubscriptionInCache(subs_t* subs, str* pres_uri, int read_response) {
redisReply *reply;
char temp_key[1] = "";
char *tk = my_strcpy(temp_key, "", 0, 0);
char *subs_cache_key = tk;
char temp_value[1] = "";
char *tv = my_strcpy(temp_value, "", 0, 0);
char *subs_cache_value = tv;
tk = my_strcpy(tk, SUBSCRIPTION_SET_PREFIX, 0, 0);
tk = my_strcpy(tk, "-", 0, 0);
tk = my_strcpy(tk, subs->pres_uri.s, 0, 0);
tk = my_strcpy(tk, ":", 0, 0);
tk = my_strcpy(tk, subs->event->name.s, 0, 0);
*tk = '\0';
// this prints correctly.
printf("subs_cache_key: %d %s \n", strlen(subs_cache_key), subs_cache_key);
int subs_cache_value_len = subs->callid.len + subs->to_tag.len + 1; // add 1 for :
tv = my_strcpy(tv, subs->to_tag.s, 1,subs->to_tag.len);
tv = my_strcpy(tv, ":", 0, 0);
tv = my_strcpy(tv, subs->callid.s, 1,subs->callid.len);
*tv= '\0';
// this prints correctly.
printf("subs_cache_value: %d %s \n", strlen(subs_cache_value), subs_cache_value);
//add in pipeline
redisAppendCommand(redis_context, "SADD %s %s", subs_cache_key, subs_cache_value))
//set expires
redisAppendCommand(redis_context, "EXPIRE %s %d", subs_cache_key, subs->expires);
// create hash for to_tag:call_id
int argc = 0;
char *arvg[22];
size_t argvlen[22];
// this prints fine.
printf("Before corruption: %s", subs_cache_value);
arvg[argc] = "HMSET";
// below prints corrupted values
printf("After corruption: %s", subs_cache_value);
printf("After corruption: %s", subs_cache_key);
argvlen[argc] = 5;
argc++;
arvg[argc] = subs_cache_value;
argvlen[argc] = subs_cache_value_len;
argc++;
.......
//rest of the code
}
I am using the custom function so that not to traverse the whole string again and again.
Please help me understand if I have done something because of which corruption is happening.
Thanks
You have
char temp_key[1] = "";
char *tk = my_strcpy(temp_key, "", 0, 0);
and go on to use tk in subsequent calls to my_strcpy.
The problem is that you don't have enough memory. Using memory beyond the valid limits leads to undefined behavior.
Use something like:
char temp_key[1000] = ""; // Make the size large enough for
// the kinds of strings you are
// expecting to see.
Similarly, use:
char temp_value[1000] = "";
Related
So, I'm working on a preprocessor for C, my post on another site went semi viral (cprogramming.com)
What I want is a function, using PCRE2, that replaces a string with another string.
I also want a function that replaces a string with the result of a callback (a null-terminated) string for each match of a string
Ruby has
str.gsub /foo/ do |i|
end
I have code that does the first one, see (https://cboard.cprogramming.com/c-programming/181161-c-regular-expressions.html)
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
char* gsub (const char* str, const char* reg, const char* rep) {
size_t outlen;
static const char* error_str = "\"DONT KNOW HOW TO ALLOCATE MEM FOR REGEX\"";
char* out = malloc(outlen =strlen(str) * strlen(rep)) ;
if (out == NULL) {
error:
fputs(error_str, stderr);
return NULL;
}
int error;
PCRE2_SIZE erroffset;
// printf(\" %l \",
const PCRE2_SPTR pattern = (PCRE2_SPTR)reg;
const PCRE2_SPTR subject = (PCRE2_SPTR)str;
const PCRE2_SPTR replacement = (PCRE2_SPTR)rep;
pcre2_code *re = pcre2_compile(pattern, PCRE2_ZERO_TERMINATED, 0, &error, &erroffset, 0);
if (re == 0) return NULL;
// return 1;
pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
int rc = pcre2_substitute(re, subject, PCRE2_ZERO_TERMINATED, 0, PCRE2_SUBSTITUTE_GLOBAL | PCRE2_SUBSTITUTE_EXTENDED, 0, 0, replacement, PCRE2_ZERO_TERMINATED, out, &outlen);
if (rc >= 0);
// printf(%s\\n, output);
pcre2_code_free(re);
size_t new_len = strlen(out);
char* new_out = realloc(out,new_len + 1);
if (new_out == NULL) goto error;
return new_out;
}
Could someone help me to make the second function ?
Is there any way to have PCRE automatically account for memory allocation sizes?
The function below runs in LPC1769. I use FreeRTOS version 10.
I am having HardFault. I have debugged and I think I cornered the issue after long hours.
If I run this function it gives HardFault. Initially, I suspected malloc in substr3 function causes it. Freeing memory allocations didn't help. I therefore started to comment-out the code block by block until I find more accurate location of the issue in the parseMessage function.
If I comment out the lines between /* START OF PROBLEMATIC AREA */ and /* END OF PROBLEMATIC AREA */
the rest of code works without a single hiccup.
All I do in that code block, I assign values in the struct variables. The struct is global and initialized. I believe that that lines are causing the issue eventually. Maybe indirectly, I don't know that far.
e.g. strcpy(productInfoLeft.ucActualID, pid);
If I run all the codes in the parseMessage, it works for one or a few messages, they parsed OK and then MCU stops responding.
Struct in a file called common.h
struct ProductInfoLeft
{
char ucActualID[ 7 ];
char ucProductName[ 13 ];
char ucBestBeforeDate[ 13 ];
char ucPrinted[ 4 ];
char ucToBePrinted[ 4 ];
char ucLane[ 3 ];
char ucLcdNumber [ 2 ];
char ucPrinterLane [ 3 ];
char ucSupplierInfo [ 13 ];
};
extern struct ProductInfoLeft productInfoLeft;
struct ProductInfoRight
{
char ucActualID[ 7 ];
char ucProductName[ 13 ];
char ucBestBeforeDate[ 13 ];
char ucPrinted[ 4 ];
char ucToBePrinted[ 4 ];
char ucLane[ 3 ];
char ucLcdNumber [ 2 ];
char ucPrinterLane [ 3 ];
char ucSupplierInfo [ 13 ];
};
extern struct ProductInfoRight productInfoRight;
Struct initialization takes place in a file called lcdtasks.c;
struct ProductInfoLeft productInfoLeft = {
.ucActualID = "",
.ucProductName = "",
.ucBestBeforeDate = "",
.ucPrinted = "",
.ucToBePrinted = "",
.ucLane = "",
.ucLcdNumber = "",
.ucPrinterLane = "",
.ucSupplierInfo = ""
};
struct ProductInfoRight productInfoRight = {
.ucActualID = "",
.ucProductName = "",
.ucBestBeforeDate = "",
.ucPrinted = "",
.ucToBePrinted = "",
.ucLane = "",
.ucLcdNumber = "",
.ucPrinterLane = "",
.ucSupplierInfo = ""
};
And the parser function in another file called uarttask.c;
void parseMessage(char * message){
//Sample data
//const char* str = "7E00002A347C31323030302D3132353330387C33302E30372E323032307C31317C33307C33317C31352D31367C31357C317C57656E67657274880D0000";
// Parsing the frame
char* start;
char* len;
char* cmd;
char* data;
char* chksum;
char* end;
stripEOL(message);
unsigned int messagelen = strlen(message);
start = substr3(message, 0, 2);
len = substr3(message, 2, 4);
cmd = substr3(message, 6, 2);
data = substr3(message, 8, messagelen-8-4);
chksum = substr3(message, messagelen-4, 2);
end = substr3(message, messagelen-2, 2);
// Converting hex (only for data) to string
char str[250];
hex_to_string(data, str, sizeof(str));
// Parsing the data in variables
//Sample data content to be parsed in variables;
//char str1[50] ="7|10000-145310|12.10.2018|1|10|0|15-16|15|1|Wegert";
char pid[6], pname[12], bbdate[10], pnr[2], ltoprinted[3], lprinted[3], planes[5], laneNr[2], lcdNr[1], sinfo[12];
strcpy(pid, strtok(str , "|"));
strcpy(pname, strtok(NULL , "|"));
strcpy(bbdate, strtok(NULL, "|"));
strcpy(pnr , strtok(NULL, "|"));
strcpy(ltoprinted , strtok(NULL, "|"));
strcpy(lprinted, strtok(NULL, "|"));
strcpy(planes, strtok(NULL, "|"));
strcpy(laneNr, strtok(NULL, "|"));
strcpy(lcdNr, strtok(NULL, "|"));
strcpy(sinfo, strtok(NULL, "|"));
uint8_t resultLCDNr1 = strncmp(lcdNr, "1", 1);
uint8_t resultLCDNr2 = strncmp(lcdNr, "2", 1);
uint8_t result7E = strcmp(start, pcStart);
uint8_t result0D = strcmp(end, pcEnd);
uint8_t result2A = strcmp(cmd, pcProductChange);
uint8_t result30 = strcmp(cmd, pcSupplierChange);
char planeleft[2], planeright[2], tempplanes[5];
strcpy(tempplanes, planes); // If this is used, the next strcpy causes lprinted variable's first element to be "0\"
strcpy(planeleft, strtok(tempplanes , "-"));
strcpy(planeright, strtok(NULL , "-"));
/* START OF PROBLEMATIC AREA */
if (result7E == 0 && result0D == 0){
if (result2A == 0){ //Product Change
if (resultLCDNr1 == 0){
strcpy(productInfoLeft.ucActualID, pid);
strcpy(productInfoLeft.ucPrinterLane, planeleft);
strcpy(productInfoLeft.ucProductName, pname);
strcpy(productInfoLeft.ucBestBeforeDate, bbdate);
strcpy(productInfoLeft.ucPrinted, lprinted);
strcpy(productInfoLeft.ucToBePrinted, ltoprinted);
strcpy(productInfoLeft.ucLane, laneNr);
strcpy(productInfoLeft.ucLcdNumber, lcdNr);
strcpy(productInfoLeft.ucSupplierInfo, sinfo);
}else if (resultLCDNr2 == 0){
strcpy(productInfoRight.ucActualID, pid);
strcpy(productInfoRight.ucPrinterLane, planeright);
strcpy(productInfoRight.ucProductName, pname);
strcpy(productInfoRight.ucBestBeforeDate, bbdate);
strcpy(productInfoRight.ucPrinted, lprinted);
strcpy(productInfoRight.ucToBePrinted, ltoprinted);
strcpy(productInfoRight.ucLane, laneNr);
strcpy(productInfoRight.ucLcdNumber, lcdNr);
strcpy(productInfoRight.ucSupplierInfo, sinfo);
}else{
return;
}
SetProductChangeOnLCD(lcdNr);
}
if (result30 == 0){ //Supply Change
if (resultLCDNr1 == 0){
strcpy(productInfoLeft.ucActualID, pid);
strcpy(productInfoLeft.ucPrinterLane, planeleft);
strcpy(productInfoLeft.ucProductName, pname);
strcpy(productInfoLeft.ucBestBeforeDate, bbdate);
strcpy(productInfoLeft.ucPrinted, lprinted);
strcpy(productInfoLeft.ucToBePrinted, ltoprinted);
strcpy(productInfoLeft.ucLane, laneNr);
strcpy(productInfoLeft.ucLcdNumber, lcdNr);
strcpy(productInfoLeft.ucSupplierInfo, sinfo);
}else if (resultLCDNr2 == 0){
strcpy(productInfoRight.ucActualID, pid);
strcpy(productInfoRight.ucPrinterLane, planeright);
strcpy(productInfoRight.ucProductName, pname);
strcpy(productInfoRight.ucBestBeforeDate, bbdate);
strcpy(productInfoRight.ucPrinted, lprinted);
strcpy(productInfoRight.ucToBePrinted, ltoprinted);
strcpy(productInfoRight.ucLane, laneNr);
strcpy(productInfoRight.ucLcdNumber, lcdNr);
strcpy(productInfoRight.ucSupplierInfo, sinfo);
}else{
return;
}
SetSupplierChangeOnLCD(lcdNr);
}
}
/* END OF PROBLEMATIC AREA */
free(start);
free(len);
free(cmd);
free(data);
free(chksum);
free(end);
}
Substring function:
char *substr3(char const *input, size_t start, size_t len) {
char *ret = malloc(len+1);
memcpy(ret, input+start, len);
ret[len] = '\0';
return ret;
}
Just for future reference, I like to share my findings and resolution of the problems.
There were two issues. One was array sizes with char used for strcpy. There were not properly set as some contributors mentioned.
Once that array sizes fixed, another issue was revealed itself in a clearer manner. It was about the malloc. For some reason although some remarks say otherwise in various resources, if you use malloc within FreeRTOS implementation, there is a chance you might have HardFault. Once I switched to FreeRTOS suggested malloc and free functions, things flattened. HardFault issue magically disappeared.
I've just placed that two wrapper functions (somewhere in a common file) without even changing my malloc and free calls.;
Creating a malloc/free functions that work with the built-in FreeRTOS heap is quite simple. We just wrap the pvPortMalloc/pvPortFree calls:
void* malloc(size_t size)
{
void* ptr = NULL;
if(size > 0)
{
// We simply wrap the FreeRTOS call into a standard form
ptr = pvPortMalloc(size);
} // else NULL if there was an error
return ptr;
}
void free(void* ptr)
{
if(ptr)
{
// We simply wrap the FreeRTOS call into a standard form
vPortFree(ptr);
}
}
Note that: You can't use that with heap schema #1 but with the others (2, 3, 4 and 5). I would recommend start using portable/MemMang/heap_4.c
Basically, is there any way to split an array of strings into arrays of strings before and after a token ("|") in C.
An example is shown below.
char *input[] = {"hello","I","am","|","a","cool","|","guy"}
//code
and the result is 3 arrays, containing
{"Hello","I","am"}
{"a","cool"}
{"guy"}
I tried strtok but that seems to split a string into pieces, rather than an array of strings into new, separate, sub-arrays of strings. I also do not know exactly how many "|" tokens will be present, and will need an unknown amount of new arrays (safe to say it'd be less than 10). They will be passed to execvp so having it as one string and just remembering where to start and stop looking will not work.
They will be passed to execvp
Assuming the strings include the program to be executed (the 1st parameter to execvp()) and the strings will be used in the order of appearance as per this pointer-array
char *input[] = {"hello","I","am","|","a","cool","|","guy"}
then a possible simple solution without any duplications might look like this:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
char * input[] = {"hello", "I", "am", "|",
"a", "cool", "|",
"guy", "|"}; /* note the additional trailing `"|"`. */
int main(void)
{
char ** pcurrent = input;
char ** pend = pcurrent + sizeof input / sizeof *input;
while (pcurrent < pend)
{
{
char ** ptmp = pcurrent;
while (ptmp < pend && **ptmp != '|')
{
++ptmp;
}
*ptmp = NULL;
}
{
pid_t pid = fork();
if ((pid_t) -1) == pid)
{
perror("fork() failed");
exit(EXIT_FAILURE);
}
if ((pid_t) 0) == pid) /* child */
{
execvp(pcurrent[0], pcurrent);
perror("execvp() failed");
exit(EXIT_FAILURE);
}
/* parent */
pcurrent = ptmp + 1;
}
} /* while (pcurrent < pend) */
} /* int main(void) */
You need manually to split the input array. And dynamically allocate a new place to store result. E.g. as:
#include <stdio.h>
#include <stdbool.h>
int main()
{
char *input[] = {"hello","I","am","|","a","cool","|","guy"};
int inputLength = sizeof(input)/sizeof(input[0]);
printf("inputLength - %d\n", inputLength);
const char ***result2DimArray = malloc(sizeof(char**) * inputLength);
int *result2DimArrayLengths = malloc(sizeof(int) * inputLength);
memset(result2DimArrayLengths, 0, sizeof(int) * inputLength);
const char **currentSection = 0;
int nextSectionNumber = 0;
for(int inputIndex = 0; inputIndex < inputLength; inputIndex++)
{
if(input[inputIndex][0] == '|')
{
currentSection = 0;
}
else
{
if(!currentSection)
{
currentSection = malloc(sizeof(char*) * inputLength);
result2DimArray[nextSectionNumber] = currentSection;
nextSectionNumber++;
}
*currentSection = input[inputIndex];
currentSection++;
result2DimArrayLengths[nextSectionNumber-1]++;
}
}
/*Checking the result*/
printf("total sections - %d\n", nextSectionNumber);
for(int i=0; i<nextSectionNumber;i++)
{
for(int j=0;j<result2DimArrayLengths[i];j++)
{
printf(result2DimArray[i][j]);
printf(", ");
}
puts("");
}
return 0;
}
Here is a solution which doesn't involve dynamic memory allocation.
Before going in to the details ...
I think it's useful when tackling a problem like this to think about how the "strings" are stored in memory. It might look something like in the attached picture. (The memory addresses are completely unrealistic - and there would be null terminators at the end of each string - but you get the idea).
As the picture shows, the vital information we need for each 'sub-array' can be stored in a <char **, int> pair. The char ** is the address of the first "string" in the sub-array; the int is the number of strings it contains.
We can use a struct string_array_t to store this information.
typedef struct {
// Pointer to first string in sub-array
char **p;
// Number of strings in sub-array
int count;
} string_array_t;
We allocate an array of these on the stack; thus no need for malloc() or free() - as long as we allocate enough sub-arrays.
string_array_t string_arrays[MAX_SUB_ARRAYS] = {0};
char *input[] = {"hello", "I", "am", "|", "a", "cool", "|", "guy"};
// Pointer to current sub-array
string_array_t *cur = NULL;
size_t n_sub_arrays = 1;
Initialize our counters and pointers:
int i = 0, j = 0, k = 0;
cur = &string_arrays[0];
size_t n_strings_total = sizeof(input) / sizeof(input[0]);
Then loop over the array.
for (i = 0; i < n_strings_total; i++) {
if (!strcmp(input[i], "|")) {
// Store total number of strings in this sub-array
cur->count = k;
k = 0;
// Switch to next sub-array
cur = &string_arrays[++j];
if (j >= MAX_SUB_ARRAYS) {
fprintf(stderr, "Not enough sub-arrays allocated ...\n");
break;
}
n_sub_arrays++;
continue;
}
if (k == 0) {
cur->p = &input[i];
}
k++;
}
cur->count = k;
Print the results.
printf("Found %zu sub arrays ...\n", n_sub_arrays);
for (i = 0; i < n_sub_arrays; i++) {
string_array_t *cur = &string_arrays[i];
for (j = 0; j < cur->count; j++) {
printf("%s ", *(cur->p++));
}
printf("\n");
}
I'm confused on what I'm doing wrong in my C program: I'm trying to create a string that begins with a '!' and adds 6 values read from a sensor (separated by commas) and then sends it over a serial port. A sample output would be: "!5,5,5,5,5,5" or "!34,34,34,34,34,34".
The problem: Because the sensor values (5 or 34 in the example above) can range from 0 to 255, I don't know at runtime how big my char array needs to be. This means I have to dynamically reallocate memory every time I want to add to my string. Below is my attempt to do so, but I'm doing this wrong because I see nothing coming across my serial port (indicating that there's a runtime error).
How can I properly implement code to allocate memory dynamically for a string? My attempts to use malloc and realloc aren't behaving as expected.
char* convertIntToString(uint8_t integerValue){
char *str = malloc(4); //up to 3 digits + 1 for null termination
utoa(integerValue, str, 10);
return str;
}
char* concat(char *s1, char *s2)
{
char *result = malloc(strlen(s1)+strlen(s2)+1);//+1 for the zero-terminator
//in real code you would check for errors in malloc here
strcpy(result, s1);
strcat(result, s2);
return result;
}
int main(void)
{
uint8_t analogValue;
char *outputStr = malloc(1); //initalize size of char array = 1 element
while (1) {
outputStr = realloc(outputStr, 1);
outputStr = concat(outputStr, "!");
analogValue = ReadADC(0);
outputStr = concat(outputStr, convertIntToString(analogValue));
for(int i = 0; i < 5; i++){
outputStr = concat(outputStr, ",");
outputStr = concat(outputStr, convertIntToString(analogValue));
}
CDC_Device_SendString(&VirtualSerial_CDC_Interface, outputStr); //send string via USB
free(outputStr);
}
}
You are running into undefined behavior since the contents of outputStr are not initialized properly in the first statement inside the while loop.
outputStr = realloc(outputStr, 1); // outputStr is not initialized.
Change them to:
outputStr = realloc(outputStr, 2);
strcpy(outputStr, "!");
You are also leaking a whole bunch of memory. The value returned from convertToString is never freed.
You can avoid that problem by changing the strategy a little bit.
Change the function to expect a string and use it.
char* convertIntToString(uint8_t integerValue,
char* str)
{
utoa(integerValue, str, 10);
return str;
}
Then, change its usage as:
outputStr = concat(outputStr, convertIntToString(analogValue, str));
You are also leaking memory due to the way you are using concat.
outputStr = concat(outputStr, ",");
That leaks the old value of outputStr. You need to keep the old value of outputStr for a bit longer so you can free it.
Here's my suggestion for the while loop:
while (1) {
outputStr = realloc(outputStr, 2);
strcpy(outputStr, "!");
analogValue = ReadADC(0);
char str[4]; // This is the max you need.
// There is no need to malloc and free.
outputStr = concat(outputStr, convertIntToString(analogValue, str));
for(int i = 0; i < 5; i++){
char* newStr = concat(outputStr, ",");
// free the old memory before using the new memory
free(outputStr);
outputStr = newStr;
newStr = concat(outputStr, convertIntToString(analogValue, str));
// free the old memory before using the new memory
free(outputStr);
outputStr = newStr;
}
CDC_Device_SendString(&VirtualSerial_CDC_Interface, outputStr); //send string via USB
free(outputStr);
}
the following code:
eliminates the unnecessary calls to malloc, free, realloc, so (amongst other things) has no memory leaks
creates the desired string to output
eliminates the unnecessary sub functions
generates a correct outputStr[] array contents
and now the code:
#include <string.h>
int main(void)
{
uint8_t analogValue;
char outputStr[20];
char temp[4];
while (1)
{
memset( outputStr, 0, sizeof(outputStr) );
outputStr = strcat(outputStr, "!");
for(int i = 0; i < 5; i++)
{
analogValue = ReadADC(0);
if( i < 4 )
sprintf( temp, "%u,", analogValue );
else
sprintf( temp, "%u", analogValue );
strcat( outputStr, temp );
}
CDC_Device_SendString(&VirtualSerial_CDC_Interface, outputStr); //send string via USB
}
}
I have a function like
char *mdb_data = NULL;
int mdb_dataLen = 0;
char *getMDBDataPtr(int len)
{
if(len <= 0)
return NULL;
if(mdb_data == NULL)
{
mdb_data = (char *)malloc(len);
memset(mdb_data, 0, len);
mdb_dataLen = len;
}
else
{
if(mdb_dataLen < len)
{
free(mdb_data);
mdb_data=NULL;
mdb_data = (char *)malloc(len);
memset(mdb_data, 0, len);
mdb_dataLen = len;
}
}
return mdb_data;
}
When this function is called once i.e mdb_data=NULL it works. Afterwards when I called it with length 1 , 2 , 3 it failed when freeing memory for 3rd case i.e it free works fine twice and the crashes the application. Any ideas why this might be happening ?