Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is _stprintf_s overwriting other variables but _stprintf is not?

I'm using visual studio for win32 programming class. I have a global array of string declared as TCHAR **bufTh allocated in memory like

bufTh = (TCHAR**)malloc(nOfTh*sizeof(TCHAR*));
for (i = 0; i < nOfTh; i++)
    bufTh[i] = (TCHAR*)malloc(BUF_LEN*sizeof(TCHAR));

then I have some threads, each of them writing on a different string in this array. I noticed that if i use _stprintf_s(bufTh[iTh], BUF_LEN, _T("%s\\"), findData.cFileName);, after this operation, some others global variables (in my case semaphores) are overwritten, while if I use _stprintf (without _s) everything goes well.

Why? Where am I going wrong?

I also tried as experiment to use an array of struct containing a string, like typedef struct{TCHAR buf[BUF_LEN];} mystr_t; and then allocate bufTh = (mystr_t*)malloc(nOfTh*sizeof(mystr_t));. In this case _stprintf_s is working as expected causing no problem.

EDIT: here is a mcve

#define UNICODE
#define _UNICODE
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NON_CONFORMING_SWPRINTFS
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#define BUF_LEN _MAX_PATH+1

typedef struct{
    DWORD iTh;
} tdata_t;

TCHAR **bufTh;
PHANDLE sem;

//DWORD WINAPI rThread(LPVOID pThParam);

int _tmain(int argc, LPTSTR argv[]){
    DWORD   i, nOfTh;
    PHANDLE hthread;
    tdata_t *tdata;

    nOfTh = 1;

    // global array of buffers, one for each reading thread
    bufTh = (TCHAR**)malloc(nOfTh*sizeof(TCHAR*));
    for (i = 0; i < nOfTh; i++)
        bufTh[i] = (TCHAR*)malloc(BUF_LEN*sizeof(TCHAR)); 

    // array of thread data, to pass to threads
    tdata = (tdata_t*)malloc(nOfTh*sizeof(tdata_t));
    for (i = 0; i < nOfTh; i++){
        tdata[i].iTh = i;
    }

    // array of semaphores, one for each thread
    sem = (PHANDLE)malloc((nOfTh)*sizeof(HANDLE)); 
    for (i = 0; i < nOfTh; i++)
        sem[i] = CreateSemaphore(NULL, 0, 1, NULL);

    // array of threads
    /*hthread = (PHANDLE)malloc(nOfTh*sizeof(HANDLE));
    for (i = 0; i < nOfTh; i++)
        hthread[i] = CreateThread(NULL, 0, &rThread, (LPVOID)&tdata[i], 0, NULL);*/

    i = 0;
    // BREAKPOINT HERE
    _stprintf_s(bufTh[i], BUF_LEN, _T("%s\\"), _T("the string that I want to write there"));
    // BREAKPOINT HERE
    WaitForSingleObject(sem[i], INFINITE);



    //WaitForMultipleObjects(nOfTh, hthread, TRUE, INFINITE);
    system("pause");
    return 0;
}
like image 847
gtatr Avatar asked May 27 '15 10:05

gtatr


1 Answers

also in my runs semaphores are overwritten with value 0xfefefefe

This is a "magic value", it is written by the safe CRT functions (like _stprintf_s) to help you debug mistakes in the buffer length you pass. The debug build of these functions fill the entire buffer, using 0xfe as a padding value.

   _stprintf_s(bufTh[i], BUF_LEN, ...));

So what you know is that the buffer size of thBuf[0] is not in fact BUF_LEN. In other words, the malloc() call is incorrect.

   #define BUF_LEN _MAX_PATH+1

This is an evil macro and causes your problem. It expands to

   bufTh[i] = (TCHAR*)malloc(_MAX_PATH + 1*sizeof(TCHAR));

Not what you meant of course. Fix:

   #define BUF_LEN (_MAX_PATH+1)

The extra parentheses are critical. Otherwise a good reason to start using the const keyword.

like image 98
Hans Passant Avatar answered Oct 05 '22 23:10

Hans Passant