Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Fix parsing of procfs stat files when comm name contains spaces #12791

Merged
merged 1 commit into from
Oct 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 2 additions & 15 deletions src/Common/src/Interop/Linux/procfs/Interop.ProcFsStat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ internal static bool TryReadStatFile(int pid, int tid, out ParsedStat result, Re
return b;
}

private static bool TryParseStatFile(string statFilePath, out ParsedStat result, ReusableTextReader reusableReader)
internal static bool TryParseStatFile(string statFilePath, out ParsedStat result, ReusableTextReader reusableReader)
{
string statFileContents;
try
Expand All @@ -220,20 +220,7 @@ private static bool TryParseStatFile(string statFilePath, out ParsedStat result,
var results = default(ParsedStat);

results.pid = parser.ParseNextInt32();
results.comm = parser.ParseRaw(delegate (string str, ref int startIndex, ref int endIndex)
{
if (str[startIndex] == '(')
{
int i;
for (i = endIndex; i < str.Length && str[i - 1] != ')'; i++) ;
if (str[i - 1] == ')')
{
endIndex = i;
return str.Substring(startIndex + 1, i - startIndex - 2);
}
}
throw new InvalidDataException();
});
results.comm = parser.MoveAndExtractNextInOuterParens();
results.state = parser.ParseNextChar();
parser.MoveNextOrFail(); // ppid
parser.MoveNextOrFail(); // pgrp
Expand Down
31 changes: 31 additions & 0 deletions src/Common/src/System/IO/StringParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,37 @@ public string MoveAndExtractNext()
return _buffer.Substring(_startIndex, _endIndex - _startIndex);
}

/// <summary>
/// Moves to the next component of the string, which must be enclosed in the only set of top-level parentheses
/// in the string. The extracted value will be everything between (not including) those parentheses.
/// </summary>
/// <returns></returns>
public string MoveAndExtractNextInOuterParens()
{
// Move to the next position
MoveNextOrFail();

// After doing so, we should be sitting at a the opening paren.
if (_buffer[_startIndex] != '(')
{
ThrowForInvalidData();
}

// Since we only allow for one top-level set of parentheses, find the last
// parenthesis in the string; it's paired with the opening one we just found.
int lastParen = _buffer.LastIndexOf(')');
if (lastParen == -1 || lastParen < _startIndex)
{
ThrowForInvalidData();
}

// Extract the contents of the parens, then move our ending position to be after the paren
string result = _buffer.Substring(_startIndex + 1, lastParen - _startIndex - 1);
_endIndex = lastParen + 1;

return result;
}

/// <summary>
/// Gets the current subcomponent of the string as a string.
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions src/Common/tests/Common.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\src\Interop\Linux\procfs\Interop.ProcFsStat.cs">
<Link>Common\Interop\Linux\procfs\Interop.ProcFsStat.cs</Link>
</Compile>
<Compile Include="..\src\System\CharArrayHelpers.cs">
<Link>Common\System\CharArrayHelpers.cs</Link>
</Compile>
Expand Down Expand Up @@ -58,9 +61,13 @@
<Compile Include="..\src\System\Net\HttpKnownHeaderNames.TryGetHeaderName.cs">
<Link>Common\System\Net\HttpKnownHeaderNames.TryGetHeaderName.cs</Link>
</Compile>
<Compile Include="..\src\System\Text\ReusableTextReader.cs">
<Link>Common\System\Text\ReusableTextReader.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)\System\AssertExtensions.cs">
<Link>CommonTest\System\AssertExtensions.cs</Link>
</Compile>
<Compile Include="Tests\Interop\procfsTests.cs" />
<Compile Include="Tests\System\CharArrayHelpersTests.cs" />
<Compile Include="Tests\System\StringExtensions.Tests.cs" />
<Compile Include="Tests\System\Collections\Generic\ArrayBuilderTests.cs" />
Expand Down
66 changes: 66 additions & 0 deletions src/Common/tests/Tests/Interop/procfsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.IO;
using System.Text;
using Xunit;

