0

I'm trying to getting UUID of a machine but this code get wrong result.

const char* getUUID() {
  char ret[512];
  io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/");
  CFStringRef uuidCf = (CFStringRef) IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
  IOObjectRelease(ioRegistryRoot);
  CFStringGetCString(uuidCf, ret, sizeof(ret)*sizeof(char), kCFStringEncodingUTF8);
  CFRelease(uuidCf);
  NSLog(@"getUUID1: %s", ret);
  return ret;
}
const char* getCPU() {
  char ret[255];
  strcpy(ret, "");
  NSLog(@"getUUID2: %s", getUUID());
  strcat(ret, getUUID());
  NSLog(@"ret: %s", ret);
  return ret;
}

Return this results:

getUUID1: 72B5E603-C915-52A7-K7C8-3E2N5214D18B - good

getUUID2: 72B5E60 - wrong

getUUID1: 72B5E603-C915-52A7-K7C8-3E2N5214D18B - good

ret: !è`? - absolutely wrong

Where am I wrong?

  • 2
    you are returning a pointer to a local variable (ret[512]). This is not valid. https://stackoverflow.com/questions/19042552/returning-a-pointer-of-a-local-variable-c Have a look at this too: https://stackoverflow.com/questions/1042940/writing-directly-to-stdstring-internal-buffers Specially the part where std::vector is used as a buffer – Pepijn Kramer Aug 22 '21 at 08:48
  • Returning data allocated on the stack is the #1 memory management bug in C++. Most compilers warn about it. So does Xcode. Haven't you seen the warning saying *"Address of stack memory associated with local variable 'ret' returned"*? – Codo Aug 22 '21 at 09:45

1 Answers1

0

I don't have all your includes or libraries so the next code is untested. But I think code with correct buffers would look like this:

#include <string>
#include <vector>

constexpr size_t buf_size = 512u;

std::string getUUID() 
{
    std::vector<char> buffer(buf_size);
    io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/");
    CFStringRef uuidCf = (CFStringRef)IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
    IOObjectRelease(ioRegistryRoot);
    CFStringGetCString(uuidCf, &buffer[0], buffer.size() * sizeof(char), kCFStringEncodingUTF8);
    CFRelease(uuidCf);
    NSLog(@"getUUID1: %s", ret);

    return std::string(buffer.data());
}

std::string getCPU() {
    std::vector<char> buffer(buf_size);
    NSLog(@"getUUID2: %s", getUUID());
    std::string ret(buffer.data());
    NSLog(@"ret: %s", ret);
    return ret;
}
Pepijn Kramer
  • 9,356
  • 2
  • 8
  • 19
  • But this it's something else entirely. Thanks, but need a char solution not string & vector. – Junayd Finley Aug 22 '21 at 11:56
  • Okay, does that mean you're working in "C"? Then you would need to "new" the buffer and let the caller delete it. Or you must let the client allocate a char buffer and pass it to the functions. – Pepijn Kramer Aug 22 '21 at 12:01
  • static char ret[512]; seems to solve the problem, but I do not know if it is a complete solution – Junayd Finley Aug 22 '21 at 12:04
  • If i use "new" solution how to delete it after use it ? – Junayd Finley Aug 22 '21 at 12:06
  • @JunaydFinley making it static does work, means the variable isn't allocated on the stack. But that it will be initialized once and keeps the memory for the duration of the program. It is usually only used if really needed. – Pepijn Kramer Aug 22 '21 at 12:26
  • char* p = new char[10]; and delete[] p; But it is basically why I don't like 'c' style memory managment. It is always unclear who will need to do the new, and who will have to do the delete. I try to keep them "symetric" so if the caller has to call delete then it also has to call the new and pass the buffer to the function – Pepijn Kramer Aug 22 '21 at 12:28
  • Thanks, I've already used them on both solutions. I think it's a limitation on C, other languages free the memory after the function makes return, not before return. – Junayd Finley Aug 23 '21 at 12:33
  • It is easy to make mistakes when switching between languages. They might look similar but in practise they can have totally different philosophies. For C++ this applies : https://en.cppreference.com/w/cpp/language/copy_elision But it might be a bit technical for you to read. But it means you can return local variables (and compiler will copy them on return, or do some optimization to avoid it). And bad luck for you was that this doesn't work for arrays. – Pepijn Kramer Aug 23 '21 at 13:01