• Hey! Guest! The 40th (!!!) GMC Jam will take place between February 25th, 12:00 UTC to March 1st 12:00 UTC. Why not join in this very special anniversary jam! Click here to find out more!

SOLVED y it segfault

Samuel Venable

Time Killer
ubuntu needs sudo apt-get install g++ libprocps-dev

~/crosspross.cpp
C++:
/*

 MIT License
 
 Copyright © 2021 Samuel Venable
 Copyright © 2021 Lars Nilsson
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 
*/

#include <string>
#include <vector>
#include <algorithm>
#include <iostream>

#include <cstdlib>
#include <cstring>
#include <climits>
#include <cstdio>

#include <proc/readproc.h>

typedef pid_t PROSSID;

using std::string;
using std::vector;
using std::to_string;

namespace {

string PathFromFile(string file) {
  size_t fp = file.find_last_of("/\\");
  return file.substr(0, fp);
}

string NameFromFile(string file) {
  size_t fp = file.find_last_of("/\\");
  return file.substr(fp + 1);
}

} // anonymous namespace

namespace CrossPross {

void ExeFromProssId(PROSSID prossId, char **buffer) {
  string symLink = string("/proc/") + to_string(prossId) + string("/exe");
  char exe[PATH_MAX]; realpath(symLink.c_str(), exe);
  string str(exe); str.resize(str.length() + 1, '\0');
  *buffer = str.data();
}


// segfaults after 3 pids printed; backtrace is garbage even with -ggdb
void ProssIdFromExe(const char *exe, PROSSID **prossId, size_t *size) {
  proc_t proc_info;
  vector<PROSSID> vec; size_t i = 0;
  memset(&proc_info, 0, sizeof(proc_info));
  PROCTAB *proc = openproc(PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS);
  while (readproc(proc, &proc_info) != 0) {
    char *buffer;
    ExeFromProssId(proc_info.tgid, &buffer);
    string str1 = exe ? : "";
    string str2 = buffer ? : "";
    if (str1 == str2) {
      vec.push_back(proc_info.tgid); i++;
    } else if (str1 == NameFromFile(str2)) {
      vec.push_back(proc_info.tgid); i++;
    } else if (str1 == PathFromFile(str2)) {
      vec.push_back(proc_info.tgid); i++;
    }
  }
  std::copy(vec.begin(), vec.end(), *prossId);
  *size = i; closeproc(proc);
}

void CwdFromProssId(PROSSID prossId, char **buffer) {
  string symLink = string("/proc/") + to_string(prossId) + string("/cwd");
  char cwd[PATH_MAX]; realpath(symLink.c_str(), cwd);
  string str(cwd); str.resize(str.length() + 1, '\0');
  *buffer = str.data();
}

// segfaults after 3 pids printed; backtrace is garbage even with -ggdb
void ProssIdFromCwd(const char *cwd, PROSSID **prossId, size_t *size) {
  proc_t proc_info;
  vector<PROSSID> vec; size_t i = 0;
  memset(&proc_info, 0, sizeof(proc_info));
  PROCTAB *proc = openproc(PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS);
  while (readproc(proc, &proc_info) != 0) {
    char *buffer;
    CwdFromProssId(proc_info.tgid, &buffer);
    string str1 = cwd ? : "";
    string str2 = buffer ? : "";
    if (str1 == str2) {
      vec.push_back(proc_info.tgid); i++;
    }
  }
  std::copy(vec.begin(), vec.end(), *prossId);
  *size = i; closeproc(proc);
}

void CmdlineFromProssId(PROSSID prossId, char ***buffer, size_t *size) {
  proc_t proc_info;
  memset(&proc_info, 0, sizeof(proc_info));
  PROCTAB *proc = openproc(PROC_FILLCOM | PROC_PID, &prossId);
  size_t i = 0, pos = 0;
  if (readproc(proc, &proc_info) != 0) {
    while (proc_info.cmdline[pos] != NULL) {
      pos += strlen(proc_info.cmdline[i]);
      i++;
    }
  }
  *buffer = proc_info.cmdline;
  *size = i; closeproc(proc);
}

void EnvironFromProssId(PROSSID prossId, char ***buffer, size_t *size) {
  string env;
  proc_t proc_info;
  memset(&proc_info, 0, sizeof(proc_info));
  PROCTAB *proc = openproc(PROC_FILLENV | PROC_PID, &prossId);
  size_t i = 0, pos = 0;
  if (readproc(proc, &proc_info) != 0) {
    while (proc_info.environ[pos] != NULL) {
      pos += strlen(proc_info.environ[i]);
      i++;
    }
  }
  *buffer = proc_info.environ;
  *size = i; closeproc(proc);
}

} // namespace CrossPross

namespace CrossProssPrint {

void PrintExeFromPid(PROSSID prossId) {
  char *buffer;
  CrossPross::ExeFromProssId(prossId, &buffer);
  std::cout << buffer << std::endl;
}

void PrintPidFromExe(const char *exe) {
  PROSSID *prossId; size_t size;
  for (size_t i = 0; i < size; i++) {
    CrossPross::ProssIdFromExe(exe, &prossId, &size);
    std::cout << prossId[i] << std::endl;
  }
}

void PrintCwdFromPid(PROSSID prossId) {
  char *buffer;
  CrossPross::CwdFromProssId(prossId, &buffer);
  std::cout << buffer << std::endl;
}

void PrintPidFromCwd(const char *cwd) {
  PROSSID *prossId; size_t size;
  for (size_t i = 0; i < size; i++) {
    CrossPross::ProssIdFromCwd(cwd, &prossId, &size);
    std::cout << prossId[i] << std::endl;
  }
}

void PrintCmdFromPid(PROSSID prossId) {
  char **buffer;
  size_t size;
  for (size_t i = 0; i <= size; i++) {
    CrossPross::CmdlineFromProssId(prossId, &buffer, &size);
    std::cout << buffer[i] << std::endl;
  }
}

void PrintEnvFromPid(PROSSID prossId) {
  char **buffer;
  size_t size;
  for (size_t i = 0; i <= size; i++) {
    CrossPross::EnvironFromProssId(prossId, &buffer, &size);
    std::cout << buffer[i] << std::endl;
  }
}

} // namespace CrossProssPrint