namespace Common.Tests
{
public class procfsTests
{
[Theory]
[InlineData("1 (systemd) S 0 1 1 0 -1 4194560 11536 2160404 55 593 70 169 4213 1622 20 0 1 0 4 189767680 1491 18446744073709551615 1 1 0 0 0 0 671173123 4096 1260 0 0 0 17 4 0 0 25 0 0 0 0 0 0 0 0 0 0", 1, "systemd", 'S', 1, 70, 169, 0, 4, 189767680, 1491, 18446744073709551615)]
[InlineData("5955 (dotnet with space) S 1806 5955 5955 34823 5955 4194304 1426 5872 0 3 16 3 16 4 20 0 1 0 674762 32677888 1447 18446744073709551615 4194304 5192652 140725672538992 140725672534152 140236068968880 0 0 3670020 1266777851 1 0 0 17 4 0 0 0 0 0 7290352 7326856 21204992 140725672540419 140725672540424 140725672540424 140725672542190 0", 5955, "dotnet with space", 'S', 5955, 16, 3, 0, 674762, 32677888, 1447, 18446744073709551615)]
[InlineData("5955 (bash) S 1806 5955 5955 34823 5955 4194304 1426 5872 0 3 16 3 16 4 20 0 1 0 674762 32677888 1447 18446744073709551615 4194304 5192652 140725672538992 140725672534152 140236068968880 0 0 3670020 1266777851 1 0 0 17 4 0 0 0 0 0 7290352 7326856 21204992 140725672540419 140725672540424 140725672540424 140725672542190 0", 5955, "bash", 'S', 5955, 16, 3, 0, 674762, 32677888, 1447, 18446744073709551615)]
[InlineData("22831 (dotnet) S 22708 22613 1811 34822 22613 4194304 215237 0 0 0 6491 4634 0 0 20 0 18 0 6054850 3672928256 23593 18446744073709551615 4194304 4294944 140729667338512 140729667328848 139709719439277 0 4 4096 17630 0 0 0 17 4 0 0 0 0 0 6392096 6393592 15552512 140729667342465 140729667342553 140729667342553 140729667346408 0", 22831, "dotnet", 'S', 1811, 6491, 4634, 0, 6054850, 3672928256, 23593, 18446744073709551615)]
[InlineData("22719 (fsnotifier64) S 22671 22613 1811 34822 22613 4194304 135 0 0 0 28 541 0 0 20 0 1 0 6052788 4882432 498 18446744073709551615 4194304 4212092 140731745592928 140731745592312 139627376925939 0 4 4096 0 1 0 0 17 3 0 0 0 0 0 6311936 6312884 25800704 140731745595967 140731745596016 140731745596016 140731745599431 0", 22719, "fsnotifier64", 'S', 1811, 28, 541, 0, 6052788, 4882432, 498, 18446744073709551615)]
[InlineData("1512 (at-spi-bus-laun) S 1163 1295 1295 0 -1 4194304 377 0 1 0 0 0 0 0 20 0 4 0 967 345894912 1453 18446744073709551615 4194304 4210132 140732353904128 140732353903600 139935649062541 0 0 4096 81920 0 0 0 17 5 0 0 0 0 0 6310768 6311952 8675328 140732353906996 140732353907038 140732353907038 140732353908686 0", 1512, "at-spi-bus-laun", 'S', 1295, 0, 0, 0, 967, 345894912, 1453, 18446744073709551615)]
[InlineData("15 (kworker/1:0H) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 4 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0", 15, "kworker/1:0H", 'S', 0, 0, 0, -20, 4, 0, 0, 18446744073709551615)]
[InlineData("1369 (sh) S 1163 1369 1369 0 -1 4194304 240 1291 0 0 0 0 0 0 20 0 1 0 902 4616192 419 18446744073709551615 93922724966400 93922725110300 140735239002352 140735239000952 140586773169914 0 0 0 65538 1 0 0 17 4 0 0 0 0 0 93922727210856 93922727215648 93922759745536 140735239006661 140735239006720 140735239006720 140735239008240 0", 1369, "sh", 'S', 1369, 0, 0, 0, 902, 4616192, 419, 18446744073709551615)]
[InlineData("1295 (dbus-daemon) S 1163 1295 1295 0 -1 4194368 1909 460 0 0 21 35 0 0 20 0 1 0 794 44421120 987 18446744073709551615 94692716101632 94692716315676 140720853604656 140720853602536 140124915441971 0 0 0 16385 1 0 0 17 5 0 0 0 0 0 94692718415176 94692718420816 94692735217664 140720853613214 140720853613288 140720853613288 140720853614563 0", 1295, "dbus-daemon", 'S', 1295, 21, 35, 0, 794, 44421120, 987, 18446744073709551615)]
[InlineData("1291 (upstart-udev-br) S 1163 1290 1290 0 -1 4194368 59 0 0 0 0 0 0 0 20 0 1 0 792 41316352 71 18446744073709551615 94876928040960 94876928122852 140734109368976 140734109368152 140299085954291 0 0 1 81920 1 0 0 17 4 0 0 0 0 0 94876930220584 94876930224400 94876938022912 140734109371165 140734109371201 140734109371201 140734109372382 0", 1291, "upstart-udev-br", 'S', 1290, 0, 0, 0, 792, 41316352, 71, 18446744073709551615)]
[InlineData("123 (deferwq) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 90 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 5 0 0 0 0 0 0 0 0 0 0 0 0 0", 123, "deferwq", 'S', 0, 0, 0, -20, 90, 0, 0, 18446744073709551615)]
[InlineData("1160 ((sd-pam)) S 1158 1158 1158 0 -1 1077936448 28 0 0 0 0 0 0 0 20 0 1 0 758 64921600 510 18446744073709551615 1 1 0 0 0 0 0 4096 0 0 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0", 1160, "(sd-pam)", 'S', 1158, 0, 0, 0, 758, 64921600, 510, 18446744073709551615)]
[InlineData("11 (watchdog/1) S 2 0 0 0 -1 69239104 0 0 0 0 0 324 0 0 -100 0 1 0 4 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 1 99 1 0 0 0 0 0 0 0 0 0 0 0", 11, "watchdog/1", 'S', 0, 0, 324, 0, 4, 0, 0, 18446744073709551615)]
[InlineData("109 (ipv6_addrconf) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 89 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0", 109, "ipv6_addrconf", 'S', 0, 0, 0, -20, 89, 0, 0, 18446744073709551615)]
[InlineData("102 (scsi_tmf_0) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 83 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0", 102, "scsi_tmf_0", 'S', 0, 0, 0, -20, 83, 0, 0, 18446744073709551615)]
[InlineData("10 (watchdog/0) S 2 0 0 0 -1 69239104 0 0 0 0 0 243 0 0 -100 0 1 0 4 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 0 99 1 0 0 0 0 0 0 0 0 0 0 0", 10, "watchdog/0", 'S', 0, 0, 243, 0, 4, 0, 0, 18446744073709551615)]
[InlineData("5955 (dotnet (nested) space) S 1806 5955 5955 34823 5955 4194304 1426 5872 0 3 16 3 16 4 20 0 1 0 674762 32677888 1447 18446744073709551615 4194304 5192652 140725672538992 140725672534152 140236068968880 0 0 3670020 1266777851 1 0 0 17 4 0 0 0 0 0 7290352 7326856 21204992 140725672540419 140725672540424 140725672540424 140725672542190 0", 5955, "dotnet (nested) space", 'S', 5955, 16, 3, 0, 674762, 32677888, 1447, 18446744073709551615)]
[InlineData("5955 (dotnet (with (parens)) sp(a)ce) S 1806 5955 5955 34823 5955 4194304 1426 5872 0 3 16 3 16 4 20 0 1 0 674762 32677888 1447 18446744073709551615 4194304 5192652 140725672538992 140725672534152 140236068968880 0 0 3670020 1266777851 1 0 0 17 4 0 0 0 0 0 7290352 7326856 21204992 140725672540419 140725672540424 140725672540424 140725672542190 0", 5955, "dotnet (with (parens)) sp(a)ce", 'S', 5955, 16, 3, 0, 674762, 32677888, 1447, 18446744073709551615)]
[InlineData("5955 (executable-(name)) S 1806 5955 5955 34823 5955 4194304 1426 5872 0 3 16 3 16 4 20 0 1 0 674762 32677888 1447 18446744073709551615 4194304 5192652 140725672538992 140725672534152 140236068968880 0 0 3670020 1266777851 1 0 0 17 4 0 0 0 0 0 7290352 7326856 21204992 140725672540419 140725672540424 140725672540424 140725672542190 0", 5955, "executable-(name)", 'S', 5955, 16, 3, 0, 674762, 32677888, 1447, 18446744073709551615)]
[InlineData("5955 (a)))b) S 1806 5955 5955 34823 5955 4194304 1426 5872 0 3 16 3 16 4 20 0 1 0 674762 32677888 1447 18446744073709551615 4194304 5192652 140725672538992 140725672534152 140236068968880 0 0 3670020 1266777851 1 0 0 17 4 0 0 0 0 0 7290352 7326856 21204992 140725672540419 140725672540424 140725672540424 140725672542190 0", 5955, "a)))b", 'S', 5955, 16, 3, 0, 674762, 32677888, 1447, 18446744073709551615)]
[InlineData("5955 (a(((b) S 1806 5955 5955 34823 5955 4194304 1426 5872 0 3 16 3 16 4 20 0 1 0 674762 32677888 1447 18446744073709551615 4194304 5192652 140725672538992 140725672534152 140236068968880 0 0 3670020 1266777851 1 0 0 17 4 0 0 0 0 0 7290352 7326856 21204992 140725672540419 140725672540424 140725672540424 140725672542190 0", 5955, "a(((b", 'S', 5955, 16, 3, 0, 674762, 32677888, 1447, 18446744073709551615)]
[InlineData("5955 (a)( ) b (() () S 1806 5955 5955 34823 5955 4194304 1426 5872 0 3 16 3 16 4 20 0 1 0 674762 32677888 1447 18446744073709551615 4194304 5192652 140725672538992 140725672534152 140236068968880 0 0 3670020 1266777851 1 0 0 17 4 0 0 0 0 0 7290352 7326856 21204992 140725672540419 140725672540424 140725672540424 140725672542190 0", 5955, "a)( ) b (() (", 'S', 5955, 16, 3, 0, 674762, 32677888, 1447, 18446744073709551615)]
[InlineData("5955 (has\\backslash) S 1806 5955 5955 34823 5955 4194304 1426 5872 0 3 16 3 16 4 20 0 1 0 674762 32677888 1447 18446744073709551615 4194304 5192652 140725672538992 140725672534152 140236068968880 0 0 3670020 1266777851 1 0 0 17 4 0 0 0 0 0 7290352 7326856 21204992 140725672540419 140725672540424 140725672540424 140725672542190 0", 5955, "has\\backslash", 'S', 5955, 16, 3, 0, 674762, 32677888, 1447, 18446744073709551615)]
public static void ParseValidStatFiles_Success(
string statFileText,
int expectedPid, string expectedComm, char expectedState, int expectedSession,
ulong expectedUtime, ulong expectedStime, long expectedNice, ulong expectedStarttime,
ulong expectedVsize, long expectedRss, ulong expectedRsslim)
{
string path = Path.GetTempFileName();
try
{
File.WriteAllText(path, statFileText);

Interop.procfs.ParsedStat result;
Assert.True(Interop.procfs.TryParseStatFile(path, out result, new ReusableTextReader()));

Assert.Equal(expectedPid, result.pid);
Assert.Equal(expectedComm, result.comm);
Assert.Equal(expectedState, result.state);
Assert.Equal(expectedSession, result.session);
Assert.Equal(expectedUtime, result.utime);
Assert.Equal(expectedStime, result.stime);
Assert.Equal(expectedNice, result.nice);
Assert.Equal(expectedStarttime, result.starttime);
Assert.Equal(expectedVsize, result.vsize);
Assert.Equal(expectedRss, result.rss);
Assert.Equal(expectedRsslim, result.rsslim);
}
finally { File.Delete(path); }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public static IPEndPoint[] ParseActiveUdpListenersFromFiles(string udp4File, str
// Parsing logic for local and remote addresses and ports, as well as socket state.
internal static TcpConnectionInformation ParseTcpConnectionInformationFromLine(string line)
{
StringParser parser = new StringParser(line, ' ', true);
StringParser parser = new StringParser(line, ' ', skipEmpty: true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also just switch the optional parameters in the overload (make the new one last). Up to you.

parser.MoveNextOrFail(); // skip Index

string localAddressAndPort = parser.MoveAndExtractNext(); // local_address
Expand All @@ -163,7 +163,7 @@ internal static TcpConnectionInformation ParseTcpConnectionInformationFromLine(s
// Common parsing logic for the local connection information.
private static IPEndPoint ParseLocalConnectionInformation(string line)
{
StringParser parser = new StringParser(line, ' ', true);
StringParser parser = new StringParser(line, ' ', skipEmpty: true);
parser.MoveNextOrFail(); // skip Index

string localAddressAndPort = parser.MoveAndExtractNext();
Expand Down