|
Pin
|
This section lists changes in behavior of Pin CRT APIs from the standard API documentation as listed in the Linux man pages.
Pin CRT is based on Musl and is ISO C and POSIX compliant, it provides standard POSIX API on both Linux & Windows. However, certain modification were required to make the CRT cross platform and to preserve some isolation requirements of Pin.
Pin CRT implements all the functionality required to support C++17 STL as well as some system level APIs, however it does not implement all the APIs provided by Musl. In deciding which APIs to support we followed these guidelines:
In Musl off_t is always 64-bit even on 32-bit. By default explicit 64-bit function names are disabled and the regular names can be used. If however, code uses explicit 64-bit names, then the following preprocessor macro should be defined _LARGEFILE64_SOURCE. Using this macro will enable names like mmap64, stat64 etc. These new names are just macro definitions. In practice mmap64 is the same as mmap, stat64 is the same as stat and so forth for all 64-bit special names.
Pin Runtime Library (PinRT) tries to maintain resource isolation between Pin/Pintools and the instrumented application. This is done at the PINOS level, however it affects the CRT behavior. The following general rules apply to all CRT APIs:
long data type structure members, function arguments and return values are replaced with _arch_long which is defined to be 32-bit long when compiling 32-bit Pintools and 64-bit long when compiling 64-bit Pintools on both Linux and Windows.long and unsigned long in limits.h (e.g LONG_MIN, LONG_MAX, ULONG_MAX) are changed to to match the limits for _arch_long.Pin CRT file creation and manipulation functions use a separate set of descriptors than the instrumented application. Trying to manipulate a file descriptor opened by the instrumented application will either fail or manipulate some other Pin or Pintool file, but not the one intended. Instrumented applications may be able to manipulate files opened by Pin or Pintools, this caveat shall be addressed in a future release.
Pin CRT has an underlying assumption that file descriptors 0, 1 and 2 of the instrumented application always belong to STDIN, STDOUT and STDERR when the application starts. This may not be true under follow execv scenarios where the parent closes those file descriptors before calling execv. In such cases results of running Pin may be undefined. Pin may either assert or it may end-up reading or writing from the wrong files when trying to read or write to STDIN, STDOUT or STDERR. An application closing STDIN, STDOUT or STDERR after Pin is attached and running will not affect Pin or the Pintool as PINOS duplicates the handles to STDIN, STDOUT and STDERR for Pin usage.
PINOS maintans CWD isolation: Any changes the instrumented application makes to the CWD do not affect Pin and Pintools. Any changes to CWD made by Pin or the Pintool also do not affect the instrumented application. All APIs that use relative paths are affected by this behavior.
Pin CRT thread Ids are not the same as the system thread Id. Trying to use a system thread Id with Pin CRT may fail and is not guranteed to work. The instrumented application is able to enumerate Pin and Pintool internal threads and is able to affect them. Pin Runtime Library (PinRT) maintains a TLS for each thread. Accessing the TLS by Pin CRT APIs does not modify the instrumented application TLS for that same thread. The application cannot modify Pin RT TLS.
Unmodified Musl uses 64-bit time functions also for 32-bit applications. Pin CRT modifies this behavior and uses 64-bit time functions for 64-bit Pintools and 32-bit time functions for 32-bit Pintools. This change affects all interfaces and all time related types and data structures. This means that current Pin CRT implementation is susceptible to the 2038 bug (EPOCH wraparound) for 32-bit Pintools because time_t is 32-bit. Using standard CRT types should allow writing cross-architecture code without worrying about this (at least fro the near future).
Pin CRT does not support setting any of the different user or group ids. All APIs that try to set any user or group id will fail, return -1 and set errno to ENOSYS. APIs that try to get user or group ids are supported only for Linux.
chdir() and fchdir() only change the current workign directory for Pin and Pintools and does not affect the instrumented application. getcwd() and get_current_dir_name() return Pin's CWD and not the instrumented application CWD.
clone() is not supported and if called will return -1 and set errno to ENOSYS.
All file descriptors opened by Pin or the Pintools will be closed on execve family of functions. This behavior affects all CRT functions that use execve for their implementation like system(), popen and posix_spawn(). For a file descriptor to survive execve the O_HONOR_CLOEXEC flag should be used. This flag is supported for dup3, pipe2, open and openat.
Passing AT_EACCESS in flags will result in an error and errno will be set to EBUSY.
getpriority and setpriority only support the mode PRIO_PROCESS with argument 0 which is the calling thread.
Trying to set the priority of an application thread will fail and errno will be set to EACCESS.
getrlimit() behavior is not modified by Pin CRT. It will return values for the instrumented process regardless of any limitations Pin may have as a result of KNOBs or API calls.
The thread Id returned by gettid() is not the same as the native O/S thread Id. This thread Id is the thread Id used by PINOS to keep track of threads.
Pin shares memory with the instrumented application but maintains isolation at the memory management level. This means that Pin and Pintools cannot unmap nor change protection of instrumented application memory and the same is true for the instrumented application. Trying to use munmap() to unmap a memory range that contains memory regions that are marked as application memory will silently skip these memory regions and unmap just the memory regions that are marked as Pin regions.
By default mmap() will fail if trying to modify a memory region that is marked as an application region by using the MAP_FIXED flag. This protection can be disabled by passing the Pin CRT specific PROT_DIS_APP_ISOL protection flag.
mmap() does not support the MAP_FIXED flag for Pin regions unless the memory region is marked with the Pin CRT specific protection flag PROT_ALLOW_REMAP. It is possible to force MAP_FIXED on a memory region not marked with PROT_ALLOW_REMAP by passing PROT_ALLOW_REMAP as part of the protection flags when calling mmap(). Please note that when using MAP_FIXED on a memory region that is not mapped, mmap() will fail.
Pin CRT's mmap() implementation cannot properly isolate memory regions allocated with MAP_GROWSDOWN or MAP_GROWSUP. The usage of these flags is strongly discouraged.
Pin shares memory with the instrumented application but maintains isolation at the memory management level. This means that Pin and Pintools cannot change protection of instrumented application memory and the same is true for the instrumented application. Trying to use mprotect() to change the protection of a range that contains memory regions that are marked as application memory will fail and errno will be set to ENOMEM. This check can be disabled by passing the Pin CRT specific PROT_DIS_APP_ISOL protection flag. Passing the flag will allow mprotect() to change the protection of application memory regions. This flag affects only the specific mprotect() call and does not change the overall behavior of Pin's memory isolation.
Marking a memory region with one of the protection flags PROT_GROWSDOWN or PROT_GROWSUP may break Pin's memory isolation. The usage of these flags is strongly discouraged.
All file handles created by Pin CRT will be created with the O_CLOEXEC flag set regardless of whether the flag can actually be specified for the API. This is true for all file creation APIs including but not limited to, open(), openat(), dup(), dup2(), dup3, pipe(), pipe2() and socket(). The above is true for all CRT functions supported by Pin CRT that return a file descriptor even if not listed here. This behavior affects process creation APIs see PINCRT_PROC section below. The O_HONOR_CLOEXEC flag is supported for dup3, pipe2, open and openat. Passing this flag will change the behavior of these functions such that the presence (or absence) of O_CLOEXEC will be honored.
posix_spawn() is partially supported: Some file_actions FDOP_CHDIR and FDOP_FCHDIR are not supported. On Windows only the STDIO files may be duplicated or opened.
pthread_attr_setinheritsched() will return an error if called with inherit value other than 0.
Calling pthread_cancel() will mark the thread for cancelation but will always behave as if the cancelation type is PTHREAD_CANCEL_DEFERRED. See pthread_setcanceltype().
pthread_create() will fail if the scheduling inherit value in the thread creation attributes is not 0. See pthread_attr_setinheritsched().
pthread_mutexattr_setprotocol() will return ENOTSUP if called with protocol PTHREAD_PRIO_INHERIT.
PTHREAD_CANCEL_ASYNCHRONOUS is not supported. When passing PTHREAD_CANCEL_ASYNCHRONOUS if cancel was already requested using pthread_cancel() for the current thread then the thread will terminate, however, future calls to pthread_cancel() will not cause an asynchronous cancelation of the thread.
pthread_setschedprio() will fail with EPERM.
setrlimit() behavior is not modified by Pin CRT. Using it will affect the instrumented application and may change its behavior in unexpected ways. Pintool writers are discouraged from using this API.
The syscall() API cannot be used to call native O/S syscalls. All syscalls issued through the syscall() API will result in accessing the underlying O/S abstraction layer and may not behave as expected. For more information see Pin Runtime Direct Syscall Interface.
Pin and Pintools changes to the umask do not affect the instrumented application. The opposite is not correct. Instrumented application changes to umask will affect Pin and Pintools. Changing the umask for Pin/Pintools will survive fork but will not survive execve. This means that after execve the umask for Pin and Pintools will be the same as for the instrumented application after execve.
vfork() is implemented using fork(). This is allowed according to the standard but it means that the child cannot assume that it shares the stack with the parent, and the parent is blocked by vfork() until the child either exits or calls execv.
Pin Runtime Library (PinRT) tries to provide the exact same functionality on both Linux and Windows, using PINOS, Pin's O/S abstraction layer. However, not all CRT APIs implemented on Linux can be implemented to provide the exact same functionality on Windows.
The following API changes are applicable to Windows:
Pin CRT on Windows does not support user and group Ids on Windows. Any API that uses user or group Ids will return -1 and set errno to ENOSYS.
Pin CRT on Windows does not support signals. Any API that uses signals will return -1 and set errno to ENOSYS.
chmod() is not supported on Windows. The function will return -1 and errno will be set to ENOSYS.
chown() is not supported on Windows. The function will return -1 and errno will be set to ENOSYS.
The only value supported for flags by accept() is 0.
The following clocks are fully supported:
CLOCK_REALTIME CLOCK_MONOTONIC CLOCK_PROCESS_CPUTIME_ID CLOCK_THREAD_CPUTIME_ID CLOCK_REALTIME_COARSE CLOCK_MONOTONIC_COARSE
The following clock is supported with reduced semantics:
CLOCK_BOOTTIME - Does not take into account suspend time and is equivalent to CLOCK_MONOTONIC_COARSE
The following clocks are not supported:
CLOCK_MONOTONIC_RAW CLOCK_REALTIME_ALARM CLOCK_BOOTTIME_ALARM CLOCK_SGI_CYCLE CLOCK_TAI
Dynamic clocks are not supported.
The following clocks are fully supported:
CLOCK_REALTIME CLOCK_MONOTONIC CLOCK_BOOTIME CLOCK_PROCESS_CPUTIME_ID
CLOCK_TAI is not supported.
Absolute time sleeping is only supported for CLOCK_REALTIME and CLOCK_PROCESS_CPUTIME_ID.
The current implementation is non-alertable so it will never exit with errno set to EINTR.
Only CLOCK_REALTIME is supported.
On Windows calling any of the exec familly of functions will not exit the calling process. It will however exit the calling thread. Processes created using exec familly of functions must be waited upon using wait() / waitpid() / wait4(). Since on Windows the thread Id form which exec was called is not the same as the process Id for the new process, it is not possible to properly wait on a process that was created directly using the exec familly of functions. So on Windows the only way to properly create a process and get a process Id that can be used to wait for it using wait() / waitpid() / wait4() is by creating the process using posix_spawn().
On Windows the result of calling faccessat will be for the effective access rights as if AT_EACCESS flag was specified. (Passing the AT_EACCESS flag is not supported. See ())
0 (the default) and only growing a file.EACCESS instead of EBADF.fork() is not supported on Windows.
Current Windows implementation has the following limitations:
EINVAL.These behavior changes also affect readdir
getpeername() is not supported on Windows.
This function always return the pid of the process that created the calling process even if this parent process has already exited.
getrlimit() is not supported on Windows. The function will return -1 and errno will be set to ENOSYS.
getsockopt() is currently not supported on Windows. The function will return -1 and errno will be set to ENOSYS.
Trying to create a hard link to a directory symbolic link will fail because a directory symbolic link is actually also a directory.
kill() is not supported on Windows.
lseek() on Windows does not support SEEK_DATA and SEEK_HOLE values for whence.
mkfifo() is supported on Windows. However both sides should use PinCRT to be able to communicate over the named FIFO.
mknod() is supported on Windows. However only nodes of type S_IFIFO or S_IFREG may be created using this function. FIFOs can only be used for communicating with another program using PinCRT. See mkfifo().
If the address passed to munmap() is the allocation base of a region and the size is 0, then the entire allocated region will be released. Pintool developers are discouraged from using this behavior but rather pass to munmap the address that was returned from mmap() and the size used for the allocation when calling mmap().
mmap() supports the following Pin CRT Windows specific protection flags which can be used when mapping memory:
WIN_PROT_RESERVE: Reserves memory without commiting it. The returned address will be aligned to Windows allocation granularity (Usually 64 KB).WIN_PROT_COMMIT: Commit a memory region (or part of it) that was previously allocated using WIN_PROT_RESERVE.If using mmap to map a file then the offset argument must be a multiplication of the allocation granularity (Usually 64 KB).
The mode argument is ignored and the file is created with the permissions of the calling user on the target directory. If a file is opened for write then PINOS will also add the DELETE Windows permission to match POSIX semantics.
poll() is supported only for sockets. Only POLLIN, POLLOUT & POLLPRI are supported. POLLPRI works only for OOB data.
ppoll() is supported work only for sockets. Only POLLIN, POLLOUT & POLLPRI are supported. POLLPRI works only for OOB data. sigmask is ignored.
pthread_kill() is not supported on Windows.
raise() is not supported on Windows.
read() is not supported for sockets.
See getdents().
Although the buffer size is passed in size_t, the underlying implementation will convert it to int.
recvmsg() is not supported on Windows.
Although the buffer size is passed in size_t, the underlying implementation will convert it to int.
These functions will fail if a file with the same name exists and is either a directory, a readonly file, or a currently executing file.
Setting a priority that is less that 0 may fail if the calling process does not have enough privilleges.
setsockopt() supports options supported by winsock2 for INET TCP Stream sockets.
Although the buffer size is passed in size_t, the underlying implementation will convert it to int.
sendmesg() is not supported on Windows.
Although the buffer size is passed in size_t, the underlying implementation will convert it to int.
setrlimit() is not supported on Windows. The function will return -1 and errno will be set to ENOSYS.
sockatmark() is not supported on Windows.
Creating and using sockets is supported on Windows. However the following limitations apply:
socketpair() is not supported on Windows.
These functions only support directories, regular files and symlinks ( S_IFDIR, S_IFREG, S_IFLINK ). If called on other file types the functions will fail and errno will be set to EBADF. The fields st_uid and st_gid of the stat structure are always set to 0. The st_dev field represents the drive letter with value of 0 corresponding to A:, 1 to B: etc. Unfortunately there is no good way to reconcile Windows file permissions with Linux file permissions, for that reason the mode field of the stat structure is filled using the same convention used in Microsoft UCRT implementation:
FILE_ATTRIBUTE_READONLY the mode will be readonly for all UGO. If it doesn't it will be RW for ALL UGO. The permission refereed in the file attributes pertain to the permissions that the calling user has on the file - they don't reflect the actual permissions of owner, groups or others.Pin's implementation supports creating NTFS symbolic links using reparse points. On Windows users must have the Create symbolic link permission to successfully create a symbolic link. If the symbolic link target is a directory then the directory must exist. If the directory does not exist then the symbolic link will be created as a regular file symbolic link. This is because on Windows directory symbolic links are actually directories themselves.
This function has no effect on Windows.
Modification time and status change time as reflected by the st_mtim and st_ctim members ot the stat structure are not updated by this call.
umask() on Windows will have no effect on the actual permission with which a file or a directory are created.
vfork() is not supported on Windows.
Any process created using any of the exec familly of functions (see execve() / execveat() / exec() / fexecve()) must be waited upon using either wait(), waitpid() or wait4() functions. On Linux unwaited processes will become zombies. In Windows Pin CRT's implementation the processes will not become zombies but certain resources used for tracking these processes will not be released.
For waitpid() and wait4() the following changes and restrictions apply:
< -1: The only accepted value is the negative value of the current process Id.-1 or 0: Wait for any child process created using the exec familly of functions.> 0: Wait for the process given with pid iff it was created using the exec familly of functions.0 and WNOHANG are supportedFor wait4() the rusage argument may not be NULL.
All these wait APIs will only wait for process termination. They will not wake-up for any other status changes.
write() is not supported for sockets.
In Pin Runtime Library (PinRT) all system calls issued by the CRT are routed through PINOS. Pin's O/S abstraction layer. When calling the syscall() interface, the request is handled by PINOS, preventing direct access to the underlying system. However, sometimes it is essential to call a native O/S syscall. This should be done only if no other option is available because it will break isolation with the instrumented application and may have adverse effect on both the Pin/Pintool and the instrumented application. If such a system call is required, Pin provides an API OS_Syscall_unsafe for that purpose. Using this API it is possible to call directly a native O/S syscall. When calling native O/S APIs make sure to follow these guidelines:
FS or GS registers (Doing this will break both Pin and the application)