int main(int argc, char **argv) {
  if (argc == 3) {
    PROSSID pid = 0;
    char *exe = NULL, *cwd = NULL;
    if (strcmp(argv[2], "self") == 0) {
      pid = getpid();
      CrossPross::ExeFromProssId(pid, &exe);
      CrossPross::CwdFromProssId(pid, &cwd);
    } else pid = strtoul(argv[2], nullptr, 10);
    if (strcmp(argv[1], "--exe-from-pid") == 0) {
      CrossProssPrint::PrintExeFromPid(pid);
    } else if (strcmp(argv[1], "--pid-from-exe") == 0) {
      CrossProssPrint::PrintPidFromExe(exe ? : argv[2]);
    } else if (strcmp(argv[1], "--cwd-from-pid") == 0) {
      CrossProssPrint::PrintCwdFromPid(pid);
    } else if (strcmp(argv[1], "--pid-from-cwd") == 0) {
      CrossProssPrint::PrintPidFromCwd(cwd ? : argv[2]);
    } else if (strcmp(argv[1], "--cmd-from-pid") == 0) {
      CrossProssPrint::PrintCmdFromPid(pid);
    } else if (strcmp(argv[1], "--env-from-pid") == 0) {
      CrossProssPrint::PrintEnvFromPid(pid);
    }
  }
  return 0;
}
~/crosspross --pid-from-exe /usr/bin
you can pass a parent directory, a exe name, or the path + exe to --pid-from -exe and case sensative it finds all pids that match
cd ~/;g++ "crosspross.cpp" -o "crosspross" -std=c++20 -static-libgcc -static-libstdc++ -lprocps -fPIC -ggdb -g
i tried adding -g and - ggdb and neither seemed to legitimately add debugging symbols and the backtrack wasn't helpful.

backtrace
Code:
neon@neon:~$ cd ~/;g++ "crosspross.cpp" -o "crosspross" -std=c++20 -static-libgcc -static-libstdc++ -lprocps -lpthread -fPIC -ggdb -g
neon@neon:~/$ gdb ./crosspross
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./crosspross...
(gdb) run --pid-from-exe /usr/bin
Starting program: /home/neon/crosspross --pid-from-exe /usr/bin
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
1479
1483
1487
1488
1644
1659
1664
1678
1680
1695
1697
1713
1721
1726
1822
2595
27536
31385
62789
62801
63106
63108
63122

Program received signal SIGSEGV, Segmentation fault.
0x000005d0000005cf in ?? ()
(gdb) bt
#0  0x000005d0000005cf in ?? ()
#1  0x0000067b0000066c in ?? ()
#2  0x0000068e00000680 in ?? ()
#3  0x0000069f00000690 in ?? ()
#4  0x000006b1000006a1 in ?? ()
#5  0x000006be000006b9 in ?? ()
#6  0x00000a230000071e in ?? ()
#7  0x00007a9900006b90 in ?? ()
#8  0x0000f5510000f545 in ?? ()
#9  0x0000f6840000f682 in ?? ()
#10 0x000000000000f692 in ?? ()
#11 0xd782b058c64d3307 in ?? ()
#12 0xd782a0147f633307 in ?? ()
#13 0x00007fff00000000 in ?? ()
#14 0x0000000000000000 in ?? ()
(gdb)
what are you do here
 
Last edited:

Samuel Venable

Time Killer
Code:
(gdb) file /home/neon/Desktop/crosspross
Reading symbols from /home/neon/Desktop/crosspross...
(gdb) run --pid-from-exe /usr/bin
Starting program: /home/neon/Desktop/crosspross --pid-from-exe /usr/bin
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
1659
72679
72845

Program received signal SIGSEGV, Segmentation fault.
0x00007fff00011c8d in ?? ()
(gdb) bt
#0  0x00007fff00011c8d in ?? ()
#1  0x00007ffff7ffc620 in ?? () from /lib64/ld-linux-x86-64.so.2
#2  0x00007fffffffde08 in ?? ()
#3  0x00000003f7f61fc8 in ?? ()
#4  0x000055555556bccb in CrossProssPrint::PrintEnvFromPid (prossId=72679) at crosspross.cpp:197
#5  0x0000555555610c10 in ?? ()
#6  0xfe701de102757785 in ?? ()
#7  0x000055555556a7d0 in _GLOBAL__sub_I_system_error.cc ()
#8  0x00007fffffffde00 in ?? ()
#9  0x0000000000000000 in ?? ()
(gdb)
I'll do valgrind next but this is what i have and i didn't even call that function oddly enough

I even went ahead and tried that exact function and process id directly and strange how it didn't crash when i acrually do call it
Code:
neon@neon:~$ ~/Desktop/crosspross --env-from-pid 72679
COLORFGBG=15;0
COLORTERM=truecolor
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
DESKTOP_SESSION=/usr/share/xsessions/plasma
 

chamaeleon

