Home > front end >  Memcpy in C causes STM to freeze after turning power off and on
Memcpy in C causes STM to freeze after turning power off and on

Time:12-10

I have a problem with STM32F401CCU. After executing a code disconnecting and connecting power the STM freezes and to unfreeze it I need to reload the build.

I have a complex set of functions that are used to turn an array of int values into a single very long char array. The char array is then written to the long term Flash memory. In order to execute that I do many operations with char arrays and they appear to be executed properly, as saving to Flash is done correctly - I tested Flash content with ST LINK and they are what they should be. But after turning power off/on to actually test if long term Flash memory works I encounter a fatal bug - upon powering STM back on it freezes and the only way to unfreeze it is to reload the build.

After many hours of tests I figured that the problem is with memcpy usage in StringCreateStrForFlashOneProduct. Presumably I created a sort of memory leak, but I don't get what's wrong.

A piece of example operation that causes STM to freeze:

static char send_save_string_final[2048];
char sssssend_char[2048] = "000000NewProduct";
char *StringCreateStrForFlashOneProduct(const int someint)
{
    memcpy(sssssend_char, "000000008888008000000000888800800000000088880080", 48);
    memcpy(send_save_string_final, sssssend_char, 48);
    return send_save_string_final;
}

The code I actually use:

FUNCTION ONE - Creates a single array of chars and then saves it to flash memory

static char output_all_sorts[6001] = "";
char all_save_string[6001] = "";
char sssssend_char_all_sorts[2048] = "00000AllProducts";
char append_char_numz_all_sorts[17] = "0000000000000000";

void FlashSaveAllSorts(void)
{
    strcpy(sssssend_char_all_sorts, "00000AllProducts");
    sssssend_char_all_sorts[2047] = 0;

    strcpy(output_all_sorts, "0");
    output_all_sorts[6000] = 0;
    strcpy(all_save_string, "00000AllProducts");
    all_save_string[6000] = 0;
    strcpy(append_char_numz_all_sorts, "0000000000000000");
    append_char_numz_all_sorts[16] = 0;

    for (int doin_int = 0; doin_int <= 6; doin_int  )
    {
        strcpy(sssssend_char_all_sorts, StringCreateStrForFlashOneProduct(doin_int));
        strcat(all_save_string, sssssend_char_all_sorts);
        strcpy(output_all_sorts, all_save_string);
    }

    strcpy(output_all_sorts, all_save_string);

    output_all_sorts[strlen(output_all_sorts)] = 0;
    Flash_Write_Data(0x08020000, output_all_sorts, 3000);
}

FUNCTION TWO - Creates a single line with all data for one product

static char send_save_string_final[2048] = "0";
char sssssend_char[2048] = "000000NewProduct";
char append_char_numz[17] = "0000000000000000";

char *StringCreateStrForFlashOneProduct(const int someint)
{
    strcpy(send_save_string_final, "0");
    send_save_string_final[2047] = 0;
    strcpy(sssssend_char, "000000NewProduct");
    sssssend_char[2047] = 0;
    strcpy(append_char_numz, "0000000000000000");
    append_char_numz[16] = 0;

    strncpy(append_char_numz, StringCreateStringFromIntTwo(someint), 17);
    append_char_numz[16] = 0;
    strcat(sssssend_char, append_char_numz);

    for (int kk = 0; kk < 3; kk = kk   1)
    {
        char append_char_one[17] = "0000000000000000";

        for (int jj = 0; jj < 12; jj = jj   1)
        {
            char append_char[17] = "0000000000000000";

            memcpy(append_char, StringCreateStringFromIntTwo(tunable_vars_machine_for_flash[someint][kk][jj]), 17);

            strcat(sssssend_char, append_char);
        }

        memcpy(append_char_one, "000000000MenuEnd", 17);
        strcat(sssssend_char, append_char_one);
    }

    char append_char_end_zeros[17] = "0000000000000000";
    memcpy(append_char_end_zeros, StringCreateStringFromIntTwo(0), 17);
    strcat(sssssend_char, append_char_numz);

    memcpy(send_save_string_final, sssssend_char, 2047);
    return send_save_string_final;
}

FUNCTION THREE - Creates a 16-chars array with a following format 000000000000001333, zeros are required to have consistent length of saved string, 1333 is example data value:

char *StringCreateStringFromIntTwo(int base_int_base)
{
    //clearprint("StringCreateStri");
    int base_int = base_int_base;

    if (base_int == 0)
    {
        base_int = 999999; /// avoid saving zero to flash memory
    }

    static char send_char_final[17]  = "0000000000000000";
    char send_char[16]  = "00000000";
    static char send_char_sixteen_zeros[17] = "0000000000000000";

    int legnewpigwphjh = strlen(send_char);

    char str_zero[2] = "0";
    char str_two_zeros[3] = "00";
    char str_three_zeros[4] = "000";
    char str_four_zeros[5] = "0000";
    char str_five_zeros[6] = "00000";
    char str_six_zeros[7] = "000000";
    char str_seven_zeros[8] = "0000000";
    char str_eight_zeros[9] = "00000000";
    char str_sixteen_zeros[17] = "0000000000000000";

    int int_mem_length = countDigits(base_int);

    char str_mem_write_int[9];
    sprintf(str_mem_write_int, "%d", base_int);

    if (int_mem_length == 7)
    {
        strcat(send_char, str_zero);
    }
    if (int_mem_length == 6)
    {
        strcat(send_char, str_two_zeros);
    }
    if (int_mem_length == 5)
    {
        strcat(send_char, str_three_zeros);
    }
    if (int_mem_length == 4)
    {
        strcat(send_char, str_four_zeros);
    }
    if (int_mem_length == 3)
    {
        strcat(send_char, str_five_zeros);
    }
    if (int_mem_length == 2)
    {
        strcat(send_char, str_six_zeros);
    }
    if (int_mem_length == 1)
    {
        strcat(send_char, str_seven_zeros);
    }

    strcat(send_char, str_mem_write_int);

    strcpy(send_char_final, str_sixteen_zeros);
    strcpy(send_char_final, send_char);

    return send_char_final;
}

CodePudding user response:

Your code is way too complicated. There are too many string copies and concatenations, and countless useless operations. You do not seem to master pointers, nor basic memory layout concepts. Above all, given your skill level, you should absolutely avoid strncpy and memcpy.

Here is a simpler approach with functions that construct the appropriate string format at the end of the buffer and return the number of characters written. With this method, composing a long string is much simpler and much less error prone:

// function to construct a fixed length string of digits with leading 0s
// buffer must point to an array at least 17 bytes long
// returns the number of characters, ie: 16
int FormatNumber16(char *buffer, int someint) {
    if (someint == 0) {
        // This test seems bogus: the product number 0 will be written as 999999
        // and so will the MenuEnd number
        someint = 999999;  // avoid writing 0 ???
    }
    return snprintf(buffer, 17, "6d", someint);
}

// function to construct the product string to store to flash
// buffer must point to an array at least 641 bytes long
// returns the number of characters, ie: 640
int FormatOneProduct(char *buffer, int product_nb) {
    int pos = 0;

    pos  = snprintf(buffer   pos, 17, "6s", "NewProduct");  
    pos  = FormatNumber16(buffer   pos, product_nb);  

    for (int kk = 0; kk < 3; kk  ) {
        for (int jj = 0; jj < 12; jj  ) {
            pos  = FormatNumber16(buffer   pos, 
                       tunable_vars_machine_for_flash[product_nb][kk][jj]);
        }
    }
    pos  = snprintf(buffer   pos, 17, "6s", "MenuEnd");  
    // vvv this will actually append 0000000000999999 ?
    pos  = FormatNumber16(buffer   pos, 0);
    // pos should be 640 = 16   16   12*3*16   16   16
    return pos; 
}

// function to write all product data to flash (7 products)
void FlashSaveAllSorts(void) {
    char buffer[6001] = "";   // no need for global data
    int pos = 0;

    pos  = snprintf(buffer   pos, 17, "6s", "AllProducts");  

    // append the description of all 7 products (0 to 6 included)
    for (int product_nb = 0; product_nb <= 6; product_nb  ) {
        pos  = FormatOneProduct(buffer   pos, product_nb);
    }
    // buffer contains 4496 = 16   640*7 characters, why write 3000 bytes?
    Flash_Write_Data(0x08020000, buffer, 3000);
}

CodePudding user response:

Some example functions:

char *StringCreateStrForFlashOneProduct(char *buff, size_t len, int someint)
{
    int mask = 1000000000;
    char *wrk = buff;

    if(!someint) someint = 999999;
    memset(buff, '0', len - 10);
    wrk  = len - 10;
    while(mask)
    {
        *wrk   = '0'   abs(someint / mask);
        someint %= mask;
        mask /= 10;
    }
    *wrk = 0;
    return buff;
}

example usage:

int main(void)
{
    char str[17];

    printf("`%s`\n", StringCreateStrForFlashOneProduct(str, 16, 1234));
}
  • Related