Skip to content

Commit

Permalink
Get rid of unsafe for procfs get methods
Browse files Browse the repository at this point in the history
  • Loading branch information
gwr committed Aug 10, 2024
1 parent 307f613 commit faec975
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices;

// The const int PRARGSZ show up as unused. Not sure why.
// C# equivalents for <sys/procfs.h> structures. See: struct lwpsinfo, struct psinfo.
// We read directly onto these from procfs, so the layouts and sizes of these structures
// must _exactly_ match those in <sys/procfs.h>

// analyzer incorrectly flags fixed buffer length const
// (https://github.com/dotnet/roslyn/issues/37593)
#pragma warning disable CA1823

internal static partial class Interop
Expand All @@ -28,6 +34,7 @@ internal struct @timestruc_t
}

// lwp ps(1) information file. /proc/<pid>/lwp/<lwpid>/lwpsinfo
// Equivalent to sys/procfs.h struct lwpsinfo
// "unsafe" because it has fixed sized arrays.
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct @lwpsinfo
Expand Down Expand Up @@ -56,8 +63,10 @@ internal unsafe struct @lwpsinfo
private int pr_lgrp; /* lwp home lgroup */
private fixed int pr_filler[4]; /* reserved for future use */
}
private const int PR_LWPSINFO_SIZE = 128; // for debug assertions

// process ps(1) information file. /proc/<pid>/psinfo
// Equivalent to sys/procfs.h struct psinfo
// "unsafe" because it has fixed sized arrays.
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct @psinfo
Expand Down Expand Up @@ -98,7 +107,12 @@ internal unsafe struct @psinfo
public int pr_contract; /* process contract */
private fixed int pr_filler[1]; /* reserved for future use */
public lwpsinfo pr_lwp; /* information for representative lwp */
// C# magic: Accessor method to get a Span for pr_psargs[]
// Does not affect the size or layout of this struct.
internal ReadOnlySpan<byte> PsArgsSpan =>
MemoryMarshal.CreateReadOnlySpan(ref pr_psargs[0], PRARGSZ);
}
private const int PR_PSINFO_SIZE = 416; // for debug assertions

// Ouput type for TryGetThreadInfoById()
internal struct ThreadInfo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.IO;
using System.Text;

internal static partial class Interop
{
Expand All @@ -23,8 +24,7 @@ internal static partial class @procfs
/// </returns>

// ProcessManager.SunOS.cs calls this
// "unsafe" due to use of fixed-size buffers
internal static unsafe bool TryGetProcessInfoById(int pid, out ProcessInfo result)
internal static bool TryGetProcessInfoById(int pid, out ProcessInfo result)
{
result = default;

Expand All @@ -34,7 +34,10 @@ internal static unsafe bool TryGetProcessInfoById(int pid, out ProcessInfo resul
using FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
psinfo pr;
Unsafe.SkipInit(out pr);
fs.ReadExactly(MemoryMarshal.AsBytes(new Span<psinfo>(ref pr)));
Span<byte> prspan = MemoryMarshal.AsBytes(new Span<psinfo>(ref pr));
Debug.Assert(prspan.Length == PR_PSINFO_SIZE,
$"psinfo struct size {prspan.Length} bytes not {PR_PSINFO_SIZE}.");
fs.ReadExactly(prspan);

result.Pid = pr.pr_pid;
result.ParentPid = pr.pr_ppid;
Expand All @@ -45,7 +48,12 @@ internal static unsafe bool TryGetProcessInfoById(int pid, out ProcessInfo resul
result.StartTime.TvNsec = pr.pr_start.tv_nsec;
result.CpuTotalTime.TvSec = pr.pr_time.tv_sec;
result.CpuTotalTime.TvNsec = pr.pr_time.tv_nsec;
result.Args = Marshal.PtrToStringUTF8((IntPtr)pr.pr_psargs);

// Get Args as a managed string, using accessor for pr_psargs[]
ReadOnlySpan<byte> argspan = pr.PsArgsSpan;
int argslen = argspan.IndexOf((byte)0);
argslen = (argslen >= 0) ? argslen : argspan.Length;
result.Args = Encoding.UTF8.GetString(argspan.Slice(0, argslen));

// A couple things from pr_lwp
result.Priority = pr.pr_lwp.pr_pri;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ internal static partial class @procfs
/// </returns>

// ProcessManager.SunOS.cs calls this
// "unsafe" due to use of fixed-size buffers
internal static unsafe bool TryGetThreadInfoById(int pid, int tid, out ThreadInfo result)
internal static bool TryGetThreadInfoById(int pid, int tid, out ThreadInfo result)
{
result = default;

Expand All @@ -35,7 +34,10 @@ internal static unsafe bool TryGetThreadInfoById(int pid, int tid, out ThreadInf
using FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
lwpsinfo pr;
Unsafe.SkipInit(out pr);
fs.ReadExactly(MemoryMarshal.AsBytes(new Span<lwpsinfo>(ref pr)));
Span<byte> prspan = MemoryMarshal.AsBytes(new Span<lwpsinfo>(ref pr));
Debug.Assert(prspan.Length == PR_LWPSINFO_SIZE,
$"psinfo struct size {prspan.Length} bytes not {PR_LWPSINFO_SIZE}.");
fs.ReadExactly(prspan);

result.Tid = pr.pr_lwpid;
result.Priority = pr.pr_pri;
Expand Down

0 comments on commit faec975

Please sign in to comment.