Search code examples
c++xcodemacosclang

Substring returns garbage when used on paths


I have the following piece of code to read a bunch of paths from another process..

//Allocate a large enough string to hold the paths..
std::string path(1024, '\0'); //there will never be a path > 1024 in length..
mach_vm_size_t size = path.size();

//Read them from the process..
int err = mach_vm_read_overwrite(task, reinterpret_cast<mach_vm_address_t>(image_infos[i].imageFilePath), size, reinterpret_cast<mach_vm_address_t>(&path[0]), &size);
if (err == KERN_SUCCESS)
{
    //Strip the path down to just the file name.
    std::string::size_type pos = path.find_last_of("\\/");
    if (pos != std::string::npos)
    {
        //Strip path components (prints just fine)
        printf("PATH: %s\n", path.c_str());

        path = path.substr(pos + 1);

        //After stripping the path (prints absolute trash)
        printf("PATH AFTER: %s\n", path.c_str());
    }
}

Before stripping it returns me:

PATH: /Applications/Xcode.app/Contents/Developer/usr/lib/libBacktraceRecording.dylib
PATH: /Applications/Xcode.app/Contents/Developer/usr/lib/libMainThreadChecker.dylib
PATH: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Debugger/libViewDebuggerSupport.dylib
PATH: /usr/lib/libc++.1.dylib
PATH: /usr/lib/libSystem.B.dylib
PATH: /usr/lib/libc++abi.dylib
PATH: /usr/lib/system/libcache.dylib
PATH: /usr/lib/system/libcommonCrypto.dylib
PATH: /usr/lib/system/libcompiler_rt.dylib
PATH: /usr/lib/system/libcopyfile.dylib
PATH: /usr/lib/system/libcorecrypto.dylib
PATH: /usr/lib/system/introspection/libdispatch.dylib
PATH: /usr/lib/system/libdyld.dylib
PATH: /usr/lib/system/libkeymgr.dylib
PATH: /usr/lib/system/liblaunch.dylib
PATH: /usr/lib/system/libmacho.dylib
PATH: /usr/lib/system/libquarantine.dylib
PATH: /usr/lib/system/libremovefile.dylib
PATH: /usr/lib/system/libsystem_asl.dylib
PATH: /usr/lib/system/libsystem_blocks.dylib
PATH: /usr/lib/system/libsystem_c.dylib
PATH: /usr/lib/system/libsystem_configuration.dylib
PATH: /usr/lib/system/libsystem_coreservices.dylib
PATH: /usr/lib/system/libsystem_darwin.dylib
PATH: /usr/lib/system/libsystem_dnssd.dylib
PATH: /usr/lib/system/libsystem_featureflags.dylib
PATH: /usr/lib/system/libsystem_info.dylib
PATH: /usr/lib/system/libsystem_m.dylib
PATH: /usr/lib/system/libsystem_malloc.dylib
PATH: /usr/lib/system/libsystem_networkextension.dylib
PATH: /usr/lib/system/libsystem_notify.dylib
PATH: /usr/lib/system/libsystem_sandbox.dylib
PATH: /usr/lib/system/libsystem_secinit.dylib
PATH: /usr/lib/system/libsystem_kernel.dylib
PATH: /usr/lib/system/libsystem_platform.dylib
PATH: /usr/lib/system/introspection/libsystem_pthread.dylib
PATH: /usr/lib/system/libsystem_symptoms.dylib
PATH: /usr/lib/system/libsystem_trace.dylib
PATH: /usr/lib/system/libunwind.dylib
PATH: /usr/lib/system/libxpc.dylib
PATH: /usr/lib/libobjc.A.dylib
PATH: /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation
PATH: /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
PATH: /usr/lib/libauto.dylib
PATH: /usr/lib/libfakelink.dylib
PATH: /usr/lib/libcompression.dylib
PATH: /System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration
PATH: /usr/lib/libarchive.2.dylib
PATH: /System/Library/PrivateFrameworks/MediaServices.framework/Versions/A/MediaServices

After stripping ANY of the paths, I get semi-readable junk (printf("%s\n"))

libMainThreadChecker.dylib
SceneKi
libcmph.dylib
libTelephonyUtilDynamic.dylib
libcompression.dylib



libsystem_kernel.dylib
libkxld.dylib
libmacho


libsystem_c.dylib

After stripping ANY of the paths, I get some weird junk (std::cout):

    \214\2512\325\377\377\377\377\377\377\377\377[e\377Ь_\377\340\230H\370([e\377 \350\260\230\355
P\357
X
HƼ\331\377\2256\377\377\377\371\357p^02ǭ\2422"U\377\377\377\377\377\377\377\377\260,e\377Ь_\377\340\370@\265,e\377 H\300\360
\361\360
\371\361
\331\362
\341\363
\321\364
\321\365
\321\366
\251\367
Y\370
1\371
9\372
\373
1\374
\375
)\376
9\377
AIA9Q\351       \371
\271
yAI
\211aX
PӼ\331\377h8\377\377\377\371\357p^$\3641Q2\325\377\377\377\377\377\377\377\377@`e\377Ь_\377\340H\250\340E`e\377 \230`\230\355
X
8g\275\331\377n7\377\377\377\354\357p^\266\327\375\2532 U\377\377\377\377\377\377\377\377ph\377Ь_\377\340Hhb\240th\377 \230 x

I have tried this as well:

if (err == KERN_SUCCESS && size > 0 && size < 1024)
{
    path = path.substr(0, size);
}

If I use std::cout, the output is even worse than printf("%s\n"). All of this happens the second I do the substr and I have no idea why.. without it, everything runs just fine :S

I am using Xcode Version 11.4.1 (11E503a)..

MacBook-Pro ~ % clang --version
Apple clang version 11.0.3 (clang-1103.0.32.59)
Target: x86_64-apple-darwin19.4.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

Any ideas what is going on? Did I do something wrong with std::string::substr?

EDIT: If I do:

char buffer[512] = {0};
mach_vm_size_t size = sizeof(buffer);

int err = mach_vm_read_overwrite(task, reinterpret_cast<mach_vm_address_t>(image_infos[i].imageFilePath), size, reinterpret_cast<mach_vm_address_t>(&buffer[0]), &size);
if (err == KERN_SUCCESS)
{
    std::string path = buffer; //lol

    std::string::size_type pos = path.find_last_of("\\/");
    if (pos != std::string::npos)
    {
        //Strip path components
        path = path.substr(pos + 1);

        printf("PATH: %s\n", path.c_str()); //PRINTS PERFECTLY!
    }
}

Solution

  • The problem is that C strings are NUL-terminated, while C++ std::string can contain embedded NULs. So after reading the path, you need to shrink the string to its actual length, which is strlen(path.data()) (not path.size() which is a buffer size only at that point), before doing anything else.