I wrote a very simple program to experiment with it and with Deleaker to find what leaks could happen here:
#include <tchar.h>
#include <windows.h>
#include <Shlobj.h>
int _tmain(int argc, _TCHAR* argv[])
{
DebugBreak(); // I take snapshot here
_TCHAR szFolderPath[520] = _T("");
SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, NULL, szFolderPath);
// Then I take snapshot here
// and compare with previous one
DebugBreak();
SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, NULL, szFolderPath);
// Finally I take snapshot here
// and compare with previous one
DebugBreak();
return 0;
}
As you see I take 3 snapshots.
I take the first snapshot and got some allocations:

Then I take the second snapshot and calculate difference between it and previous snapshot to view what was allocated by SHGetFolderPath. Indeed some allocations were made:

In fact I suspected that this is one time allocations and that's true: I call SHGetFolderPath again, take new snapshot and compare it with previous one. No new allocations:

I did another experiment to be absolutely sure. Just start infinite cycle and check memory usage in Task Manager:
while (true)
{
_TCHAR szFolderPath[520] = _T("");
SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, NULL, szFolderPath);
}
Memory usage seems to be stable.
So I think you don't need to care about this small leak.