Member
C++:
/*
void ExeFromProssId(PROSSID prossId, char **buffer) {
  ...
  string str(exe); str.resize(str.length() + 1, '\0');
  *buffer = str.data();
}

void CwdFromProssId(PROSSID prossId, char **buffer) {
  ...
  string str(cwd); str.resize(str.length() + 1, '\0');
  *buffer = str.data();
}
Returning the address of something stack allocated (the std::string str variable, which will clean up any internal heap allocated data it uses when destroyed) can quite possibly cause issues for you. You could try making them static so they are local but are not stack allocated (making those variables thread-unsafe of course, and you need to copy any required information before calling the function again to avoid losing the content for a previous call or holding on to a possibly invalidated pointer).

Also, the str.data() function is not guaranteed to have a zero-terminated buffer returned (unlike str.c_str()), which in turn means constructing a std::string from such a pointer may or may not include additional characters after the valid data ends and/or also cause a crash.

Edit:
Finally, you're leaking memory related to your proc_t proc_info structure as fields like environ are allocated on the heap.
GML:
void ProssIdFromCwd(const char *cwd, PROSSID **prossId, size_t *size) {
  proc_t proc_info;
  ...
  if (readproc(proc, &proc_info) != 0) {
    ...
  }
}
Without calling procfree() with a dynamically allocated proc_t structure (because it frees the pointer itself, so can't be a pointer to an instance on the stack) or manually freeing the memory of data stored in it, you'll leak memory. Whether this is relevant or not depends on whether you're limiting your implementation to the standalone executable you have in your code, or if it will be turned into a reusable library to be used in a long running process with potentially many calls.
 
Last edited:

Yal

🍋 *lemon noises*
GMC Elder
From my experiences, segfaults in this type of situations usually happen when you link incompatible files (e.g. from different versions of the same SDK) so function references are undefined or erroneous... then when the code tries executing the function it loads non-executable memory (or a null pointer) and that's what's causing the actual segfault. (Segfaults are illegal memory references, where you try accessing a segment you're not allowed to)

So if you're compiling standard library code instead of writing your own stuff (this wasn't clear from the opening post), make sure you're meeting the prerequisites. Sometimes old libraries / packages use deprecated interfaces, and that's when this sort of thing usually happens (apt should handle installation dependencies fine so I don't think you're missing any libraries)
 

Samuel Venable

Time Killer
Returning the address of something stack allocated (the std::string str variable, which will clean up any internal heap allocated data it uses when destroyed) can quite possibly cause issues for you. You could try making them static so they are local but are not stack allocated (making those variables thread-unsafe of course).

Also, the str.data() function is not guaranteed to have a zero-terminated buffer returned (unlike str.c_str()), which in turn means constructing a std::string from such a pointer may or may not include additional characters after the valid data ends and/or also cause a crash.

Edit:
Finally, you're leaking memory related to your proc_t proc_info structure as fields like environ are allocated on the heap.
GML:
void ProssIdFromCwd(const char *cwd, PROSSID **prossId, size_t *size) {
  proc_t proc_info;
  ...
  if (readproc(proc, &proc_info) != 0) {
    ...
  }
}
Without calling procfree() with a dynamically allocated proc_t structure (because it frees the pointer itself, so can't be a pointer to an instance on the stack) or manually freeing the memory of data stored in it, you'll leak memory. Whether this is relevant or not depends on whether you're limiting your implementation to the standalone executable you have in your code, or if it will be turned into a reusable library to be used in a long running process with potentially many calls.

Thank you! That is very useful information.

From Google:
The realpath() function shall derive, from the pathname pointed to by file_name, an absolute pathname that names the same file, whose resolution does not involve '. ... The generated pathname shall be stored as a null-terminated string, up to a maximum of {PATH_MAX} bytes, in the buffer pointed to by resolved_name.
I was concatinating with std::string for no reason, aside from std::string making it not thread safe, i could've just spared myself and used strcat(), but also realpath() is null terminated, I got realpath() confused with readlink() which isn't necessarily null terminated but serves the same purpose other than that mostly. I forgot that's the whole reason I used realpath() and not readlink().

About your edit - also very useful. I'l try adding that and see if the segfaults go away.

Edit:
C++:
  std::copy(vec.begin(), vec.end(), *prossId);
  *size = i; closeproc(proc);
It's actually called closeproc(), and I am using it. Although perhaps you meant something else and misspoke?

Edit: I see what you mean. freeproc() is for proc_t * and not PROCTAB *.

Here's my code now but it still segfaults and now the file command doesn't help at all either:

C++:
/*

 MIT License
 
 Copyright © 2021 Samuel Venable
 Copyright © 2021 Lars Nilsson
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 
*/

#include <string>
#include <vector>
#include <algorithm>
#include <iostream>

#include <cstdlib>
#include <cstring>
#include <climits>
#include <cstdio>

#include <proc/readproc.h>

typedef pid_t PROSSID;

using std::string;
using std::vector;
using std::to_string;

namespace {

string PathFromFile(string file) {
  size_t fp = file.find_last_of("/\\");
  return file.substr(0, fp);
}

string NameFromFile(string file) {
  size_t fp = file.find_last_of("/\\");
  return file.substr(fp + 1);
}

} // anonymous namespace

