The prototype of RegSetValueExA is:
LSTATUS RegSetValueExA(HKEY hKey,LPCSTR lpValueName,DWORD Reserved,DWORD dwType,const BYTE *lpData,DWORD cbData);
lpData points to the data to be stored in registry. cbData is the number of first bytes in lpData to be stored. In most cases, the function stores exactly cbData character in the registry. Each character (byte) is converted to 2 bytes(unicode of that byte) and then stored in registry. The NULL bytes in lpData are not handled specially, i.e., they are handled like other ordinary characters and not considered as the terminating NULL of a string. If the first cbData bytes in lpData do not contain null bytes, there will be no NULL bytes in the registry. If there are three null bytes, there would be 3 null unicodes in registry.
The reading function is:
LSTATUS RegQueryValueExA(HKEY hKey,LPCSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData);
lpData points to the memory you allocated. lpcbData points to any value, not necessarily the length of the whole allocated memory pointed by lpData. The function checks the size of what is stored in the registry, calculates how much memory is needed for storing those information(size in registry/2), and puts that calculated value to lpcbData. If the new lpcbData is larger than its original value(you specified), the function does not do anything(does not do partial copy so the content in lpData is not modified) and returns with the error code 234. If the new lpcbData is equal or less than the old value(you specified), this function copy the whole content(converted from unicode to byte) to lpData. The function does not bother to add NULL to the end of lpData.
The bug occurs when you call RegSetValueExA to store a null-terminated string lpData to registry but set cbData to strlen(lpData). Now, RegSetValueExA will actually store strlen(lpData)+1 characters(i.e.,2*(strlen(lpData)+1) bytes) in registry, i.e., RegSetValueExA will store the terminating null character of lpData to registry as well although you did not tell it to do so. If later you call RegQueryValueExA to retrieve the data but set lpcbData to strlen(lpData), the function will fail with the error code 234 because there’s 1 more character (the NULL character) in registry than strlen(lpData).
ps: somtimes, you may find garbled characters in the REG_SZ data of a registry value. It seems the data is corrupted. Anyway, you cannot recognize the mess content of the data. That is not necessarily a problem. regedit displays the data of a value according to the type of the value name. If the value name is ascii(created by RegSetValueExA), it displays the value data as ascii. If the value name is unicode(created by RegSetValueExW), it displays the value data as unicode. Note that it does not display the original value data (unicode) that is stored in registry but converts the two-byte unicode to one-byte ascii before displaying it. So, if the value name is unicode, the original value data is first converted into ascii(the data size is shrinked by half), then the ascii data is considered as unicode of characters at the half number of the original characters, so the result is garbled characters.