namespace CrossPross {

void ExeFromProssId(PROSSID prossId, char **buffer) {
  string symLink = string("/proc/") + to_string(prossId) + string("/exe");
  char exe[PATH_MAX]; realpath(symLink.c_str(), exe);
  static string str; str = exe; str.resize(str.length() + 1, '\0');
  *buffer = (char *)str.c_str();
}


// segfaults after 3 pids printed; backtrace is garbage even with -ggdb
void ProssIdFromExe(const char *exe, PROSSID **prossId, size_t *size) {
  vector<PROSSID> vec; size_t i = 0;
  PROCTAB *proc = openproc(PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS);
  while (proc_t *proc_info = readproc(proc, NULL)) {
    char *buffer;
    ExeFromProssId(proc_info->tgid, &buffer);
    string str1 = exe ? : "";
    string str2 = buffer ? : "";
    if (str1 == str2) {
      vec.push_back(proc_info->tgid); i++;
    } else if (str1 == NameFromFile(str2)) {
      vec.push_back(proc_info->tgid); i++;
    } else if (str1 == PathFromFile(str2)) {
      vec.push_back(proc_info->tgid); i++;
    }
    freeproc(proc_info);
  }
  std::copy(vec.begin(), vec.end(), *prossId);
  *size = i; closeproc(proc);
}

void CwdFromProssId(PROSSID prossId, char **buffer) {
  string symLink = string("/proc/") + to_string(prossId) + string("/cwd");
  char cwd[PATH_MAX]; realpath(symLink.c_str(), cwd);
  static string str; str = cwd; str.resize(str.length() + 1, '\0');
  *buffer = (char *)str.c_str();
}

// segfaults after 3 pids printed; backtrace is garbage even with -ggdb
void ProssIdFromCwd(const char *cwd, PROSSID **prossId, size_t *size) {
  vector<PROSSID> vec; size_t i = 0;
  PROCTAB *proc = openproc(PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS);
  while (proc_t *proc_info = readproc(proc, NULL)) {
    char *buffer;
    CwdFromProssId(proc_info->tgid, &buffer);
    string str1 = cwd ? : "";
    string str2 = buffer ? : "";
    if (str1 == str2) {
      vec.push_back(proc_info->tgid); i++;
    }
    freeproc(proc_info);
  }
  std::copy(vec.begin(), vec.end(), *prossId);
  *size = i; closeproc(proc);
}

void CmdlineFromProssId(PROSSID prossId, char ***buffer, size_t *size) {
  PROCTAB *proc = openproc(PROC_FILLCOM | PROC_PID, &prossId);
  size_t i = 0, pos = 0;
  if (proc_t *proc_info = readproc(proc, NULL)) {
    while (proc_info->cmdline[pos] != NULL) {
      pos += strlen(proc_info->cmdline[i]);
      i++;
    }
    *buffer = proc_info->cmdline;
    freeproc(proc_info);
  }
  *size = i; closeproc(proc);
}

void EnvironFromProssId(PROSSID prossId, char ***buffer, size_t *size) {
  PROCTAB *proc = openproc(PROC_FILLENV | PROC_PID, &prossId);
  size_t i = 0, pos = 0;
  if (proc_t *proc_info = readproc(proc, NULL)) {
    while (proc_info->environ[pos] != NULL) {
      pos += strlen(proc_info->environ[i]);
      i++;
    }
    *buffer = proc_info->environ;
    freeproc(proc_info);
  }
  *size = i; closeproc(proc);
}

} // namespace CrossPross

namespace CrossProssPrint {

void PrintExeFromPid(PROSSID prossId) {
  char *buffer;
  CrossPross::ExeFromProssId(prossId, &buffer);
  std::cout << buffer << std::endl;
}

void PrintPidFromExe(const char *exe) {
  PROSSID *prossId; size_t size;
  for (size_t i = 0; i < size; i++) {
    CrossPross::ProssIdFromExe(exe, &prossId, &size);
    std::cout << prossId[i] << std::endl;
  }
}

void PrintCwdFromPid(PROSSID prossId) {
  char *buffer;
  CrossPross::CwdFromProssId(prossId, &buffer);
  std::cout << buffer << std::endl;
}

void PrintPidFromCwd(const char *cwd) {
  PROSSID *prossId; size_t size;
  for (size_t i = 0; i < size; i++) {
    CrossPross::ProssIdFromCwd(cwd, &prossId, &size);
    std::cout << prossId[i] << std::endl;
  }
}

void PrintCmdFromPid(PROSSID prossId) {
  char **buffer;
  size_t size;
  for (size_t i = 0; i <= size; i++) {
    CrossPross::CmdlineFromProssId(prossId, &buffer, &size);
    std::cout << buffer[i] << std::endl;
  }
}

void PrintEnvFromPid(PROSSID prossId) {
  char **buffer;
  size_t size;
  for (size_t i = 0; i <= size; i++) {
    CrossPross::EnvironFromProssId(prossId, &buffer, &size);
    std::cout << buffer[i] << std::endl;
  }
}

} // namespace CrossProssPrint

int main(int argc, char **argv) {
  if (argc == 3) {
    PROSSID pid = 0;
    char *exe = NULL, *cwd = NULL;
    if (strcmp(argv[2], "self") == 0) {
      pid = getpid();
      CrossPross::ExeFromProssId(pid, &exe);
      CrossPross::CwdFromProssId(pid, &cwd);
    } else pid = strtoul(argv[2], nullptr, 10);
    if (strcmp(argv[1], "--exe-from-pid") == 0) {
      CrossProssPrint::PrintExeFromPid(pid);
    } else if (strcmp(argv[1], "--pid-from-exe") == 0) {
      CrossProssPrint::PrintPidFromExe(exe ? : argv[2]);
    } else if (strcmp(argv[1], "--cwd-from-pid") == 0) {
      CrossProssPrint::PrintCwdFromPid(pid);
    } else if (strcmp(argv[1], "--pid-from-cwd") == 0) {
      CrossProssPrint::PrintPidFromCwd(cwd ? : argv[2]);
    } else if (strcmp(argv[1], "--cmd-from-pid") == 0) {
      CrossProssPrint::PrintCmdFromPid(pid);
    } else if (strcmp(argv[1], "--env-from-pid") == 0) {
      CrossProssPrint::PrintEnvFromPid(pid);
    }
  }
  return 0;
}
 
Last edited:

chamaeleon

Member
It's actually called closeproc(), and I am using it. Although perhaps you meant something else and misspoke?
closeproc() will free stuff related to your proc variable. I don't think it will free anything allocated by readproc() which will be held in your proc_info variable (like environ).
C:
proc_t* proc_info;
...
proc_info = readproc(proc, NULL); // request a new struct to be allocated instead of using an existing struct
if (proc_info != NULL) {
    ...
    freeproc(proc_info); // free all allocated memory for the struct including itself
}
Or, I think .. (but I wouldn't like being responsible for making sure I catch all cases of needed frees)
C:
proc_t proc_info;
...
readproc(proc, &proc_info);
...
if (proc_info.environ != NULL) free(proc_info.environ);
if (proc_info.cmdline != NULL) free(proc_info.cmdline);
 
Last edited:

chamaeleon

Member
C++:
...
  static string str; str = exe; str.resize(str.length() + 1, '\0');
  *buffer = (char *)str.c_str();
...
   *buffer = proc_info->cmdline;
    freeproc(proc_info);
...
    *buffer = proc_info->environ;
    freeproc(proc_info);
...
}
No need to resize str to add a terminating zero. str.c_str() will handle it for you as needed.

You're retaining a pointer value that is deallocated right after (possibly the root cause of your crash for this version of the code). You could try
C:
...
    *buffer = strdup(proc_info->cmdline);
    freeproc(proc_info);
...
    *buffer = strdup(proc_info->environ);
    freeproc(proc_info);
...
and call free(buffer) when you're done with them after the calls to get the values.

Edit: scratch my change. I am not familiar with the proc api and the structs. I just realized that the may be zero terminated entries in a single allocated buffer, which means strdup won't work (for environ, perhaps ok for cmdline). Anyway, the problem is freeing the struct while needing the data. Since you're writing C++ code, personally I'd probably pass in a reference to a std::vector<std::string> and fill it before freeing the structure instead of dealing with all the pointers and size variables.

Edit: Use of uninitialized variable as loop terminator need to be fixed as well
C:
size_t size;
  for (size_t i = 0; i <= size; i++) {
Related of course, I'd change
C:
for (size_t i = 0; i < size; i++) {
    CrossPross::ProssIdFromCwd(cwd, &prossId, &size);
...
into
C:
CrossPross::ProssIdFromCwd(cwd, &prossId, &size);
for (size_t i = 0; i < size; i++) {
...
The data shouldn't be changing over the iterations. I think you're gathering the same data over and over, and just pick a different entry for display. All the data is there the first time you call these functions, so move it outside the loop. Doesn't eliminate the required changes related to freeing memory before these functions returns, of course.
 
Last edited:

Samuel Venable

Time Killer
Here's what i have now:

C++:
/*

 MIT License
 
 Copyright © 2021 Samuel Venable
 Copyright © 2021 Lars Nilsson
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 
*/

#include <string>
#include <vector>
#include <algorithm>
#include <iostream>

#include <cstdlib>
#include <cstring>
#include <climits>
#include <cstdio>

#include <proc/readproc.h>

typedef pid_t PROSSID;

using std::string;
using std::vector;
using std::to_string;

namespace {

string PathFromFile(string file) {
  size_t fp = file.find_last_of("/\\");
  return file.substr(0, fp);
}

string NameFromFile(string file) {
  size_t fp = file.find_last_of("/\\");
  return file.substr(fp + 1);
}

} // anonymous namespace

namespace CrossPross {

void ExeFromProssId(PROSSID prossId, char **buffer) {
  string symLink = string("/proc/") + to_string(prossId) + string("/exe");
  char exe[PATH_MAX]; realpath(symLink.c_str(), exe);
  *buffer = strdup(exe);
}

// segfaults after 3 pids printed; backtrace is garbage even with -ggdb
void ProssIdFromExe(const char *exe, PROSSID **prossId, size_t *size) {
  vector<PROSSID> vec; size_t i = 0;
  PROCTAB *proc = openproc(PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS);
  while (proc_t *proc_info = readproc(proc, NULL)) {
    char *buffer;
    ExeFromProssId(proc_info->tgid, &buffer);
    string str1 = exe ? : "";
    string str2 = buffer ? : "";
    free(buffer);
    if (str1 == str2) {
      vec.push_back(proc_info->tgid); i++;
    } else if (str1 == NameFromFile(str2)) {
      vec.push_back(proc_info->tgid); i++;
    } else if (str1 == PathFromFile(str2)) {
      vec.push_back(proc_info->tgid); i++;
    }
    freeproc(proc_info);
  }
  std::copy(vec.begin(), vec.end(), *prossId);
  *size = i; closeproc(proc);
}

void CwdFromProssId(PROSSID prossId, char **buffer) {
  string symLink = string("/proc/") + to_string(prossId) + string("/cwd");
  char cwd[PATH_MAX]; realpath(symLink.c_str(), cwd);
  *buffer = strdup(cwd);
}

// segfaults after 3 pids printed; backtrace is garbage even with -ggdb
void ProssIdFromCwd(const char *cwd, PROSSID **prossId, size_t *size) {
  vector<PROSSID> vec; size_t i = 0;
  PROCTAB *proc = openproc(PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS);
  while (proc_t *proc_info = readproc(proc, NULL)) {
    char *buffer;
    CwdFromProssId(proc_info->tgid, &buffer);
    string str1 = cwd ? : "";
    string str2 = buffer ? : "";
    free(buffer);
    if (str1 == str2) {
      vec.push_back(proc_info->tgid); i++;
    }
    freeproc(proc_info);
  }
  std::copy(vec.begin(), vec.end(), *prossId);
  *size = i; closeproc(proc);
}

void CmdlineFromProssId(PROSSID prossId, char ***buffer, size_t *size) {
  static vector<string> vec1; size_t i = 0;
  PROCTAB *proc = openproc(PROC_FILLCOM | PROC_PID, &prossId);
  if (proc_t *proc_info = readproc(proc, NULL)) {
    while (proc_info->cmdline[i] != NULL) {
      vec1.push_back(proc_info->cmdline[i]);
      i++;
    }
    freeproc(proc_info);
  }
  vector<char *> vec2;
  for (size_t i = 0; i <= vec1.size(); i++)
    vec2.push_back((char *)vec1[i].c_str());
  char **arr = new char *[vec2.size()]();
  std::copy(vec2.begin(), vec2.end(), arr);
  *buffer = arr; *size = i; closeproc(proc);
}

void EnvironFromProssId(PROSSID prossId, char ***buffer, size_t *size) {
  static vector<string> vec1; size_t i = 0;
  PROCTAB *proc = openproc(PROC_FILLENV | PROC_PID, &prossId);
  if (proc_t *proc_info = readproc(proc, NULL)) {
    while (proc_info->environ[i] != NULL) {
      vec1.push_back(proc_info->environ[i]);
      i++;
    }
    freeproc(proc_info);
  }
  vector<char *> vec2;
  for (size_t i = 0; i <= vec1.size(); i++)
    vec2.push_back((char *)vec1[i].c_str());
  char **arr = new char *[vec2.size()]();
  std::copy(vec2.begin(), vec2.end(), arr);
  *buffer = arr; *size = i; closeproc(proc);
}

} // namespace CrossPross

namespace CrossProssPrint {

void PrintExeFromPid(PROSSID prossId) {
  char *buffer;
  CrossPross::ExeFromProssId(prossId, &buffer);
  std::cout << buffer << std::endl;
  free(buffer);
}

void PrintPidFromExe(const char *exe) {
  PROSSID *prossId; size_t size;
  CrossPross::ProssIdFromExe(exe, &prossId, &size);
  for (size_t i = 0; i < size; i++) {
    std::cout << prossId[i] << std::endl;
  }
}

void PrintCwdFromPid(PROSSID prossId) {
  char *buffer;
  CrossPross::CwdFromProssId(prossId, &buffer);
  std::cout << buffer << std::endl;
  free(buffer);
}

void PrintPidFromCwd(const char *cwd) {
  PROSSID *prossId; size_t size;
  CrossPross::ProssIdFromCwd(cwd, &prossId, &size);
  for (size_t i = 0; i < size; i++) {
    std::cout << prossId[i] << std::endl;
  }
}

void PrintCmdFromPid(PROSSID prossId) {
  char **buffer; size_t size;
  CrossPross::CmdlineFromProssId(prossId, &buffer, &size);
  for (size_t i = 0; i < size; i++) {
    std::cout << buffer[i] << std::endl;
  }
  free(buffer);
}

void PrintEnvFromPid(PROSSID prossId) {
  char **buffer; size_t size;
  CrossPross::EnvironFromProssId(prossId, &buffer, &size);
  for (size_t i = 0; i < size; i++) {
    std::cout << buffer[i] << std::endl;
  }
  free(buffer);
}

} // namespace CrossProssPrint

int main(int argc, char **argv) {
  if (argc == 3) {
    PROSSID pid = 0;
    char *exe = NULL, *cwd = NULL;
    if (strcmp(argv[2], "self") == 0) {
      pid = getpid();
      CrossPross::ExeFromProssId(pid, &exe);
      CrossPross::CwdFromProssId(pid, &cwd);
    } else pid = strtoul(argv[2], nullptr, 10);
    if (strcmp(argv[1], "--exe-from-pid") == 0) {
      CrossProssPrint::PrintExeFromPid(pid);
    } else if (strcmp(argv[1], "--pid-from-exe") == 0) {
      CrossProssPrint::PrintPidFromExe(exe ? : argv[2]);
    } else if (strcmp(argv[1], "--cwd-from-pid") == 0) {
      CrossProssPrint::PrintCwdFromPid(pid);
    } else if (strcmp(argv[1], "--pid-from-cwd") == 0) {
      CrossProssPrint::PrintPidFromCwd(cwd ? : argv[2]);
    } else if (strcmp(argv[1], "--cmd-from-pid") == 0) {
      CrossProssPrint::PrintCmdFromPid(pid);
    } else if (strcmp(argv[1], "--env-from-pid") == 0) {
      CrossProssPrint::PrintEnvFromPid(pid);
    }
  }
  return 0;
}
I have good news; printing the Environment Block and Command Line no longer segfaults. However there's also bad news, printing a list of Process ID's from a given Executable or Current Working Directory still segfaults. I think you've helped enough for now, I don't want you guys devoting too much of your time if it's a burden at all.

That said, I'll post the fully working code here when it's done.
 
Last edited:

chamaeleon

Member
C++:
void ProssIdFromExe(const char *exe, PROSSID **prossId, size_t *size) {
...
  std::copy(vec.begin(), vec.end(), *prossId);
...
}

void ProssIdFromCwd(const char *cwd, PROSSID **prossId, size_t *size) {
...
  std::copy(vec.begin(), vec.end(), *prossId);
...
}


void PrintPidFromExe(const char *exe) {
  PROSSID *prossId; size_t size;
  CrossPross::ProssIdFromExe(exe, &prossId, &size);
...
}

void PrintPidFromCwd(const char *cwd) {
  PROSSID *prossId; size_t size;
  CrossPross::ProssIdFromCwd(cwd, &prossId, &size);
...
}
In both cases, you're attempting to copy from a vector into unallocated space. You pass in an address to an uninitialized pointer value, and do not allocate space within the functions that get the data before the copy operation.

Maybe add a malloc() call before copying will be sufficient.
C:
void ProssIdFromExe(const char *exe, PROSSID **prossId, size_t *size) {
...
  *prossId = (PROSSID *)malloc(sizeof(PROSSID)*vec.size());
  std::copy(vec.begin(), vec.end(), *prossId);
...
}

void ProssIdFromCwd(const char *cwd, PROSSID **prossId, size_t *size) {
...
  *prossId = (PROSSID *)malloc(sizeof(PROSSID)*vec.size());
  std::copy(vec.begin(), vec.end(), *prossId);
...
}
Although, since you're using C++, why not simply use the std::vector<> you have already populated as the means to get the data out and get rid manual memory management? Unless the purpose is for your functions to have a C API down the road.
 
Last edited:

Samuel Venable

Time Killer
In both cases, you're attempting to copy from a vector into unallocated space. You pass in an address to an uninitialized pointer value, and do not allocate space within the functions that get the data before the copy operation.

Maybe add a malloc() call before copying will be sufficient.
C:
void ProssIdFromExe(const char *exe, PROSSID **prossId, size_t *size) {
...
  *prossId = (PROSSID *)malloc(sizeof(PROSSID)*vec.size());
  std::copy(vec.begin(), vec.end(), *prossId);
...
}

void ProssIdFromCwd(const char *cwd, PROSSID **prossId, size_t *size) {
...
  *prossId = (PROSSID *)malloc(sizeof(PROSSID)*vec.size());
  std::copy(vec.begin(), vec.end(), *prossId);
...
}
Although, since you're using C++, why not simply use the std::vector<> you have already populated as the means to get the data out and get rid manual memory management? Unless the purpose is for your functions to have a C API down the road.
Awesome! Thank you for the advice. The reason I am not using c++ std::string and std::vector for function arguments and return types is because this will be a cross-platform development library I was going to add to various package managers, and exporting library's functions with C++-specific types is a bad practice because calling the library with those types will only work with certain compilers as they are implementation defined, and will have varying ABI compatibility.

I can reuse all this same basic logic while writing it for other platform equivalents.

Edit: That fixed everything! Thanks!

C++:
/*

 MIT License
 
 Copyright © 2021 Samuel Venable
 Copyright © 2021 Lars Nilsson
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 
*/

#include <string>
#include <vector>
#include <algorithm>
#include <iostream>

#include <cstdlib>
#include <cstring>
#include <climits>
#include <cstdio>

#include <proc/readproc.h>
#include <signal.h>

using std::string;
using std::vector;
using std::to_string;
typedef pid_t PROSSID;

namespace {

string PathFromFile(string file) {
  size_t fp = file.find_last_of("/\\");
  return file.substr(0, fp);
}

string NameFromFile(string file) {
  size_t fp = file.find_last_of("/\\");
  return file.substr(fp + 1);
}

} // anonymous namespace

namespace CrossPross {

bool ProssIdExists(PROSSID prossId) {
  return (kill(prossId, 0) == 0);
}

bool ProssIdKill(PROSSID prossId) {
  return (kill(prossId, SIGKILL) == 0);
}

void ParentProssIdFromProssId(PROSSID prossId, PROSSID *parentProssId) {
  PROCTAB *proc = openproc(PROC_FILLSTATUS | PROC_PID, &prossId);
  if (proc_t *proc_info = readproc(proc, NULL)) { 
    *parentProssId = proc_info->ppid;
    freeproc(proc_info);
  }
  closeproc(proc);
}

void ProssIdFromParentProssId(PROSSID parentProssId, PROSSID **prossId, size_t *size) {
  vector<PROSSID> vec; size_t i = 0;
  PROCTAB *proc = openproc(PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS);
  while (proc_t *proc_info = readproc(proc, NULL)) {
    if (proc_info->ppid == parentProssId) {
      vec.push_back(proc_info->tgid); i++;
    }
    freeproc(proc_info);
  }
  *prossId = (PROSSID *)malloc(sizeof(PROSSID) * vec.size());
  std::copy(vec.begin(), vec.end(), *prossId);
  *size = i; closeproc(proc);
}

void ExeFromProssId(PROSSID prossId, char **buffer) {
  string symLink = string("/proc/") + to_string(prossId) + string("/exe");
  char exe[PATH_MAX]; realpath(symLink.c_str(), exe);
  *buffer = strdup(exe);
}

void ProssIdFromExe(const char *exe, PROSSID **prossId, size_t *size) {
  vector<PROSSID> vec; size_t i = 0;
  PROCTAB *proc = openproc(PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS);
  while (proc_t *proc_info = readproc(proc, NULL)) {
    char *buffer; ExeFromProssId(proc_info->tgid, &buffer);
    string str1 = exe ? : "";
    string str2 = buffer ? : "";
    free(buffer);
    if (str1 == str2) {
      vec.push_back(proc_info->tgid); i++;
    } else if (str1 == NameFromFile(str2)) {
      vec.push_back(proc_info->tgid); i++;
    } else if (str1 == PathFromFile(str2)) {
      vec.push_back(proc_info->tgid); i++;
    }
    freeproc(proc_info);
  }
  *prossId = (PROSSID *)malloc(sizeof(PROSSID) * vec.size());
  std::copy(vec.begin(), vec.end(), *prossId);
  *size = i; closeproc(proc);
}

void CwdFromProssId(PROSSID prossId, char **buffer) {
  string symLink = string("/proc/") + to_string(prossId) + string("/cwd");
  char cwd[PATH_MAX]; realpath(symLink.c_str(), cwd);
  *buffer = strdup(cwd);
}

void ProssIdFromCwd(const char *cwd, PROSSID **prossId, size_t *size) {
  vector<PROSSID> vec; size_t i = 0;
  PROCTAB *proc = openproc(PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS);
  while (proc_t *proc_info = readproc(proc, NULL)) {
    char *buffer; CwdFromProssId(proc_info->tgid, &buffer);
    string str1 = cwd ? : "";
    string str2 = buffer ? : "";
    free(buffer);
    if (str1 == str2) {
      vec.push_back(proc_info->tgid); i++;
    }
    freeproc(proc_info);
  }
  *prossId = (PROSSID *)malloc(sizeof(PROSSID) * vec.size());
  std::copy(vec.begin(), vec.end(), *prossId);
  *size = i; closeproc(proc);
}

void CmdlineFromProssId(PROSSID prossId, char ***buffer, size_t *size) {
  if (!ProssIdExists(prossId)) return;
  static vector<string> vec1; size_t i = 0;
  PROCTAB *proc = openproc(PROC_FILLCOM | PROC_PID, &prossId);
  if (proc_t *proc_info = readproc(proc, NULL)) {
    while (proc_info->cmdline[i] != NULL) {
      vec1.push_back(proc_info->cmdline[i]);
      i++;
    }
    freeproc(proc_info);
  }
  vector<char *> vec2;
  for (size_t i = 0; i <= vec1.size(); i++)
    vec2.push_back((char *)vec1[i].c_str());
  char **arr = new char *[vec2.size()]();
  std::copy(vec2.begin(), vec2.end(), arr);
  *buffer = arr; *size = i; closeproc(proc);
}

void EnvironFromProssId(PROSSID prossId, char ***buffer, size_t *size) {
  if (!ProssIdExists(prossId)) return;
  static vector<string> vec1; size_t i = 0;
  PROCTAB *proc = openproc(PROC_FILLENV | PROC_PID, &prossId);
  if (proc_t *proc_info = readproc(proc, NULL)) {
    while (proc_info->environ[i] != NULL) {
      vec1.push_back(proc_info->environ[i]);
      i++;
    }
    freeproc(proc_info);
  }
  vector<char *> vec2;
  for (size_t i = 0; i <= vec1.size(); i++)
    vec2.push_back((char *)vec1[i].c_str());
  char **arr = new char *[vec2.size()]();
  std::copy(vec2.begin(), vec2.end(), arr);
  *buffer = arr; *size = i; closeproc(proc);
}

} // namespace CrossPross

namespace CrossProssPrint {

void PrintWhetherPidExists(PROSSID prossId) {
  std::cout << CrossPross::ProssIdExists(prossId) << std::endl;
}

void PrintWhetherPidKilled(PROSSID prossId) {
  std::cout << CrossPross::ProssIdKill(prossId) << std::endl;
}

void PrintPpidFromPid(PROSSID prossId) {
  PROSSID parentProssId;
  CrossPross::ParentProssIdFromProssId(prossId, &parentProssId);
  std::cout << parentProssId << std::endl;
}

void PrintPidFromPpid(PROSSID parentProssId) {
  PROSSID *prossId; size_t size;
  CrossPross::ProssIdFromParentProssId(parentProssId, &prossId, &size);
  for (size_t i = 0; i < size; i++) {
    std::cout << prossId[i] << std::endl;
  }
  free(prossId);
}

void PrintExeFromPid(PROSSID prossId) {
  char *buffer;
  CrossPross::ExeFromProssId(prossId, &buffer);
  std::cout << buffer << std::endl;
  free(buffer);
}

void PrintPidFromExe(const char *exe) {
  PROSSID *prossId; size_t size;
  CrossPross::ProssIdFromExe(exe, &prossId, &size);
  for (size_t i = 0; i < size; i++) {
    std::cout << prossId[i] << std::endl;
  }
  free(prossId);
}

void PrintCwdFromPid(PROSSID prossId) {
  char *buffer;
  CrossPross::CwdFromProssId(prossId, &buffer);
  std::cout << buffer << std::endl;
  free(buffer);
}

void PrintPidFromCwd(const char *cwd) {
  PROSSID *prossId; size_t size;
  CrossPross::ProssIdFromCwd(cwd, &prossId, &size);
  for (size_t i = 0; i < size; i++) {
    std::cout << prossId[i] << std::endl;
  }
  free(prossId);
}

void PrintCmdFromPid(PROSSID prossId) {
  char **buffer; size_t size;
  CrossPross::CmdlineFromProssId(prossId, &buffer, &size);
  for (size_t i = 0; i < size; i++) {
    std::cout << buffer[i] << std::endl;
  }
  delete[] buffer;
}

void PrintEnvFromPid(PROSSID prossId) {
  char **buffer; size_t size;
  CrossPross::EnvironFromProssId(prossId, &buffer, &size);
  for (size_t i = 0; i < size; i++) {
    std::cout << buffer[i] << std::endl;
  }
  delete[] buffer;
}

} // namespace CrossProssPrint

int main(int argc, char **argv) {
  if (argc == 3) {
    PROSSID pid = 0; 
    char *exe = NULL, *cwd = NULL;
    if (strcmp(argv[2], "self") == 0) {
      pid = getpid(); 
      CrossPross::ExeFromProssId(pid, &exe);
      CrossPross::CwdFromProssId(pid, &cwd);
    } else pid = strtoul(argv[2], nullptr, 10);
    if (strcmp(argv[1], "--pid-exists") == 0) {
      CrossProssPrint::PrintWhetherPidExists(pid);
    } else if (strcmp(argv[1], "--pid-kill") == 0) {
      CrossProssPrint::PrintWhetherPidKilled(pid);
    } else if (strcmp(argv[1], "--ppid-from-pid") == 0) {
      CrossProssPrint::PrintPpidFromPid(pid);
    } else if (strcmp(argv[1], "--pid-from-ppid") == 0) {
      CrossProssPrint::PrintPidFromPpid(pid);
    } else if (strcmp(argv[1], "--exe-from-pid") == 0) {
      CrossProssPrint::PrintExeFromPid(pid);
    } else if (strcmp(argv[1], "--pid-from-exe") == 0) {
      CrossProssPrint::PrintPidFromExe(exe ? : argv[2]);
    } else if (strcmp(argv[1], "--cwd-from-pid") == 0) {
      CrossProssPrint::PrintCwdFromPid(pid);
    } else if (strcmp(argv[1], "--pid-from-cwd") == 0) {
      CrossProssPrint::PrintPidFromCwd(cwd ? : argv[2]);
    } else if (strcmp(argv[1], "--cmd-from-pid") == 0) {
      CrossProssPrint::PrintCmdFromPid(pid);
    } else if (strcmp(argv[1], "--env-from-pid") == 0) {
      CrossProssPrint::PrintEnvFromPid(pid);
    }
  }
  return 0;
}
 
Last edited:

GMWolf

aka fel666
C++-specific types is a bad practice because calling the library with those types will only work with certain compilers as they are implementation defined, and will have varying ABI compatibility.
Just have the libra user compile it from source . It's much less of a pain than linking to an already compiled lib. Even with a C abi it can be a huge pain, different compilation options can still lead to issues (like symbol visibility etc).

You can also wrap your c++ functions with a C abi.
 

Samuel Venable

Time Killer
Just have the libra user compile it from source . It's much less of a pain than linking to an already compiled lib. Even with a C abi it can be a huge pain, different compilation options can still lead to issues (like symbol visibility etc).

You can also wrap your c++ functions with a C abi.
I might consider that, but for now, I am just using the functions i wrote to be used in a quick CLI program, which now supports Windows, macOS, Linux, and FreeBSD; available on GitHub: https://github.com/time-killer-games/crosspross I'll worry about adding it to package managers after I figure out how to use AppVeyor, Azure, and Travis for CI tests.
 
Top