tag:blogger.com,1999:blog-72393892523151074332024-03-05T03:47:02.721-08:00Zone of Ambiguityligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.comBlogger36125tag:blogger.com,1999:blog-7239389252315107433.post-54934033510436522272022-11-23T09:45:00.001-08:002022-11-23T10:02:55.773-08:00ImageMagick sandboxing issue<p>And you know what? Of course I introduced a bug while implementing sandboxing feature for <a href="https://www.fancy-viewer.com/" target="_blank">Fancy Viewer</a>: the support of some raw images was broken from 1.0.2.10 till 1.0.2.13, because of Image Magick requires the use of a filesystem to load these raw images (actually their codecs just doesn't support Blobs).</p><p>The root cause of the bug is that Low Integrity application obviously can't access any general-purpose temporary folder; there are some folders that Image Magick knows about, and FOLDERID_LocalAppDataLow is not in the list:</p>
<pre> <code id="htmlViewer" style="background-color: #f0f0f0; background: rgb(240, 240, 240); color: #444444; display: block; font-weight: 400; padding: 0.5em;"><span style="background: none; color: #888888; font-weight: 400;">// ImageMagick-Windows\ImageMagick\MagickCore\resource.c</span>
MagickExport MagickBooleanType GetPathTemplate(char *path)
{
</code><code id="htmlViewer" style="background-color: #f0f0f0; background: rgb(240, 240, 240); color: #444444; display: block; font-weight: 400; padding: 0.5em;">.............</code><code id="htmlViewer" style="background-color: #f0f0f0; background: rgb(240, 240, 240); color: #444444; display: block; font-weight: 400; padding: 0.5em;"> (<span style="background: none; color: #444444; font-weight: 700;">void</span>) FormatLocaleString(path,MagickPathExtent,<span style="background: none; color: #880000; font-weight: 400;">"magick-"</span> MagickPathTemplate);
<span style="background: none; color: #397300; font-weight: 400;">exception</span>=AcquireExceptionInfo();
<span style="background: none; color: #397300; font-weight: 400;">directory</span>=(char *) GetImageRegistry(StringRegistryType,<span style="background: none; color: #880000; font-weight: 400;">"temporary-path"</span>,
<span style="background: none; color: #397300; font-weight: 400;">exception</span>);
<span style="background: none; color: #397300; font-weight: 400;">exception</span>=DestroyExceptionInfo(<span style="background: none; color: #397300; font-weight: 400;">exception</span>);
<span style="background: none; color: #444444; font-weight: 700;">if</span> (<span style="background: none; color: #397300; font-weight: 400;">directory</span> == (char *) <span style="background: none; color: #78a960; font-weight: 400;">NULL</span>)
<span style="background: none; color: #397300; font-weight: 400;">directory</span>=GetEnvironmentValue(<span style="background: none; color: #880000; font-weight: 400;">"MAGICK_TEMPORARY_PATH"</span>);
<span style="background: none; color: #444444; font-weight: 700;">if</span> (<span style="background: none; color: #397300; font-weight: 400;">directory</span> == (char *) <span style="background: none; color: #78a960; font-weight: 400;">NULL</span>)
<span style="background: none; color: #397300; font-weight: 400;">directory</span>=GetEnvironmentValue(<span style="background: none; color: #880000; font-weight: 400;">"MAGICK_TMPDIR"</span>);
<span style="background: none; color: #444444; font-weight: 700;">if</span> (<span style="background: none; color: #397300; font-weight: 400;">directory</span> == (char *) <span style="background: none; color: #78a960; font-weight: 400;">NULL</span>)
<span style="background: none; color: #397300; font-weight: 400;">directory</span>=GetEnvironmentValue(<span style="background: none; color: #880000; font-weight: 400;">"TMPDIR"</span>);
<span style="background: none; color: #888888; font-weight: 400;">#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__) || defined(__CYGWIN__)</span>
<span style="background: none; color: #444444; font-weight: 700;">if</span> (<span style="background: none; color: #397300; font-weight: 400;">directory</span> == (char *) <span style="background: none; color: #78a960; font-weight: 400;">NULL</span>)
<span style="background: none; color: #397300; font-weight: 400;">directory</span>=GetEnvironmentValue(<span style="background: none; color: #880000; font-weight: 400;">"TMP"</span>);
<span style="background: none; color: #444444; font-weight: 700;">if</span> (<span style="background: none; color: #397300; font-weight: 400;">directory</span> == (char *) <span style="background: none; color: #78a960; font-weight: 400;">NULL</span>)
<span style="background: none; color: #397300; font-weight: 400;">directory</span>=GetEnvironmentValue(<span style="background: none; color: #880000; font-weight: 400;">"TEMP"</span>);
<span style="background: none; color: #888888; font-weight: 400;">#endif</span>
<span style="background: none; color: #888888; font-weight: 400;">#if defined(__VMS)</span>
<span style="background: none; color: #444444; font-weight: 700;">if</span> (<span style="background: none; color: #397300; font-weight: 400;">directory</span> == (char *) <span style="background: none; color: #78a960; font-weight: 400;">NULL</span>)
<span style="background: none; color: #397300; font-weight: 400;">directory</span>=GetEnvironmentValue(<span style="background: none; color: #880000; font-weight: 400;">"MTMPDIR"</span>);
<span style="background: none; color: #888888; font-weight: 400;">#endif</span>
<span style="background: none; color: #888888; font-weight: 400;">#if defined(P_tmpdir)</span>
<span style="background: none; color: #444444; font-weight: 700;">if</span> (<span style="background: none; color: #397300; font-weight: 400;">directory</span> == (char *) <span style="background: none; color: #78a960; font-weight: 400;">NULL</span>)
<span style="background: none; color: #397300; font-weight: 400;">directory</span>=ConstantString(P_tmpdir);
<span style="background: none; color: #888888; font-weight: 400;">#endif</span>
.............
<span style="background: none; color: #888888; font-weight: 400;">#endif</span>
<span style="background: none; color: #444444; font-weight: 700;">return</span>(MagickTrue);
}</code> </pre><p>So, I set MAGICK_TEMPORARY_PATH environment variable pointing to some sub-directory of LocalLow folder (acquired by SHGetKnownFolderPath(..FOLDERID_LocalAppDataLow,,), and decided that the fix is done, a trivial one.<br /></p><p>Except I found that nothing has changed. <br />That's why: <br />1) I set environment variable with SetEnvironmentVariable WinAPI function<br />2) ImageMagick uses getenv CRT function, which is part of UCRT on Windows<br /><br />And Windows UCRT keeps own copy of all process environment variables without any synchronization with process environment block: it just copies all the variables while initialization and then uses a separate data structure that clearly resembles Unix'es "environ", except it is properly synchronized and has a longer name:</p>
<pre> <code id="htmlViewer" style="background-color: #f0f0f0; background: rgb(240, 240, 240); color: #444444; display: block; font-weight: 400; padding: 0.5em;"><span style="background: none; color: #888888; font-weight: 400;">// Windows Kits\10\Source\10.0.10240.0\ucrt\env\getenv.cpp</span>
<span style="background: none; color: #888888; font-weight: 400;">// These functions search the environment for a variable with the given name.</span>
<span style="background: none; color: #888888; font-weight: 400;">// If such a variable is found, a pointer to its value is returned. Otherwise,</span>
<span style="background: none; color: #888888; font-weight: 400;">// nullptr is returned. Note that if the environment is access and manipulated</span>
<span style="background: none; color: #888888; font-weight: 400;">// from multiple threads, this function cannot be safely used: the returned</span>
<span style="background: none; color: #888888; font-weight: 400;">// pointer may not be valid when the function returns.</span>
<span style="background: none; color: #444444; font-weight: 700;">template</span> <<span style="background: none; color: #444444; font-weight: 700;">typename</span> Character>
<span style="background: none; color: #444444; font-weight: 400;"><span style="background: none; color: #444444; font-weight: 700;">static</span> Character* __cdecl <span style="background: none; color: #880000; font-weight: 700;">common_getenv_nolock</span><span style="background: none; color: #444444; font-weight: 400;">(Character <span style="background: none; color: #444444; font-weight: 700;">const</span>* <span style="background: none; color: #444444; font-weight: 700;">const</span> name)</span> <span style="background: none; color: #880000; font-weight: 700;">throw</span><span style="background: none; color: #444444; font-weight: 400;">()</span>
</span>{
<span style="background: none; color: #444444; font-weight: 700;">typedef</span> __crt_char_traits<Character> traits;
Character** <span style="background: none; color: #444444; font-weight: 700;">const</span> environment = traits::<span style="background: none; color: #397300; font-weight: 400;">get_or_create_environment_nolock</span>();
<span style="background: none; color: #444444; font-weight: 700;">if</span> (environment == <span style="background: none; color: #78a960; font-weight: 400;">nullptr</span> || name == <span style="background: none; color: #78a960; font-weight: 400;">nullptr</span>)
<span style="background: none; color: #444444; font-weight: 700;">return</span> <span style="background: none; color: #78a960; font-weight: 400;">nullptr</span>;
<span style="background: none; color: #444444; font-weight: 700;">size_t</span> <span style="background: none; color: #444444; font-weight: 700;">const</span> name_length = traits::<span style="background: none; color: #397300; font-weight: 400;">tcslen</span>(name);
<span style="background: none; color: #444444; font-weight: 700;">for</span> (Character** current = environment; *current; ++current)
{
<span style="background: none; color: #444444; font-weight: 700;">if</span> (traits::<span style="background: none; color: #397300; font-weight: 400;">tcslen</span>(*current) <= name_length)
<span style="background: none; color: #444444; font-weight: 700;">continue</span>;
<span style="background: none; color: #444444; font-weight: 700;">if</span> (*(*current + name_length) != <span style="background: none; color: #880000; font-weight: 400;">'='</span>)
<span style="background: none; color: #444444; font-weight: 700;">continue</span>;
<span style="background: none; color: #444444; font-weight: 700;">if</span> (traits::<span style="background: none; color: #397300; font-weight: 400;">tcsnicoll</span>(*current, name, name_length) != <span style="background: none; color: #880000; font-weight: 400;">0</span>)
<span style="background: none; color: #444444; font-weight: 700;">continue</span>;
<span style="background: none; color: #888888; font-weight: 400;">// Internal consistency check: The environment string should never use</span>
<span style="background: none; color: #888888; font-weight: 400;">// a bigger buffer than _MAX_ENV. See also the SetEnvironmentVariable</span>
<span style="background: none; color: #888888; font-weight: 400;">// SDK function.</span>
_ASSERTE(traits::<span style="background: none; color: #397300; font-weight: 400;">tcsnlen</span>(*current + name_length + <span style="background: none; color: #880000; font-weight: 400;">1</span>, _MAX_ENV) < _MAX_ENV);
<span style="background: none; color: #444444; font-weight: 700;">return</span> *current + name_length + <span style="background: none; color: #880000; font-weight: 400;">1</span>;
}
<span style="background: none; color: #444444; font-weight: 700;">return</span> <span style="background: none; color: #78a960; font-weight: 400;">nullptr</span>;
}</code></pre>
<p> So, <br /></p>
<pre><code id="htmlViewer" style="background-color: #f0f0f0; background: rgb(240, 240, 240); color: #444444; display: block; font-weight: 400; padding: 0.5em;"> <span style="background: none; color: #444444; font-weight: 700;">_putenv_s</span>(<span style="background: none; color: #880000; font-weight: 400;">"MAGICK_TEMPORARY_PATH"</span>, fvMagickAppDataPath.c_str());</code></pre>
<p>did the trick.<br /></p>ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-58688850593089837952022-11-13T05:24:00.004-08:002022-11-13T05:32:45.826-08:00UI Windows Sandboxing<p>What I love about programming is that system programming can strike you back even if you are writing a simple desktop UI tool. For example, if you want it to be more secure, as I do. (it is Fancy Viewer tool in my case <a href="https://www.fancy-viewer.com/">https://www.fancy-viewer.com/</a>)</p><p>The tool uses ImageMagick library (plus plugins) which I completely trust, but vulnerabilities happen and it is better to run the parsers in some isolated environment, i.e. sandbox. </p><p>There are some Windows API functions for that:<br /></p><pre><code id="htmlViewer" style="background-color: #f0f0f0; background: rgb(240, 240, 240); color: #444444; display: block; font-weight: 400; padding: 0.5em;"><span style="background: none; color: #397300; font-weight: 400;">CreateRestrictedToken</span></code></pre><pre><code id="htmlViewer" style="background-color: #f0f0f0; background: rgb(240, 240, 240); color: #444444; display: block; font-weight: 400; padding: 0.5em;"><span style="background: none; color: #397300; font-weight: 400;">CreateProcessAsUserW</span></code></pre>which work as charm:<pre><span style="color: #444444;"></span></pre><pre><img alt="" height="41" src="data:image/png;base64,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" width="400" /><span style="color: #444444;"><br /></span></pre><p>Except you have to rewrite token's default DACL or the app refuses to start on Windows 7 (or on Windows 10 with "run as administrator").</p><p>Like here:<br /></p><pre><code id="htmlViewer" style="background-color: #f0f0f0; background: rgb(240, 240, 240); color: #444444; display: block; font-weight: 400; padding: 0.5em;"><span style="background: none; color: #444444; font-weight: 400;">BOOL <span style="background: none; color: #880000; font-weight: 700;">CreateProcessRestrictedW</span><span style="background: none; color: #444444; font-weight: 400;">(LPWSTR lpCommandLine,
LPSTARTUPINFOW lpStartupInfo,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
OUT LPPROCESS_INFORMATION lpProcessInformation)</span>
</span>{
HANDLE hProcessToken = <span style="background: none; color: #880000; font-weight: 400;">0</span>, hRestrictedToken = <span style="background: none; color: #880000; font-weight: 400;">0</span>;
<span style="background: none; color: #444444; font-weight: 700;">if</span> (!<span style="background: none; color: #397300; font-weight: 400;">OpenProcessToken</span>(<span style="background: none; color: #397300; font-weight: 400;">GetCurrentProcess</span>(),
TOKEN_ALL_ACCESS | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY,
&hProcessToken))
{
<span style="background: none; color: #444444; font-weight: 700;">return</span> FALSE;
}
<span style="background: none; color: #444444; font-weight: 400;">lsvu::HandleGuard <span style="background: none; color: #880000; font-weight: 700;">processTokenGuard</span><span style="background: none; color: #444444; font-weight: 400;">(hProcessToken)</span></span>;
<span style="background: none; color: #888888; font-weight: 400;">// get current user sid</span>
std::vector<<span style="background: none; color: #444444; font-weight: 700;">char</span>> currentUserSID;
<span style="background: none; color: #444444; font-weight: 700;">if</span> (<span style="background: none; color: #397300; font-weight: 400;">QueryTokenSID_Silent</span>(hProcessToken, &currentUserSID))
{
<span style="background: none; color: #444444; font-weight: 700;">return</span> FALSE;
}
<span style="background: none; color: #888888; font-weight: 400;">// collect other system sids</span>
std::vector<<span style="background: none; color: #444444; font-weight: 700;">char</span>> adminSID;
<span style="background: none; color: #444444; font-weight: 700;">if</span> (<span style="background: none; color: #397300; font-weight: 400;">GetWellKnownSid_Silent</span>(WinBuiltinAdministratorsSid, adminSID))
{
<span style="background: none; color: #444444; font-weight: 700;">return</span> FALSE;
}
std::vector<<span style="background: none; color: #444444; font-weight: 700;">char</span>> localSystemSID;
<span style="background: none; color: #444444; font-weight: 700;">if</span> (<span style="background: none; color: #397300; font-weight: 400;">GetWellKnownSid_Silent</span>(WinLocalSystemSid, localSystemSID))
{
<span style="background: none; color: #444444; font-weight: 700;">return</span> FALSE;
}
SID_AND_ATTRIBUTES sidToDisable = { adminSID.<span style="background: none; color: #397300; font-weight: 400;">data</span>(), <span style="background: none; color: #880000; font-weight: 400;">0</span> };
<span style="background: none; color: #888888; font-weight: 400;">// create the restricted token</span>
<span style="background: none; color: #444444; font-weight: 700;">if</span> (!<span style="background: none; color: #397300; font-weight: 400;">CreateRestrictedToken</span>(hProcessToken,
DISABLE_MAX_PRIVILEGE | LUA_TOKEN,
<span style="background: none; color: #880000; font-weight: 400;">1</span>, &sidToDisable,
<span style="background: none; color: #880000; font-weight: 400;">0</span>, <span style="background: none; color: #880000; font-weight: 400;">0</span>,
<span style="background: none; color: #880000; font-weight: 400;">0</span>, <span style="background: none; color: #880000; font-weight: 400;">0</span>,
&hRestrictedToken))
{
<span style="background: none; color: #444444; font-weight: 700;">return</span> FALSE;
}
<span style="background: none; color: #444444; font-weight: 400;">lsvu::HandleGuard <span style="background: none; color: #880000; font-weight: 700;">restrictedTokenGuard</span><span style="background: none; color: #444444; font-weight: 400;">(hRestrictedToken)</span></span>;
<span style="background: none; color: #888888; font-weight: 400;">// Set the token to low integrity:</span>
TOKEN_MANDATORY_LABEL tokenLabel = { <span style="background: none; color: #880000; font-weight: 400;">0</span> };
tokenLabel.Label.Attributes = SE_GROUP_INTEGRITY;
<span style="background: none; color: #444444; font-weight: 700;">if</span> (!<span style="background: none; color: #397300; font-weight: 400;">ConvertStringSidToSidW</span>(<span style="background: none; color: #880000; font-weight: 400;">L"S-1-16-4096"</span>, &tokenLabel.Label.Sid))
{
<span style="background: none; color: #444444; font-weight: 700;">return</span> FALSE;
}
{
<span style="background: none; color: #444444; font-weight: 400;">LocalGuard <span style="background: none; color: #880000; font-weight: 700;">sidLabelGuard</span><span style="background: none; color: #444444; font-weight: 400;">(tokenLabel.Label.Sid)</span></span>;
<span style="background: none; color: #444444; font-weight: 700;">if</span> (!<span style="background: none; color: #397300; font-weight: 400;">SetTokenInformation</span>(hRestrictedToken,
TokenIntegrityLevel,
&tokenLabel,
<span style="background: none; color: #397300; font-weight: 400;"><span style="background: none; color: #444444; font-weight: 700;">sizeof</span></span>(tokenLabel) + <span style="background: none; color: #397300; font-weight: 400;">GetLengthSid</span>(tokenLabel.Label.Sid)))
{
<span style="background: none; color: #444444; font-weight: 700;">return</span> FALSE;
}
}
<span style="background: none; color: #888888; font-weight: 400;">// Create new DACL</span>
std::vector<<span style="background: none; color: #444444; font-weight: 700;">char</span>> dacl;
<span style="background: none; color: #444444; font-weight: 700;">if</span> (<span style="background: none; color: #397300; font-weight: 400;">CreateACL_Silent</span>(dacl, currentUserSID, adminSID, localSystemSID))
{
<span style="background: none; color: #444444; font-weight: 700;">return</span> FALSE;
}
TOKEN_DEFAULT_DACL newDefaulDACL = { (PACL)dacl.<span style="background: none; color: #397300; font-weight: 400;">data</span>() };
<span style="background: none; color: #444444; font-weight: 700;">if</span> (!<span style="background: none; color: #397300; font-weight: 400;">SetTokenInformation</span>(hRestrictedToken, TokenDefaultDacl, <br /> &newDefaulDACL, <span style="background: none; color: #397300; font-weight: 400;"><span style="background: none; color: #444444; font-weight: 700;">sizeof</span></span>(newDefaulDACL)))
{
<span style="background: none; color: #444444; font-weight: 700;">return</span> FALSE;
}
<span style="background: none; color: #888888; font-weight: 400;">// Create a new process using the restricted token</span>
BOOL result = <span style="background: none; color: #397300; font-weight: 400;">CreateProcessAsUserW</span>(hRestrictedToken,
<span style="background: none; color: #78a960; font-weight: 400;">NULL</span>,
lpCommandLine,
<span style="background: none; color: #78a960; font-weight: 400;">NULL</span>,
<span style="background: none; color: #78a960; font-weight: 400;">NULL</span>,
bInheritHandles,
dwCreationFlags,
(LPVOID)lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
<span style="background: none; color: #444444; font-weight: 700;">return</span> result;
} </code> </pre><p>It isn't a full compilable source, but demonstrates the idia well enough.</p>ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-47758917350571161582022-10-26T11:35:00.003-07:002022-11-13T05:32:32.367-08:00[offtop] UI and Guilty Pleasure<p>Suddenly started a desktop tool for file viewing purposes:<br /></p><p><a href=" https://www.fancy-viewer.com/ "> https://www.fancy-viewer.com/ </a></p><p>Yeaaah, just another photo viewing tool: Windows/API, ImageMagick-based, see About->Licenses for licenses.</p><p>There are couple of reasons why I did it:</p><p>- first, I need a hobby and I'm not in the mood for another low level hobby-security-project; had a lot of that stuff on the job;</p><p>- then, the process of testing i.e, going through gigabytes of photos on my hard drive calms me very well, which is good for the mental health. Funny thing, UI bugs don't frustrate me at all (I know a lot of people who hate them terribly);</p><p>- I use the tool by myself and I just like it this way: I like the ability of reviewing photos without being limited with fixed-sized thumbnails; I also use built-in FTPS client features, Tags and Favorites features, Dark Theme, etc.<br /></p><p>It is still a little bit raw: doesn't have proper auto-update system and code signing (I ordered the cert, but the process is slow as hell). UI obviously lacks of RTL support; multi-language support is not that great, it currently just supports only two of languages: English and Ukrainian. </p><p>P.S: Some UI controls were created completely from scratch, and it was a lot of fun with Win32 stuff which I also love (while 70%-80% of my regular job is about Linux/Unix systems currently)<br /></p><p></p>ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-4928326646748298382018-01-06T06:34:00.002-08:002018-01-06T07:44:37.914-08:00Orthia Windbg Extension 2.0.0.193 released<div class="value">
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download"></pre>
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download"> </pre>
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download">Orthia Windbg Extension 2.0.0.193 Released</pre>
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download">Latest version:
<a href="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download">https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download</a></pre>
<h3 class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download">
1. New Major Feature added: Code Emulator</h3>
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download"></pre>
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download">How to use: </pre>
<blockquote class="tr_bq">
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download">// load extension and setup profile
.load orthia.dll
!orthia.profile %temp%\test.db
// rewrite default VM (another way is to use vm_vm_new)
!orthia.vm_vm_def
// run the function and show the result
!orthia.vm_vm_call 0 nt!PsGetCurrentProcess --print </pre>
</blockquote>
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download"></pre>
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download">See Wiki for the details:
<a href="https://sourceforge.net/p/diana-dasm/wiki/Orthia%20Windbg%20plugin/">https://sourceforge.net/p/diana-dasm/wiki/Orthia%20Windbg%20plugin/</a> </pre>
<h3 class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download">
2. Code Analyzer improved</h3>
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download">1. Memory consumption reduced
2. Performance of analyzing improved</pre>
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download"></pre>
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download"></pre>
<br />
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download">The latest sources: </pre>
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download"><a href="https://sourceforge.net/p/diana-dasm/code/HEAD/tree/trunk/src/">https://sourceforge.net/p/diana-dasm/code/HEAD/tree/trunk/src/</a></pre>
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download"> </pre>
<pre class="selectable" style="width: 97%;" title="https://sourceforge.net/projects/diana-dasm/files/orthia-2.0.0.193.zip/download"></pre>
</div>
ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-60989799880310551022017-01-04T09:47:00.002-08:002017-09-21T06:59:44.669-07:00Windbg: raw dumping of usermode memoryThis script works fine for me and dumps all the MEM_COMMIT pages to the specified folder:<br />
<br />
<blockquote class="tr_bq">
.foreach /ps 6 (place {!address -o:1 /f:MEM_COMMIT}) { .foreach /pS a /ps 100 (size {!address place }) { .echo place size; .writemem c:\dir2export\prefix${place} place L?${size}; } }</blockquote>
<br />
How to use:<br />
- change "c:\dir4data" to your directory name;<br />
- change "prefix" to the appropriate file prefix or remove it at all;<br />
<br />
Do not forget that Windbg doesn't understand multi-line scripts and !address extension works differently in the kernel-mode environment.<br />
<br />
<b>UPD. </b>For some strange reason Windbg randomly shows can't access the memory error, but the next run of script completes successfully.<br />
<br />
<b>UPD2. </b>Also the script is useful for full memory search:<br />
<blockquote class="tr_bq">
// 8 bytes<br />
.foreach /ps 6 (place {!address -o:1 /f:MEM_COMMIT}) { .foreach /pS a /ps 100 (size {!address place }) { s -q ${place} L?${size}/8 <quad-value-to-scan>put-variable-here; } }</quad-value-to-scan></blockquote>
<blockquote class="tr_bq">
// 4 bytes<br />
.foreach /ps 6 (place {!address -o:1 /f:MEM_COMMIT}) { .foreach /pS a /ps 100 (size {!address place }) { s -d ${place} L?${size}/4 <dword-value-to-scan>put-variable-here; } } </dword-value-to-scan></blockquote>
<br />
etc ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-5882173145603215172016-06-07T00:51:00.000-07:002016-06-07T00:55:42.529-07:00The terrible story about .NET Invoke1. There is something interesting about PostMessage<br />
<blockquote class="tr_bq">
There is a limit of 10,000 posted messages per message queue. This
limit should be sufficiently large. If your application exceeds the
limit, it should be redesigned to avoid consuming so many system
resources. To adjust this limit, modify the following registry key.
<br />
<pre><b>HKEY_LOCAL_MACHINE</b>
<b>SOFTWARE</b>
<b>Microsoft</b>
<b>Windows NT</b>
<b>CurrentVersion</b>
<b>Windows</b>
<b>USERPostMessageLimit</b></pre>
The minimum acceptable value is 4000. </blockquote>
<a href="https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms644944%28v=vs.85%29.aspx">https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms644944%28v=vs.85%29.aspx</a><br />
<br />
2. And this explains why Invoke hangs when reaches the limit:<br />
<br />
<blockquote class="tr_bq">
<pre class="brush:csharp">private object MarshaledInvoke(Control caller,
Delegate method,
object[] args,
bool synchronous)
{
int lpdwProcessId;
/// ....
/// skipped
/// ....
if (flag)
this.InvokeMarshaledCallbacks();
else
{
UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle),
threadCallbackMessage,
IntPtr.Zero,
IntPtr.Zero);
}
if (!synchronous)
return entry;
if (!entry.IsCompleted)
this.WaitForWaitHandle(entry.AsyncWaitHandle); // <<<< OOPS
if (entry.exception != null)
throw entry.exception;
return entry.retVal;
}</pre>
</blockquote>
<pre class="brush:csharp"></pre>
<pre class="brush:csharp"><a href="http://workblog.pilin.name/2007/04/control.html">http://workblog.pilin.name/2007/04/control.html </a></pre>
<pre class="brush:csharp"></pre>
<pre class="brush:csharp">It's a scary, scary world</pre>
ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-35985166595627998132015-11-05T02:54:00.003-08:002015-11-05T02:58:38.082-08:00oh my god! they killed LastAccessTimeСабж случился 9 лет назад вместе с выходом Windows Vista и остался незаметным для широких масс <strike>пользователей</strike> программистов до сих пор:<br />
<br />
<a href="http://blogs.technet.com/b/filecab/archive/2006/11/07/disabling-last-access-time-in-windows-vista-to-improve-ntfs-performance.aspx">http://blogs.technet.com/b/filecab/archive/2006/11/07/disabling-last-access-time-in-windows-vista-to-improve-ntfs-performance.aspx</a><br />
<a href="https://technet.microsoft.com/en-us/library/cc959914.aspx">https://technet.microsoft.com/en-us/library/cc959914.aspx</a><br />
<br />
Итого, из пяти параметров FILE_BASIC_INFORMATION осталось три полезных, своего рода рекорд.ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-12320513896911494572013-08-26T12:21:00.002-07:002017-01-04T09:49:09.441-08:00Orthia Windbg PluginДошли руки дописать <a href="https://sourceforge.net/projects/diana-dasm/files/">winbg-плагин</a> который дает скромную возможность анализировать код прямо в windbg сессии. Поскольку плагин базируется на библиотеке diana, я почему-то решил назвать его orthia.<br />
Краткое описание возможностей доступно на <a href="https://sourceforge.net/p/diana-dasm/wiki/Orthia%20Windbg%20plugin/">sourceforge wiki</a><br />
Примеры использования:<br />
1) как настроить окружение. Orthia сохраняет всю информацию в sqlite базе данных на диске, перед работой с плагином нужно указать имя файла с помощью команды !orthia.profile.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaXe3mRC2OHrUgF_te4DbLaFpaRYtgQhkW8uQU2mu4bGTdDyIQ37UVWs97ZiBvDkMii62DrTb4HClsoFcFVfaGvg202T84ae8dURh0DxW0rHgh0wq1o4zEyBrc1MioOkxV8bkhLSi7Eb0/s1600/sample1-tuneup.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaXe3mRC2OHrUgF_te4DbLaFpaRYtgQhkW8uQU2mu4bGTdDyIQ37UVWs97ZiBvDkMii62DrTb4HClsoFcFVfaGvg202T84ae8dURh0DxW0rHgh0wq1o4zEyBrc1MioOkxV8bkhLSi7Eb0/s200/sample1-tuneup.png" /> </a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
2) как проанализировать все модули (не рекомендуется в kernel mode под живым коннекшном - может быть долго)</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEPAAEZdofT5YJJALxxzqVVVC_fc3kJuwz2BdIF3RJAtWMFzjNlbUGzXgX7EHpLEZuYkcoNbBQCjtI8rhUnj6MYgxky49V3M1H_XhNQRC-wxn2dzxagIJOhWjiM4sImz8FplkYHTSYLH8/s1600/sample2-reload.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEPAAEZdofT5YJJALxxzqVVVC_fc3kJuwz2BdIF3RJAtWMFzjNlbUGzXgX7EHpLEZuYkcoNbBQCjtI8rhUnj6MYgxky49V3M1H_XhNQRC-wxn2dzxagIJOhWjiM4sImz8FplkYHTSYLH8/s200/sample2-reload.png" /> </a></div>
<div class="separator" style="clear: both; text-align: left;">
исполнительная система nt у меня и так подгружается 2.5 минуты</div>
<div class="separator" style="clear: both; text-align: left;">
3) пример команды !orthia.x - eXamine address</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYfAd1QTIwh8Ocje2MqGWCXbOY4oWZxY7-_w0XphWvlE6rqxHoYF_PDlEY70_gX0kMm1sz7jGDHPgwBKJ2lcVCBP760oIq6bYDW_xElTcIO-WQqevvdCw7SGIcj86yERqTHILw9YTYme8/s1600/sample3-x.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYfAd1QTIwh8Ocje2MqGWCXbOY4oWZxY7-_w0XphWvlE6rqxHoYF_PDlEY70_gX0kMm1sz7jGDHPgwBKJ2lcVCBP760oIq6bYDW_xElTcIO-WQqevvdCw7SGIcj86yERqTHILw9YTYme8/s200/sample3-x.png" /> </a><br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
4) пример команды !orthia.xr - eXamine Range</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0_ZE7yzXnoduTK5bTVDRZazm_vANBuwftgjo4qR49xCGBo4CGt-HVbHnX2gnl8DRGmWnrUA7QQat0uE8a__P0V72c77Mnm0hkIfLIQn3mdc6lKuAIPnyIlWTb436J9uyggUHeuC2xaxg/s1600/sample4-xr.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0_ZE7yzXnoduTK5bTVDRZazm_vANBuwftgjo4qR49xCGBo4CGt-HVbHnX2gnl8DRGmWnrUA7QQat0uE8a__P0V72c77Mnm0hkIfLIQn3mdc6lKuAIPnyIlWTb436J9uyggUHeuC2xaxg/s200/sample4-xr.png" /> </a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
5) пример анализа связки nt + ntfs, часть I:</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfR7zgMI8g2JfDW1zlEPaRI0zuHwF6UuxexfUOBUOhvbBYGWLMoe7fae1-rtKOO97KOJM0pI0Yy7cCAHbFSb6U0mHdF6WSUEM-dW_YUHxRY2Fuocf2ZNDfOc87XU3H2kvfKQruieSry5k/s1600/sample5-live1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfR7zgMI8g2JfDW1zlEPaRI0zuHwF6UuxexfUOBUOhvbBYGWLMoe7fae1-rtKOO97KOJM0pI0Yy7cCAHbFSb6U0mHdF6WSUEM-dW_YUHxRY2Fuocf2ZNDfOc87XU3H2kvfKQruieSry5k/s200/sample5-live1.png" /> </a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
6) пример анализа связки nt+ntfs, часть II:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7sEJu5v3YpYt328gO_8187cYZBJUYzZmTAlA_vqj6P4gvLMprjY5eE0rLZ_GH4UhHtyVEAEaE2mFt00woGn52ajKOljKHjcS6ashxq8nl0qN8Tk_7zrWaQXDVAuIucKGWNxOOKwiLnqk/s1600/sample5-live2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7sEJu5v3YpYt328gO_8187cYZBJUYzZmTAlA_vqj6P4gvLMprjY5eE0rLZ_GH4UhHtyVEAEaE2mFt00woGn52ajKOljKHjcS6ashxq8nl0qN8Tk_7zrWaQXDVAuIucKGWNxOOKwiLnqk/s200/sample5-live2.png" /> </a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Пути улучшения:</div>
<div class="separator" style="clear: both; text-align: left;">
- конечно же багфикс. ну что за программа без багов;</div>
<div class="separator" style="clear: both; text-align: left;">
- нужно бы слегка оптимизировать анализ по скорости;</div>
<div class="separator" style="clear: both; text-align: left;">
- есть идея добавить GUI окно со стрелочками ala-IDA, если получится встроиться прямо в windbg.</div>
<div class="separator" style="clear: both; text-align: left;">
Вообще, это все писалось строго для fun'а, но может быть кому-то быть полезным.</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-76881264049963259292013-04-10T16:03:00.001-07:002013-04-10T16:18:41.165-07:00Mystical 0x33 cs selector in WOWЕсли посмотреть во внутренности WOW64 эмулятора под Windows 8 64 (интересно глянуть на других виндах, нету под рукой) можно увидеть что-то занятное:<br />
<br />
<span style="font-family: Courier New;">ntdll!NtClose:<br />
77750e4c b80d000000 mov eax,0xd<br />
77750e51 64ff15c0000000 call dword ptr fs:[000000c0]<br />
77750e58 c20400 ret 0x4<br />
77750e5b 90 </span><br />
<br />
Вместо родного sysenter'а находится нечто новое - call.<br />
<br />
Интересно, что студийный отладчик отказывается заходить внутрь call, делая вид, что там ничего нет, windbg и diana_dasm показывают честный переход на:<br />
<br />
776521dc ea662565773300 jmp 0033:77652566<br />
<br />
Вот что Livekd говорит о новом мистическом селекторе 0x33:<br />
<br />
<br />
<span style="font-family: Courier New;">0: kd> dg 33<br />
P Si Gr Pr Lo<br />
Sel Base Limit Type l ze an es ng Flags<br />
---- ----------------- ----------------- ---------- - -- -- -- -- --------<br />
0033 00000000`00000000 00000000`00000000 Code RE Ac 3 Nb By P Lo 000002fb</span><br />
<br />
Он вроде бы RE, но почитать эту память из usermode, изменив значение ds на 33 у меня не получается.<br />
<br />
UPD: Можно прочитать адрес 77652566 по DS селектору, там живет некий обработчик прерывания (?), заканчивающийся iretd. Судя по всему, вызывается он через некий специальный механизм, ибо получает параметры в некоторых регистрах, которые не подготавливаются в <span style="font-family: Courier New;">ntdll!NtClose.</span>ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-45935218491039870932013-04-09T13:44:00.002-07:002013-04-09T13:44:38.365-07:00 lock free intrusive FIFO - Part3В продолжении истории о <a href="http://zone-of-ambiguity.blogspot.com/2011/11/lock-free-intrusive-fifo-part2.html">Lock Free Intrusive FIFO</a>, задался целью улучшить поведение <a href="http://zone-of-ambiguity.blogspot.com/2011/11/lock-free-intrusive-fifo.html">pop_front </a>из MPMC-версии очереди. <br />
<br />
Описание проблемы <a href="http://zone-of-ambiguity.blogspot.com/2011/11/lock-free-intrusive-fifo.html">из предыдущего поста</a>:<br />
<blockquote class="tr_bq">
Также интересно было бы попробовать, можно ли данный примитив привести к
виду wait-free. В приведенной ниже реализации производители особо не
мешают друг другу, но потребители перманентно "толкаются", и могут
вхолостую использовать ресурсы процессора, что видимо, не есть гуд.</blockquote>
Решение, приведенное в нем, действительно обладает недостатком: в нем каждый поток пытается захватить &m_processingNode, чтобы впоследствии эксклюзивно вынимать m_pFront - первую ноду. Хотелось бы добиться того, чтобы каждый поток мог гарантированно получить ноду за конечное количество шагов.<br />
При работе над этой проблемой, у меня возникла забавная мысль, что сам оригинальный MPSC без processingNode является идеальным средством для синхронизации потоков.<br />
Т.е. если рядом с основной MPSC очередью данных положить еще одну MPSC очередь для синхронизации, содержащую некие ThreadNodes, то можно привести pop_front к wait_free виду, используя следующий алгоритм:<br />
1. выделили ThreadNode node; на стеке<br />
2. сделали lockQueue.push_back(&node);<br />
3. ждем пока lockQueue.m_pFront не будет равен указателю на node.<br />
4. вуаля! мы захватили лок.<br />
5. вынимаем элемент используя pop_front из dataQueue<br />
6. отпускаем лок: делаем lockQueue.pop_front()<br />
В данном алгоритме присутствует одна проблема. Поскольку наш MPSC Queue работает с рутовой/фейковой нодой, то в пункт 3 потоки могут и не попасть, если фейковая нода находится на первом месте. Т.е. нужно анализировать m_pFront на предмет наличия в нем указателя на фейковую ноду:<br />
<br />
<!-- Colorized Code Begins -->
<!-- Setup Info -->
<!-- First : 1 -->
<!-- Font Face : 'Courier New' -->
<!-- Font Size : +1 -->
<!-- Pre Tag : 0 -->
<!-- Raw : 1 -->
<!-- Table : 0 -->
<span style="font-family: Courier New;"><span style="color: #9933ff;">class</span> <span style="color: green;">CLock</span>:<span style="color: #339966;">private</span> <span style="color: green;">CListImpl</span><br />
{<br />
<span style="color: green;">BaseNode</span> * <span style="color: blue;">m_pRootLock</span>;<br />
<span style="color: #339966;">public</span>:<br />
CLock()<br />
: m_pRootLock(0)<br />
{<br />
}<br />
<span style="color: green;">void</span> <span style="color: blue;">lock</span>(<span style="color: green;">BaseNode</span> * <span style="color: blue;">pThreadNode</span>)<br />
{<br />
push_back(pThreadNode);<br />
<br />
<span style="color: #9933ff;">while</span>(1)<br />
{<br />
<span style="color: #9933ff;">if</span> (m_pFirst == pThreadNode)<br />
<span style="color: #9933ff;">return</span>; // we won the race!<br />
</span><br />
<span style="font-family: Courier New;"> <br />
<span style="color: #9933ff;">if</span> (m_pFirst == &m_rootNode)<br />
{ // oops, we need to choose one person who </span><br />
<span style="font-family: Courier New;"> // will kill the dragon<br />
<span style="color: #9933ff;">if</span> (!CompareAndSwap(&m_pRootLock, pThreadNode, (<span style="color: green;">BaseNode</span> *)0))<br />
{<br />
<span style="color: #9933ff;">if</span> (<span style="color: blue;">m_pFirst</span> == &m_rootNode)<br />
{<br />
pop_front(<span style="color: #339966;">true</span>);<br />
}<br />
Exchange(&m_pRootLock, (<span style="color: green;">BaseNode</span> *)0);<br />
}<br />
}<br />
}<br />
}<br />
<span style="color: green;">void</span> <span style="color: blue;">unlock</span>(<span style="color: green;">BaseNode</span> * <span style="color: blue;">pTheadNode</span>)<br />
{<br />
pop_front(<span style="color: #339966;">false</span>);<br />
}<br />
};</span><br />
<span style="font-family: Courier New;"><br />
</span>
<!-- Colorized Code Ends --> <br />
<span style="font-family: Courier New;">Т.е из MPSC очереди получился прекрасный лок для использования в MPMC очереди.</span><span style="font-family: Courier New;">Данный примитив </span><span style="font-family: Courier New;"><span style="font-family: Courier New;">мне чем-то </span>напоминает Bakery Lock, но в отличие от него позволяет синхронизировать заранее неизвестное количество потоков.</span><br />
<span style="font-family: Courier New;">Тогда сама очередь может выглядеть так:<br />
</span>
<br />
<br />
<!-- Colorized Code Begins -->
<!-- Setup Info -->
<!-- First : 1 -->
<!-- Font Face : 'Courier New' -->
<!-- Font Size : +1 -->
<!-- Pre Tag : 0 -->
<!-- Raw : 1 -->
<!-- Table : 0 -->
<span style="font-family: Courier New;"><span style="color: #9933ff;">template<</span><span style="color: #9933ff;">class</span> <span style="color: green;">NodeType</span><span>></span><br />
<span style="color: #9933ff;">class</span> <span style="color: green;">CIntrusiveList</span><br />
{<br />
<span style="color: green;">CListImpl</span> <span style="color: blue;">m_listImpl</span>;<br />
<span style="color: green;">CLock</span> <span style="color: blue;">m_popLock</span>;<br />
<span style="color: #339966;">public</span>:<br />
CIntrusiveList()<br />
{<br />
}<br />
<span style="color: green;">void</span> <span style="color: blue;">push_back</span>(<span style="color: green;">NodeType</span> * <span style="color: blue;">pNode</span>)<br />
{<br />
m_listImpl.push_back(pNode);<br />
}<br />
<span style="color: green;">NodeType</span> * <span style="color: blue;">pop_front</span>()<br />
{<br />
<span style="color: green;">ScopedLock</span> <span style="color: blue;">guard</span>(&m_popLock);<br />
<span style="color: #9933ff;">return</span> <span style="color: #9933ff;">static_cast</span><span><</span><span style="color: green;">NodeType</span> *<span>></span>(<span style="color: blue;">m_listImpl</span>.pop_front(<span style="color: #339966;">false</span>));<br />
}<br />
};</span><br />
<span style="font-family: Courier New;"><br />
</span>
<!-- Colorized Code Ends --> <br />
<span style="font-family: Courier New;">По моему, достаточно краси<span>во.</span></span><br />
<span style="font-family: Courier New;"><span>Законченн<span>ый пример:</span></span></span><br />
<span style="font-family: Courier New;"><span><span><a href="https://xp-dev.com/svn/ligen-blog-support/trunk/lock.cpp">https://xp-dev.com/svn/ligen-blog-support/trunk/lock.cpp</a> </span></span></span><br />
<span style="font-family: Courier New;"><span><a href="https://xp-dev.com/svn/ligen-blog-support/trunk/lat_relacy_test/"><span>https://xp-dev.com/svn/ligen-blog-support/trunk/lat_relacy_test/ </span></a> </span><br />
</span>
<!-- Colorized Code Ends --> ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-88842561163500388582012-12-23T09:37:00.000-08:002012-12-23T09:37:38.424-08:00Diana Dasm 1.0 releasedЯ рад сообщить, что бранч релизной версии Diana Disassembler поселился тут:<br />
<a href="https://diana-dasm.svn.sourceforge.net/svnroot/diana-dasm/v1.0.0/src">https://diana-dasm.svn.sourceforge.net/svnroot/diana-dasm/v1.0.0/src</a><br />
В бранче как обычно дизассемблер и эмулятор:<br />
<ul>
<li>дизассемблер поддерживает 490 команд (<a href="https://diana-dasm.svn.sourceforge.net/svnroot/diana-dasm/v1.0.0/src/diana_core/diana_core/diana_gen.c">более 1100 опкодов</a>)</li>
<li>эмулятор может эмулировать <a href="https://diana-dasm.svn.sourceforge.net/svnroot/diana-dasm/v1.0.0/src/diana_core/diana_processor/diana_processor_commands.c">131 команду</a> </li>
<li>как и раньше, все компоненты могут работать в kernel-mode, внутри движка только С, никаких внешних зависимостей, все работает на стримах</li>
</ul>
<br />
<br />
<br />
Новости ревизии:<br />
<br />
<blockquote class="tr_bq">
[1.0.0-diana-win32-src] - 116 revision<br />+ improved database format<br />+ imporved performance<br />+ fixed mov r15, cr8 | 45 0F 20 C7 added cr8-15, dr8-15<br />+ fixes LOCK/REP prefixes in DianaProcessor<br />+ fixed specs for SYSENTER/SYSCALL<br />+ HINT_NOP tests<br />+ added hint_nop support and long nops with prefixes, added command ids<br />+ fixed SLDT/INVLPGA<br />+ added special flag for privileged instructions<br />+ added GETSECXGETBV/XSETBVEMMS/FEMMSXSAVE/XRSTOR<br />+ DianaProcessor: fixed prefix 0x67 for jmp/loop/call<br />+ added MASKMOVQ/MOVNTQfix PMOVMSKB/MASKMOVDQU/PEXTRW<br />+ added VMREAD/VMWRITE opcodes<br />+ added MFENCE/LFENCE/SFENCE/XRSTOR/CLFLUSH</blockquote>
Так же у каждой команды появился персистентный <a href="https://diana-dasm.svn.sourceforge.net/svnroot/diana-dasm/v1.0.0/src/diana_core/diana_core/diana_commands.h">целочисленный идентификатор</a>, рекомендуется к использованию вместо строкового идентификатора.ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-14998107058125320802011-12-24T02:49:00.000-08:002011-12-24T02:58:15.230-08:00а вы говорите виндовый шелл это скучноНо место творчеству есть везде:<br /><pre>@echo off<span class="operator"><br />::</span> Code by Herbert Kleebauer<br />echo Bj@jzh`0X<span class="operator">-</span>`<span class="operator">/</span>PPPPPPa<span class="operator">(</span>DE<span class="operator">(</span>DM<span class="operator">(</span>DO<span class="operator">(</span>Dh<span class="operator">(</span>Ls<span class="operator">(</span>Lu<span class="operator">(</span>LX<span class="operator">(</span>LeZRR<span class="operator">]</span>EEEUYRX2Dx<span class="operator">=></span>d_t<span class="operator">.</span>com<br />echo 0DxFP<span class="operator">,</span>0Xx<span class="operator">.</span>t0P<span class="operator">,=</span>XtGsB4o@$<span class="operator">?</span>PIyU WwX0GwUY Wv<span class="operator">;</span>ovBX2Gv0ExGIuht6<span class="operator">>></span>d_t<span class="operator">.</span>com<br />echo LisqMz`wGH@wKuur`G@w<span class="operator">?</span>ogBgGG<span class="operator">}</span>G<span class="operator">?</span>j_egoNOG<span class="operator">?</span>w<span class="operator">?</span>`gBLksqgG`w<span class="operator">?</span>WgBgG<span class="operator">>></span>d_t<span class="operator">.</span>com<br />echo G<span class="operator">}</span>G<span class="operator">?</span>R_MgoNMy<span class="operator">?</span>wSx@W<span class="operator">?</span>s<span class="operator">?</span>W<span class="operator">?</span>@zAB`LrFuBLyt<span class="operator">~</span>vuco<span class="operator">{</span>@LuKooD<span class="operator">?</span>BFHqrIcP<span class="operator">>></span>d_t<span class="operator">.</span>com<br />echo _sdDxb1T<span class="operator">??=?</span>rILO_sdDqx1T<span class="operator">??=?</span>rILO_sdDnl1T<span class="operator">??=?</span>rILO_sdD`c1T<span class="operator">??>></span>d_t<span class="operator">.</span>com<br />echo<span class="operator"> =?</span>rILO_sdDgg1T<span class="operator">??=?</span>rILO_sdDll1T<span class="operator">??=?</span>rILO_sdDrr1T<span class="operator">??=??</span>IL<span class="operator">?</span>0xxx<span class="operator">>></span>d_t<span class="operator">.</span>com<br /><br />FOR<span class="operator"> /</span>F<span class="string"> "delims="</span><span class="operator"> %%</span>i IN<span class="operator"> (</span><span class="char">'d_t.com'</span><span class="operator">)</span> DO<span class="operator"> %%</span>i<br />del d_t<span class="operator">.</span>com<br /><br />echo century<span class="operator">: %</span>_cy<span class="operator">%</span><br /><br />echo year<span class="operator">: %</span>_yr<span class="operator">%</span><br />echo month<span class="operator">: %</span>_mo<span class="operator">%</span><br />echo day<span class="operator">: %</span>_da<span class="operator">%</span><br />echo hour<span class="operator">: %</span>_hh<span class="operator">%</span><br /><br />echo minute<span class="operator">: %</span>_mm<span class="operator">%</span><br />echo second<span class="operator">: %</span>_ss<span class="operator">%</span><br />echo all<span class="operator">: %</span>_cy<span class="operator">%%</span>_yr<span class="operator">%-%</span>_mo<span class="operator">%-%</span>_da<span class="operator">% %</span>_hh<span class="operator">%:%</span>_mm<span class="operator">%:%</span>_ss<span class="operator">%</span><br /><br />echo<span class="operator">.</span><br />echo<span class="operator"> %</span>DATE<span class="operator">% %</span>TIME<span class="operator">%</span><br />pause<span class="operator">></span>nul</pre>ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-87893080332320450332011-11-09T10:47:00.000-08:002011-11-09T11:00:33.694-08:00lock free intrusive FIFO - Part2Попробовал <a href="http://groups.google.com/group/relacy">Relacy Race Detector</a>. Либа оправдала все ожидания - сходу нашла 1 баг в pop_front:<br /><br /><font face="Courier New" size="+1"><font color="purple">#include</font> <font color="#996600">"windows.h"</font><br /><br /><font color="#9933FF">template</font><<font color="#9933FF">class</font> <font color="green">Type</font>><br /><font color="green">Type</font> * <font color="blue">Exchange</font>(<font color="green">Type</font> ** <font color="blue">ppDestination</font>, <font color="green">Type</font> * <font color="blue">pData</font>)<br />{<br /> <font color="#9933FF">return</font> (<font color="green">Type</font> * )<font color="blue">InterlockedExchangePointer</font>((<font color="green">void</font>**<font color="blue"></font>)ppDestination, pData);<br />}<br /><br /><font color="#9933FF">struct</font> <font color="green">BaseNode</font><br />{<br /> <font color="green">BaseNode</font> * <font color="blue">pNext</font>;<br /><br /> BaseNode()<br /> : pNext(0)<br /> {<br /> }<br /><br /><font color="#339966">private</font>:<br /> BaseNode(<font color="#9933FF">const</font> <font color="green">BaseNode</font> &);<br /> <font color="green">BaseNode</font> & <font color="blue">operator</font> = (<font color="#9933FF">const</font> <font color="green">BaseNode</font> &);<br />};<br /><br /><font color="#9933FF">template</font><<font color="#9933FF">class</font> <font color="green">Type</font>><br /><font color="#9933FF">struct</font> <font color="green">ValueNode</font>:<font color="#339966">public</font> <font color="green">BaseNode</font><br />{<br /> <font color="green">Type</font> <font color="blue">value</font>;<br /><font color="#339966">public</font>:<br /> ValueNode(<font color="green">Type</font> <font color="blue">obj</font> = 0)<br /> : value(obj)<br /> {<br /> }<br /> ~ValueNode()<br /> {<br /> }<br />};<br /><br /><font color="#9933FF">template</font> <<font color="#9933FF">class</font> <font color="green">NodeType</font>><br /><font color="#9933FF">class</font> <font color="green">CList</font><br />{<br /> CList(<font color="#9933FF">const</font> <font color="green">CList</font> &);<br /> <font color="green">CList</font> & <font color="blue">operator</font> = (<font color="#9933FF">const</font> <font color="green">CList</font> &);<br /><br /> <font color="green">BaseNode</font> <font color="blue">m_processingNode</font>;<br /> <font color="green">BaseNode</font> <font color="blue">m_fakeNode</font>;<br /> <font color="green">BaseNode</font> * <font color="blue">m_pFirst</font>;<br /> <font color="green">BaseNode</font> * <font color="blue">m_pLast</font>;<br /><br /> <font color="green">long</font> <font color="blue">m_fakeNodeAdded</font>;<br /><font color="#339966">protected</font>:<br /> <font color="green">void</font> <font color="blue">push_back_impl</font>(<font color="green">BaseNode</font> * <font color="blue">pNode</font>)<br /> {<br /> <font color="green">BaseNode</font> * <font color="blue">pRealLast</font> = Exchange(&m_pLast, pNode);<br /> <font color="brown"><i>// if pRealLast is fakenode, only after that node will be ready to be fetched:</i></font><br /> pRealLast->pNext = pNode;<br /> }<br /><br /> <font color="green">bool</font> <font color="blue">pop_front_impl</font>(<font color="green">BaseNode</font> ** <font color="blue">ppNode</font>)<br /> {<br /> *ppNode = 0;<br /><br /> <font color="#9933FF">while</font>(1)<br /> {<br /> <font color="brown"><i>// take a first node</i></font><br /> <font color="green">BaseNode</font> * <font color="blue">pFirst</font> = Exchange(&m_pFirst, &m_processingNode);<br /> <font color="#9933FF">if</font> (pFirst == &m_processingNode)<br /> <font color="#9933FF">continue</font>;<br /><br /> <font color="brown"><i>// pFirst is valid</i></font><br /> <font color="#9933FF">if</font> (!pFirst->pNext)<br /> {<br /> <font color="brown"><i>// there is no second element</i></font><br /> <font color="#9933FF">if</font> (pFirst == &m_fakeNode)<br /> {<br /> <font color="brown"><i>// cleanup</i></font><br /> Exchange(&m_pFirst, pFirst);<br /> <font color="#9933FF">return</font> <font color="#339966">false</font>;<br /> }<br /><br /> <font color="brown"><i>// push back fake node</i></font><br /> <font color="#9933FF">if</font> (InterlockedIncrement(&m_fakeNodeAdded) != 1)<br /> {<br /> InterlockedDecrement(&m_fakeNodeAdded);<br /><br /> <font color="brown"><i>// cleanup</i></font><br /> Exchange(&m_pFirst, pFirst);<br /> <font color="#9933FF">continue</font>;<br /> }<br /><br /> push_back_impl(&m_fakeNode);<br /><br /> <font color="brown"><i>// still not added</i></font><br /> <font color="#9933FF">if</font> (!pFirst->pNext)<br /> {<br /> <font color="brown"><i>// cleanup</i></font><br /> Exchange(&m_pFirst, pFirst);<br /> <font color="#9933FF">continue</font>;<br /> }<br /> }<br /><br /> *ppNode = pFirst;<br /> Exchange(&m_pFirst, pFirst->pNext);<br /> pFirst->pNext = 0;<br /> <font color="#9933FF">return</font> <font color="#339966">true</font>;<br /> }<br /> }<br /><br /><font color="#339966">public</font>:<br /> CList()<br /> : m_pFirst(0), m_pLast(0), m_fakeNodeAdded(1)<br /> {<br /> m_pFirst = m_pLast = &m_fakeNode;<br /> }<br /><br /> <font color="brown"><i>// interface:</i></font><br /> <font color="green">void</font> <font color="blue">push_back</font>(<font color="green">NodeType</font> * <font color="blue">pNode</font>)<br /> {<br /> push_back_impl(pNode);<br /> }<br /><br /> <font color="green">bool</font> <font color="blue">pop_front</font>(<font color="green">NodeType</font> ** <font color="blue">pNode</font>)<br /> {<br /> <font color="#9933FF">while</font>(1)<br /> {<br /> <font color="green">bool</font> <font color="blue">res</font> = pop_front_impl((<font color="green">BaseNode</font> **)<font color="blue">pNode</font>);<br /> <font color="#9933FF">if</font> (!res)<br /> <font color="#9933FF">return</font> res;<br /><br /> <font color="#9933FF">if</font> (*pNode != &m_fakeNode)<br /> {<br /> <font color="#9933FF">return</font> res;<br /> }<br /> InterlockedDecrement(&m_fakeNodeAdded);<br /> }<br /> }<br />};<br /></font><br />Действительно, довольно дурацкий ляп - pop_front_impl может вернуть &m_fakeNode и во второй раз, нужно вызывать ее в цикле. В остальном все вроде бы ок, больше багов нет.<br />З.Ы. Похоже, фреймворк вправду крут.ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-44796072514833736902011-11-09T07:09:00.000-08:002011-11-09T09:01:14.657-08:00optimization patterns for i386Сабж любезно предоставлен оптимизирующими компиляторами:<br />1)<blockquote>NEG ESI<br />SBB ESI, ESI<br />AND ESI, [ESP+0x844]</blockquote><br />2)<blockquote>NEG EAX<br />SBB EAX, EAX<br />NEG EAX</blockquote><br />Мне понравилось. <br />Кому лень парсить, разгадку помещаю в комменты.ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com3tag:blogger.com,1999:blog-7239389252315107433.post-16117545632437807032011-11-09T03:29:00.000-08:002011-11-09T04:33:15.563-08:00lock free intrusive FIFOВдохновившись постами remark'а с rsdn, решил попробовать сделать что-либо самому в модной сфере lock free, чтобы глубже разобраться в вопросе, так сказать. В результате трудов вечерком создал уродца, который можно использовать, например так:<br /><br /><font face="Courier New" size="+1"><font color="green">CList</font><<font color="green">ValueNode</font><<font color="green">int</font><font color="blue"></font>> > <font color="blue">list</font>;<br />list.push_back(<font color="#9933FF">new</font> <font color="green">ValueNode</font><<font color="green">int</font><font color="blue"></font>>(100500));<br /><font color="green">ValueNode</font><<font color="green">int</font><font color="blue"></font>> * <font color="blue">pNode</font> = 0;<br /><font color="#9933FF">if</font> (list.pop_front(&pNode))<br />{<br /> <font color="#0066CC">std</font>::cout<<pNode->value<<<font color="#996600">"\n"</font>;<br /> <font color="#9933FF">delete</font> pNode;<br />}<br /></font> <br />Теперь задаюсь вопросом, как бы так надежно верифицировать сие чудо и найти в нем ляпы.<br />Приходят в голову следующие варианты:<br />1) написать дикий многопоточный тест и расставить рандомные слипы в самом листе;<br />2) расписать все состояния примитива и переходы между ними.<br />3) использовать <a href="http://www.1024cores.net/home/downloads">чудо тулзу Relacy</a> с 1024cores.net.<br /><br />Поскольку было уже несколько поздно, успел реализовал только пункт 1: все вроде ок, потестил все ветки, ведем себя корректно. Очередь заполняется, очищается, ресурсы чистятся, ABA проблемы вроде бы нет, можно удалять элементы сразу после pop_front, или использовать повторно. <br />Вариант номер № 2 мне особенно близок, правда, есть твердая уверенность, что он может потребовать уйму времени. Интересно посмотреть на Relacy, думаю в ближайшее время таки попробую в ней разобраться.<br /><br />Также интересно было бы попробовать, можно ли данный примитив привести к виду wait-free. В приведенной ниже реализации производители особо не мешают друг другу, но потребители перманентно "толкаются", и могут вхолостую использовать ресурсы процессора, что видимо, не есть гуд.<br /><br />Собственно чудо:<br /><font face="Courier New" size="+1"><font color="purple">#include</font> <font color="#996600">"windows.h"</font><br /><br /><font color="#9933FF">template</font><<font color="#9933FF">class</font> <font color="green">Type</font>><br /><font color="green">Type</font> * <font color="blue">Exchange</font>(<font color="green">Type</font> ** <font color="blue">ppDestination</font>, <font color="green">Type</font> * <font color="blue">pData</font>)<br />{<br /> <font color="#9933FF">return</font> (<font color="green">Type</font> * )<font color="blue">InterlockedExchangePointer</font>((<font color="green">void</font>**<font color="blue"></font>)ppDestination, pData);<br />}<br /><br /><font color="#9933FF">struct</font> <font color="green">BaseNode</font><br />{<br /> <font color="green">BaseNode</font> * <font color="blue">pNext</font>;<br /><br /> BaseNode()<br /> : pNext(0)<br /> {<br /> }<br /><br /><font color="#339966">private</font>:<br /> BaseNode(<font color="#9933FF">const</font> <font color="green">BaseNode</font> &);<br /> <font color="green">BaseNode</font> & <font color="blue">operator</font> = (<font color="#9933FF">const</font> <font color="green">BaseNode</font> &);<br />};<br /><br /><font color="#9933FF">template</font><<font color="#9933FF">class</font> <font color="green">Type</font>><br /><font color="#9933FF">struct</font> <font color="green">ValueNode</font>:<font color="#339966">public</font> <font color="green">BaseNode</font><br />{<br /> <font color="green">Type</font> <font color="blue">value</font>;<br /><font color="#339966">public</font>:<br /> ValueNode(<font color="green">Type</font> <font color="blue">obj</font> = 0)<br /> : value(obj)<br /> {<br /> }<br /> ~ValueNode()<br /> {<br /> }<br />};<br /><br /><font color="#9933FF">template</font> <<font color="#9933FF">class</font> <font color="green">NodeType</font>><br /><font color="#9933FF">class</font> <font color="green">CList</font><br />{<br /> CList(<font color="#9933FF">const</font> <font color="green">CList</font> &);<br /> <font color="green">CList</font> & <font color="blue">operator</font> = (<font color="#9933FF">const</font> <font color="green">CList</font> &);<br /><br /> <font color="green">BaseNode</font> <font color="blue">m_processingNode</font>;<br /> <font color="green">BaseNode</font> <font color="blue">m_fakeNode</font>;<br /> <font color="green">BaseNode</font> * <font color="blue">m_pFirst</font>;<br /> <font color="green">BaseNode</font> * <font color="blue">m_pLast</font>;<br /><br /> <font color="green">long</font> <font color="blue">m_fakeNodeAdded</font>;<br /><font color="#339966">protected</font>:<br /> <font color="green">void</font> <font color="blue">push_back_impl</font>(<font color="green">BaseNode</font> * <font color="blue">pNode</font>)<br /> {<br /> <font color="green">BaseNode</font> * <font color="blue">pRealLast</font> = Exchange(& m_pLast, pNode);<br /><font color="brown"><i> // if pRealLast is fakenode, only after that node will be ready to be fetched:</i></font><br /> pRealLast->pNext = pNode;<br /> }<br /><br /> <font color="green">bool</font> <font color="blue">pop_front_impl</font>(<font color="green">BaseNode</font> ** <font color="blue">ppNode</font>)<br /> {<br /> *ppNode = 0;<br /><br /> <font color="#9933FF">while</font>(1)<br /> {<br /> <font color="brown"><i>// take a first node</i></font><br /> <font color="green">BaseNode</font> * <font color="blue">pFirst</font> = Exchange(&m_pFirst, &m_processingNode);<br /> <font color="#9933FF">if</font> (pFirst == &m_processingNode)<br /> <font color="#9933FF">continue</font>;<br /><br /> <font color="brown"><i>// pFirst is valid</i></font><br /> <font color="#9933FF">if</font> (!pFirst->pNext)<br /> {<br /> <font color="brown"><i>// there is no second element</i></font><br /> <font color="#9933FF">if</font> (pFirst == &m_fakeNode)<br /> {<br /> <font color="brown"><i>// cleanup</i></font><br /> Exchange(&m_pFirst, pFirst);<br /> <font color="#9933FF">return</font> <font color="#339966">false</font>;<br /> }<br /><br /> <font color="brown"><i>// push back fake node</i></font><br /> <font color="#9933FF">if</font> (InterlockedIncrement(&m_fakeNodeAdded) != 1)<br /> {<br /> InterlockedDecrement(&m_fakeNodeAdded);<br /><br /> <font color="brown"><i>// cleanup</i></font><br /> Exchange(&m_pFirst, pFirst);<br /> <font color="#9933FF">continue</font>;<br /> }<br /><br /> push_back_impl(&m_fakeNode);<br /><br /> <font color="brown"><i>// still not added</i></font><br /> <font color="#9933FF">if</font> (!pFirst->pNext)<br /> {<br /> <font color="brown"><i>// cleanup</i></font><br /> Exchange(&m_pFirst, pFirst);<br /> <font color="#9933FF">continue</font>;<br /> }<br /> }<br /><br /> *ppNode = pFirst;<br /> Exchange(&m_pFirst, pFirst->pNext);<br /> pFirst->pNext = 0;<br /> <font color="#9933FF">return</font> <font color="#339966">true</font>;<br /> }<br /> }<br /><br /><font color="#339966">public</font>:<br /> CList()<br /> : m_pFirst(0), m_pLast(0), m_fakeNodeAdded(1)<br /> {<br /> m_pFirst = m_pLast = &m_fakeNode;<br /> }<br /><br /> <font color="brown"><i>// interface:</i></font><br /> <font color="green">void</font> <font color="blue">push_back</font>(<font color="green">NodeType</font> * <font color="blue">pNode</font>)<br /> {<br /> push_back_impl(pNode);<br /> }<br /><br /> <font color="green">bool</font> <font color="blue">pop_front</font>(<font color="green">NodeType</font> ** <font color="blue">pNode</font>)<br /> {<br /> <font color="green">bool</font> <font color="blue">res</font> = pop_front_impl((<font color="green">BaseNode</font> **)<font color="blue">pNode</font>);<br /> <font color="#9933FF">if</font> (!res)<br /> <font color="#9933FF">return</font> res;<br /><br /> <font color="#9933FF">if</font> (*pNode == &m_fakeNode)<br /> {<br /> InterlockedDecrement(&m_fakeNodeAdded);<br /> <font color="#9933FF">return</font> pop_front_impl((<font color="green">BaseNode</font> **)<font color="blue">pNode</font>);<br /> }<br /> <font color="#9933FF">return</font> res;<br /> }<br />};<br /></font>ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-73212030478281616152011-08-17T14:56:00.000-07:002011-08-17T16:26:41.194-07:00Новое в Vista's IOCPВ Vista к IOCP наконец то добавили штуку, которую логично было бы добавить с самого начала: возможность отключать ненужные нотификации успешных завершений с помощью функции <a href="http://msdn.microsoft.com/en-us/library/aa365538%28v=vs.85%29.aspx">SetFileCompletionNotificationModes</a>. Просто выставляешь флаг FILE_SKIP_COMPLETION_PORT_ON_SUCCESS на сокет и все. Теперь если асинхронная функция выполнилась успешно, можно сразу же освобождать используемые ей ресурсы и инициировать новый запрос, все как и в нормальном асинхронном IO без использования портов завершения.
<br />Интересно, что некоторые функции, типа AcceptEx, и так всегда обладали таким поведением.
<br />Поскольку аналога GetFileCompletionNotificationModes в МСДН не наблюдается, пришлось из любопытства написать свой:
<br />
<br /><font face="Courier New" size="+1"><font color="#9933FF">namespace</font> <font color="green">kernel</font>
<br />{
<br /><font color="#9933FF">typedef</font> <font color="green">LONG</font> <font color="blue">NTSTATUS</font>;
<br /><font color="brown"><i>//---------------------------------------</i></font>
<br /><font color="#9933FF">typedef</font> <font color="#9933FF">struct</font> <font color="green">_IO_STATUS_BLOCK</font>
<br />{
<br /> union
<br /> {
<br /> <font color="green">NTSTATUS</font> <font color="blue">Status</font>;
<br /> <font color="green">PVOID</font> <font color="blue">Pointer</font>;
<br /> };
<br /> <font color="green">ULONG_PTR</font> <font color="blue">Information</font>;
<br />}IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
<br /><font color="brown"><i>//---------------------------------------</i></font>
<br /><font color="#9933FF">typedef</font>
<br />NTSYSAPI
<br /><font color="green">DWORD</font>
<br />(<font color="green">NTAPI</font> * <font color="blue">RtlNtStatusToDosErrorPtr</font>)(<font color="green">IN</font> <font color="green">NTSTATUS</font> <font color="blue">status</font>);
<br />
<br /><font color="#9933FF">typedef</font>
<br />NTSYSAPI
<br /><font color="green">NTSTATUS</font>
<br />(<font color="green">NTAPI</font> * <font color="blue">NtQueryInformationFilePtr</font>)(<font color="green">IN</font> <font color="green">HANDLE</font> <font color="blue">FileHandle</font>,
<br /> <font color="green">OUT</font> <font color="green">PIO_STATUS_BLOCK</font> <font color="blue">IoStatusBlock</font>,
<br /> <font color="green">OUT</font> <font color="green">PVOID</font> <font color="blue">FileInformation</font>,
<br /> <font color="green">IN</font> <font color="green">ULONG</font> <font color="blue">Length</font>,
<br /> <font color="green">IN</font> <font color="green">DWORD</font> <font color="blue">FileInformationClass</font>);
<br />}
<br /><font color="#9933FF">class</font> <font color="green">CUndocumentedNtdll</font>
<br />{
<br /> <font color="green">HMODULE</font> <font color="blue">m_hNtDll</font>;
<br /> <font color="#0066CC">kernel</font>::<font color="green">NtQueryInformationFilePtr</font> <font color="blue">m_pNtQueryInformationFile</font>;
<br /> <font color="#0066CC">kernel</font>::<font color="green">RtlNtStatusToDosErrorPtr</font> <font color="blue">m_pRtlNtStatusToDosError</font>;
<br />
<br /><font color="#339966">public</font>:
<br /> CUndocumentedNtdll()
<br /> {
<br /> m_hNtDll = GetModuleHandle(L<font color="#996600">"ntdll.dll"</font>);
<br /> m_pNtQueryInformationFile =
<br /> (<font color="#0066CC">kernel</font>::NtQueryInformationFilePtr)
<br /> GetProcAddress(m_hNtDll, <font color="#996600">"NtQueryInformationFile"</font>);
<br />
<br /> m_pRtlNtStatusToDosError =
<br /> (<font color="#0066CC">kernel</font>::RtlNtStatusToDosErrorPtr)
<br /> GetProcAddress(m_hNtDll, <font color="#996600">"RtlNtStatusToDosError"</font>);
<br /> }
<br />
<br /> <font color="green">ULONG</font> <font color="blue">GetFileCompletionNotificationModes</font>(<font color="green">HANDLE</font> <font color="blue">hFile</font>,
<br /> <font color="green">ULONG</font> * <font color="blue">pFlags</font>)
<br /> {
<br /> <font color="#9933FF">if</font>(!m_pNtQueryInformationFile || !m_pRtlNtStatusToDosError)
<br /> <font color="#9933FF">return</font> ERROR_NOT_SUPPORTED;
<br />
<br /> <font color="green">ULONG</font> <font color="blue">flags</font> = 0;
<br /> <font color="#0066CC">kernel</font>::<font color="green">IO_STATUS_BLOCK</font> <font color="blue">statusBlock</font>;
<br /> <font color="#0066CC">kernel</font>::<font color="green">NTSTATUS</font> <font color="blue">status</font> = m_pNtQueryInformationFile(hFile, &statusBlock, pFlags, 4, 0x29);
<br /> <font color="#9933FF">if</font> (<font color="green">status</font> >= 0)
<br /> <font color="#9933FF">return</font> <font color="blue">NO_ERROR</font>;
<br /> <font color="#9933FF">return</font> m_pRtlNtStatusToDosError(status);
<br /> }
<br />}; ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-72154174400082107612011-07-22T13:03:00.000-07:002011-07-22T13:52:19.804-07:00А тем временем на фронте дизассемблированияНовости проекта <a href="https://diana-dasm.svn.sourceforge.net/svnroot/diana-dasm">Diana-Dasm</a>:<br /><span style="font-weight:bold;">1)</span> на текущий момент поддерживается 438 команд (734 опкода): всяческие i386, amd64, fpu, sse, mmx и прочая, прочая, прочая;<br /><span style="font-weight:bold;">2)</span> доступна альфа версия виртуального процессора для i386. Вот этот кусок кода выводит 100 раз фразу hello, world:<br /><table width = "100%" bgcolor="#F2F2F2"><tr><td><pre><font color="#000000">#include</font> <font color="#006400">"test_win32_common.h"</font><br /><br /><font color="#0000FF">static</font> <font color="#0000FF">char</font> <font color="#000000">g_stack</font><font color="#C8003C">[</font><font color="#40B440">1024</font><font color="#C8003C">*</font><font color="#40B440">1024</font><font color="#C8003C">];</font><br /><font color="#0000FF">static</font> <font color="#0000FF">void</font> <font color="#C8003C">*</font> <font color="#000000">g_oldESP</font> <font color="#C8003C">=</font> <font color="#40B440">0</font><font color="#C8003C">;</font><br /><br /><font color="#0000FF">void</font> <font color="#0000FF">__cdecl</font> <font color="#000000">test_function</font><font color="#C8003C">()</font><br /><font color="#C8003C">{</font><br /> <font color="#0000FF">for</font><font color="#C8003C">(</font><font color="#0000FF">int</font> <font color="#000000">i</font> <font color="#C8003C">=</font> <font color="#40B440">0</font><font color="#C8003C">;</font> <font color="#000000">i</font><font color="#C8003C"><</font> <font color="#40B440">100</font><font color="#C8003C">;</font> <font color="#C8003C">++</font><font color="#000000">i</font><font color="#C8003C">)</font><br /> <font color="#000000">std</font><font color="#C8003C">::</font><font color="#000000">cout</font><font color="#C8003C"><<</font><font color="#006400">"hello, world!"</font><font color="#C8003C">;</font><br /><font color="#C8003C">}</font><br /><br /><font color="#0000FF">void</font> <font color="#000000">test_processor2</font><font color="#C8003C">()</font><br /><font color="#C8003C">{</font><br /> <i><font color="#808080">// create processor </font></i><br /> <font color="#000000">DianaWin32Processor</font> <font color="#000000">proc</font><font color="#C8003C">;</font><br /><br /> <font color="#000000">TEST_ASSERT</font><font color="#C8003C">(</font><font color="#000000">DianaWin32Processor_Init</font><font color="#C8003C">(&</font><font color="#000000">proc</font><font color="#C8003C">)==</font><font color="#000000">DI_SUCCESS</font><font color="#C8003C">);</font><br /> <br /> <i><font color="#808080">// load current thread context to the virtual processor</font></i><br /> <font color="#000000">DianaProcessor</font> <font color="#C8003C">*</font> <font color="#000000">pCallContext</font> <font color="#C8003C">=</font> <font color="#C8003C">&</font><font color="#000000">proc</font><font color="#C8003C">.</font><font color="#000000">m_processor</font><font color="#C8003C">;</font><br /> <font color="#000000">DianaProcessor_LoadLiveContext32</font><font color="#C8003C">(</font><font color="#000000">pCallContext</font><font color="#C8003C">);</font><br /><br /> <i><font color="#808080">// set new EIP</font></i><br /> <font color="#000000">DI_JUMP_TO_RIP</font><font color="#C8003C">((</font><font color="#000000">OPERAND_SIZE</font><font color="#C8003C">)(</font><font color="#0000FF">void</font><font color="#C8003C">*)</font><font color="#000000">test_function</font><font color="#C8003C">);</font><br /><br /> <i><font color="#808080">// and new stack</font></i><br /> <font color="#000000">SET_REG_RSP</font><font color="#C8003C">((</font><font color="#000000">OPERAND_SIZE</font><font color="#C8003C">)</font><font color="#000000">g_stack</font> <font color="#C8003C">+</font> <font color="#0000FF">sizeof</font><font color="#C8003C">(</font><font color="#000000">g_stack</font><font color="#C8003C">));</font><br /> <br /> <i><font color="#808080">// push return code </font></i><br /> <font color="#000000">OPERAND_SIZE</font> <font color="#000000">exitOp</font> <font color="#C8003C">=</font> <b><font color="#40B440">0x</font></b><font color="#40B440">87654321</font><font color="#C8003C">;</font><br /> <font color="#000000">diana_internal_push</font><font color="#C8003C">(</font><font color="#000000">pCallContext</font><font color="#C8003C">,</font> <font color="#C8003C">&</font><font color="#000000">exitOp</font><font color="#C8003C">);</font><br /><br /> <i><font color="#808080">// execute function!</font></i><br /> <font color="#0000FF">for</font><font color="#C8003C">(</font><font color="#0000FF">int</font> <font color="#000000">i</font> <font color="#C8003C">=</font> <font color="#40B440">0</font><font color="#C8003C">;</font> <font color="#C8003C">;</font> <font color="#C8003C">++</font><font color="#000000">i</font><font color="#C8003C">)</font><br /> <font color="#C8003C">{</font><br /> <font color="#000000">OPERAND_SIZE</font> <font color="#000000">rip</font> <font color="#C8003C">=</font> <font color="#000000">GET_REG_RIP</font><font color="#C8003C">;</font><br /> <font color="#0000FF">if</font> <font color="#C8003C">(</font><font color="#000000">rip</font> <font color="#C8003C">==</font> <font color="#000000">exitOp</font><font color="#C8003C">)</font><br /> <font color="#0000FF">break</font><font color="#C8003C">;</font><br /><br /> <font color="#000000">TEST_ASSERT</font><font color="#C8003C">(</font><font color="#000000">DianaProcessor_ExecOnce</font><font color="#C8003C">(</font><font color="#000000">pCallContext</font><font color="#C8003C">)</font> <font color="#C8003C">==</font> <font color="#000000">DI_SUCCESS</font><font color="#C8003C">);</font><br /> <font color="#C8003C">}</font><br /><font color="#C8003C">}</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td></tr></table><br />Я страшно доволен<br /><span style="font-weight:bold;">3) </span>первоначальные принипы проекта все соблюдаются: только pure C, никаких требований к рантайму, все на стримах, все легко использовать в ядре, лицензия BSDligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com2tag:blogger.com,1999:blog-7239389252315107433.post-25439564359374465822011-04-03T10:53:00.000-07:002011-04-03T11:22:15.425-07:00Способ передачи була по ntkernl-овскиВ семерке оригинально реализован сабж. Вот так выглядит экспортируемая функция RtlPrefetchMemoryNonTemporal в памяти:<table width = "100%" bgcolor="#F2F2F2"><tr><td><pre><font color="#000000">kd</font><font color="#C8003C">></font> <font color="#000000">u</font> <b><font color="#40B440">0x</font></b><font color="#40B440">82603000</font><font color="#C8003C">+</font><font color="#000000">FB9A</font><font color="#C8003C">*</font><font color="#40B440">4</font><br /><font color="#000000">nt</font><font color="#C8003C">!</font><font color="#000000">RtlPrefetchMemoryNonTemporal</font><font color="#C8003C">:</font><br /><font color="#40B440">82641</font><b><font color="#40B440">e</font></b><font color="#40B440">68</font> <font color="#40B440">90</font> <font color="#000000">nop</font><br /><font color="#40B440">82641</font><b><font color="#40B440">e</font></b><font color="#40B440">69</font> <font color="#000000">a1b4aa7282</font> <font color="#000000">mov</font> <font color="#000000">eax</font><font color="#C8003C">,[</font><font color="#000000">nt</font><font color="#C8003C">!</font><font color="#000000">KePrefetchNTAGranularity</font> <font color="#C8003C">(</font><font color="#40B440">8272</font><font color="#000000">aab4</font><font color="#C8003C">)]</font><br /><font color="#40B440">82641</font><b><font color="#40B440">e</font></b><font color="#40B440">6</font><font color="#000000">e</font> <font color="#40B440">0</font><font color="#000000">f184100</font> <font color="#000000">prefetchnta</font> <font color="#000000">byte</font> <font color="#000000">ptr</font> <font color="#C8003C">[</font><font color="#000000">ecx</font><font color="#C8003C">]</font><br /><font color="#40B440">82641</font><b><font color="#40B440">e</font></b><font color="#40B440">72</font> <b><font color="#40B440">0</font></b><font color="#40B440">3</font><font color="#000000">c8</font> <font color="#000000">add</font> <font color="#000000">ecx</font><font color="#C8003C">,</font><font color="#000000">eax</font><br /><font color="#40B440">82641</font><b><font color="#40B440">e</font></b><font color="#40B440">74</font> <font color="#40B440">2</font><font color="#000000">bd0</font> <font color="#000000">sub</font> <font color="#000000">edx</font><font color="#C8003C">,</font><font color="#000000">eax</font><br /><font color="#40B440">82641</font><b><font color="#40B440">e</font></b><font color="#40B440">76</font> <font color="#40B440">77</font><font color="#000000">f6</font> <font color="#000000">ja</font> <font color="#000000">nt</font><font color="#C8003C">!</font><font color="#000000">RtlPrefetchMemoryNonTemporal</font><font color="#C8003C">+</font><b><font color="#40B440">0x</font></b><font color="#40B440">6</font> <font color="#C8003C">(</font><font color="#40B440">82641</font><b><font color="#40B440">e</font></b><font color="#40B440">6</font><font color="#000000">e</font><font color="#C8003C">)</font><br /><font color="#40B440">82641</font><b><font color="#40B440">e</font></b><font color="#40B440">78</font> <font color="#000000">c3</font> <font color="#000000">ret</font><br /><font color="#40B440">82641</font><b><font color="#40B440">e</font></b><font color="#40B440">79</font> <font color="#40B440">90</font> <font color="#000000">nop</font><br /></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272"></font></a></i></b></td></tr></table>А вот так она же выглядит на диске:<br /><table width = "100%" bgcolor="#F2F2F2"><tr><td><pre><font color="#000000">kd</font><font color="#C8003C">></font> <font color="#000000">u</font> <b><font color="#40B440">0x</font></b><font color="#40B440">00050800</font><font color="#C8003C">+</font><font color="#000000">FB9A</font><font color="#C8003C">*</font><font color="#40B440">4</font><br /><b><font color="#40B440">0</font></b><font color="#40B440">008</font><font color="#000000">f668</font> <font color="#000000">c3</font> <font color="#000000">ret</font><br /><b><font color="#40B440">0</font></b><font color="#40B440">008</font><font color="#000000">f669</font> <font color="#000000">a1b4aa7282</font> <font color="#000000">mov</font> <font color="#000000">eax</font><font color="#C8003C">,[</font><font color="#000000">nt</font><font color="#C8003C">!</font><font color="#000000">KePrefetchNTAGranularity</font> <font color="#C8003C">(</font><font color="#40B440">8272</font><font color="#000000">aab4</font><font color="#C8003C">)]</font><br /><b><font color="#40B440">0</font></b><font color="#40B440">008</font><font color="#000000">f66e</font> <font color="#40B440">0</font><font color="#000000">f184100</font> <font color="#000000">prefetchnta</font> <font color="#000000">byte</font> <font color="#000000">ptr</font> <font color="#C8003C">[</font><font color="#000000">ecx</font><font color="#C8003C">]</font><br /><b><font color="#40B440">0</font></b><font color="#40B440">008</font><font color="#000000">f672</font> <b><font color="#40B440">0</font></b><font color="#40B440">3</font><font color="#000000">c8</font> <font color="#000000">add</font> <font color="#000000">ecx</font><font color="#C8003C">,</font><font color="#000000">eax</font><br /><b><font color="#40B440">0</font></b><font color="#40B440">008</font><font color="#000000">f674</font> <font color="#40B440">2</font><font color="#000000">bd0</font> <font color="#000000">sub</font> <font color="#000000">edx</font><font color="#C8003C">,</font><font color="#000000">eax</font><br /><b><font color="#40B440">0</font></b><font color="#40B440">008</font><font color="#000000">f676</font> <font color="#40B440">77</font><font color="#000000">f6</font> <font color="#000000">ja</font> <b><font color="#40B440">0</font></b><font color="#40B440">008</font><font color="#000000">f66e</font><br /><b><font color="#40B440">0</font></b><font color="#40B440">008</font><font color="#000000">f678</font> <font color="#000000">c3</font> <font color="#000000">ret</font><br /><b><font color="#40B440">0</font></b><font color="#40B440">008</font><font color="#000000">f679</font> <font color="#40B440">90</font> <font color="#000000">nop</font><br /></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td></tr></table><br />WRK объясняет, откуда взялось отличие - ntldr таким чудесным образом передает знание о свойствах процессора непосредственно ядру. Т.е. он делает что-то в духе:<br /><table width = "100%" bgcolor="#F2F2F2"><tr><td><pre><font color="#C8003C">*(</font><font color="#0000FF">char</font><font color="#C8003C">*)</font><font color="#000000">GetProcAddr</font><font color="#C8003C">(</font><font color="#000000">ntosBase</font><font color="#C8003C">,</font> <font color="#006400">"RtlPrefetchMemoryNonTemporal"</font><font color="#C8003C">)</font> <font color="#C8003C">=</font> <b><font color="#40B440">0x</font></b><font color="#40B440">C3</font><br /></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272"></font></a></i></b></td></tr></table>Как по мне, через именованную секцию данных было бы красивее, но и так тоже ничегоligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-50635071103150226412011-02-10T04:31:00.000-08:002011-02-10T04:34:17.361-08:00дизассемблер в x64Рекомендую позитив: <a href="http://govnokod.ru/2502">http://govnokod.ru/2502</a>.<br />Нужно сказать, что файл amd64\decode.c из WRK прекрасен от начала и до конца.ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-13335026428122597632011-02-09T14:17:00.000-08:002011-02-09T14:37:54.721-08:00что странное о InterlockedCompareExchangeПрекрасное рядом:<br /><blockquote>Interlocked operations cannot be used on non-cached memory.</blockquote> <a href="http://msdn.microsoft.com/en-us/library/ff547853%28v=vs.85%29.aspx">в DDK</a>.<br /><br />Как бы так интерпретировать эту дивную фразу? <br />Ересь какая-то.<br /><br />З.Ы. Кстати, видели в семерке? сплошное локфри кругом - subj классно ложится на ps-овские ЗарегатьМегаКеллбэк, УдалитьМегаКеллбэк, ВызватьВсеКеллбеки. Массив + CAS. Красота.ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com2tag:blogger.com,1999:blog-7239389252315107433.post-52570021928340238662010-10-03T05:27:00.000-07:002010-10-03T05:41:18.522-07:00libcurl + FTP + NAT = LOVE и адов угарЯ конечно понимаю, что FTP - это совсем не тот протокол, от которого нужно было бы ожидать нормальной производительности в случае вычитки большого количества небольших частей файлов.<br /><br />Но его реализация в сабже добавляет масла в огонь: чудесный код из дебрей libcurl, представленный ниже, может ждать до минуты после каждой успешной операции (!!!!!) пока Control Connection не подтвердит что закачка прошла успешно, или не отвалится:<table width = "100%" bgcolor="#F2F2F2"><tr><td><pre><b><font color="#000000">\</font></b><font color="#000000">libcurl</font><b><font color="#000000">\</font></b><font color="#000000">curl</font><font color="#C8003C">-</font><font color="#40B440">7.20.1</font><b><font color="#000000">\</font></b><font color="#000000">lib</font><b><font color="#000000">\</font></b><font color="#000000">ftp</font><font color="#C8003C">.</font><font color="#000000">c</font><br /><font color="#0000FF">static</font> <font color="#000000">CURLcode</font> <font color="#000000">ftp_done</font><font color="#C8003C">(</font><font color="#0000FF">struct</font> <font color="#000000">connectdata</font> <font color="#C8003C">*</font><font color="#000000">conn</font><font color="#C8003C">,</font> <font color="#000000">CURLcode</font> <font color="#000000">status</font><font color="#C8003C">,</font><br /> <font color="#0000FF">bool</font> <font color="#000000">premature</font><font color="#C8003C">)</font><br /><font color="#C8003C">{</font><br /> <i><font color="#808080">//..</font></i><br /> <font color="#0000FF">if</font><font color="#C8003C">((</font><font color="#000000">ftp</font><font color="#C8003C">-></font><font color="#000000">transfer</font> <font color="#C8003C">==</font> <font color="#000000">FTPTRANSFER_BODY</font><font color="#C8003C">)</font> <font color="#C8003C">&&</font> <font color="#000000">ftpc</font><font color="#C8003C">-></font><font color="#000000">ctl_valid</font> <font color="#C8003C">&&</font><br /> <font color="#000000">pp</font><font color="#C8003C">-></font><font color="#000000">pending_resp</font> <font color="#C8003C">&&</font> <font color="#C8003C">!</font><font color="#000000">premature</font><font color="#C8003C">)</font> <font color="#C8003C">{</font><br /> <i><font color="#808080">/*<br /> * Let's see what the server says about the transfer we just performed,<br /> * but lower the timeout as sometimes this connection has died while the<br /> * data has been transfered. This happens when doing through NATs etc that<br /> * abandon old silent connections.<br /> */</font></i><br /> <font color="#0000FF">long</font> <font color="#000000">old_time</font> <font color="#C8003C">=</font> <font color="#000000">pp</font><font color="#C8003C">-></font><font color="#000000">response_time</font><font color="#C8003C">;</font><br /><br /> <font color="#000000">pp</font><font color="#C8003C">-></font><font color="#000000">response_time</font> <font color="#C8003C">=</font> <font color="#40B440">60</font><font color="#C8003C">*</font><font color="#40B440">1000</font><font color="#C8003C">;</font> <i><font color="#808080">/* give it only a minute for now */</font></i> <i><font color="#808080">// WTF here</font></i><br /> <font color="#000000">pp</font><font color="#C8003C">-></font><font color="#000000">response</font> <font color="#C8003C">=</font> <font color="#000000">Curl_tvnow</font><font color="#C8003C">();</font> <i><font color="#808080">/* timeout relative now */</font></i><br /><br /> <font color="#000000">result</font> <font color="#C8003C">=</font> <font color="#000000">Curl_GetFTPResponse</font><font color="#C8003C">(&</font><font color="#000000">nread</font><font color="#C8003C">,</font> <font color="#000000">conn</font><font color="#C8003C">,</font> <font color="#C8003C">&</font><font color="#000000">ftpcode</font><font color="#C8003C">);</font><br /><br /> <font color="#000000">pp</font><font color="#C8003C">-></font><font color="#000000">response_time</font> <font color="#C8003C">=</font> <font color="#000000">old_time</font><font color="#C8003C">;</font> <i><font color="#808080">/* set this back to previous value */</font></i><br /><br /> <font color="#0000FF">if</font><font color="#C8003C">(!</font><font color="#000000">nread</font> <font color="#C8003C">&&</font> <font color="#C8003C">(</font><font color="#000000">CURLE_OPERATION_TIMEDOUT</font> <font color="#C8003C">==</font> <font color="#000000">result</font><font color="#C8003C">))</font> <font color="#C8003C">{</font><br /> <font color="#000000">failf</font><font color="#C8003C">(</font><font color="#000000">data</font><font color="#C8003C">,</font> <font color="#006400">"control connection looks dead"</font><font color="#C8003C">);</font><br /> <font color="#000000">ftpc</font><font color="#C8003C">-></font><font color="#000000">ctl_valid</font> <font color="#C8003C">=</font> <font color="#000000">FALSE</font><font color="#C8003C">;</font> <i><font color="#808080">/* mark control connection as bad */</font></i><br /> <font color="#000000">conn</font><font color="#C8003C">-></font><font color="#000000">bits</font><font color="#C8003C">.</font><font color="#000000">close</font> <font color="#C8003C">=</font> <font color="#000000">TRUE</font><font color="#C8003C">;</font> <i><font color="#808080">/* mark for closure */</font></i><br /> <font color="#C8003C">}</font><br /><font color="#C8003C">}</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td></tr></table><br />Не правда ли, это прекрасно?<br /><br />Как раз сейчас наблюдаю интересную картину, когда Сontrol Connection (не без помощи сил <span style="text-decoration: line-through;">Тьмы</span> NAT) на определенных файлах отваливается ровно через раз, а я получаю минутное ожидание на каждый второй read. Особенно смешно, что сам read проходит практически мгновенно.<br /><br />Конечно, установка злостных значений для SIO_KEEPALIVE_VALS немного улучшает ситуацию, CURL оказывается не выставляет keep-alives вообще; но все равно, некий батхерт остается.<br /><br />Трагизм ситуации заключается еще и в том, что это "ожидание подтверждения" вобщем то мне совершено не нужно - данные уже вычитаны, посчитаны и находятся в локальном буфере, можно было бы их уже и использовать.<br /><br />П.С А это всё select-based схема, в случае, если бы CURL базировалась на IOCP, такого архитектурного косяка впринципе не могло бы существовать<br /><br />П.П.С Вообще, мне libcurl скорее нравится чем нет, если бы не такие скелеты в шкафу, да еще если бы у нее на уровне дизайна была бы предусмотрена асбтракция "Connection", была бы чудо библиотекаligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-74510498934400300072010-09-07T05:54:00.000-07:002010-09-10T05:04:47.340-07:00GetLastError and side effectsПредставим себе, что у нас в проекте есть такое чудо:<table width = "100%" bgcolor="#F2F2F2"><tr><td><pre><font color="#000000">hSomething</font> <font color="#C8003C">=</font> <font color="#C8003C">::</font><font color="#000000">CreateSomething</font><font color="#C8003C">(...);</font><br /><font color="#0000FF">if</font> <font color="#C8003C">(!</font><font color="#000000">hSomething</font><font color="#C8003C">)</font><br /> <font color="#0000FF">throw</font> <font color="#000000">std</font><font color="#C8003C">::</font><font color="#000000">runtime_error</font><font color="#C8003C">(</font><font color="#006400">"Cannot create something: "</font> <font color="#C8003C">+</font> <font color="#000000">some_utils</font><font color="#C8003C">::</font><font color="#000000">FormatError</font><font color="#C8003C">(</font><font color="#000000">GetLastError</font><font color="#C8003C">()));</font> <font color="#C8003C">*</font><br /></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td></tr></table>Какие проблемы могут быть с этим кодом?<br /><br />Ну, о том, что вообще-то имеет смысл сообщать об ошибке в виде кода ошибки, а не в виде невнятной строки (непонятно на каком языке) речь даже не идет. Представим, что нам очень нужно записать куда-нибудь именно строку, т.е. на месте throw std::runtime_error вполне мог бы быть некий LogLog.<br /><br />Возвращаемся к коду. Если бы я увидел такой код на review, я посчитал бы его некорректным, аргументируя тем, что компилятор вполне может расставить вызовы функций в следующей последовательности:<br /><table width = "100%" bgcolor="#F2F2F2"><tr><td><pre><font color="#000000">call</font> <font color="#000000">std</font><font color="#C8003C">::</font><font color="#000000">basic_string</font><font color="#C8003C"><</font><font color="#0000FF">char</font><font color="#C8003C">>::</font><font color="#000000">std</font><font color="#C8003C">::</font><font color="#000000">basic_string</font><font color="#C8003C"><</font><font color="#0000FF">char</font><font color="#C8003C">>(</font><font color="#0000FF">const</font> <font color="#0000FF">char</font> <font color="#C8003C">*)</font><br /><font color="#C8003C">....</font><br /><font color="#000000">call</font> <font color="#000000">GetLastError</font><br /><font color="#000000">call</font> <font color="#000000">some_utils</font><font color="#C8003C">::</font><font color="#000000">FormatError</font><br /><font color="#000000">call</font> <font color="#000000">_CxxThrowException</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td></tr></table><br /><br />Не трудно представить, к чему это приведет, учитывая, что конструктор строки вполне может вызвать malloc, а значит и HeapAlloc. (Который пренепременно вызовет SetLastError(NO_ERROR) в случае успешного выделения памяти)<br /><br />Поэтому, я сам всегда старался писать так, чтобы исключить возможные side effects:<br /><table width = "100%" bgcolor="#F2F2F2"><tr><td><pre><font color="#000000">hSomething</font> <font color="#C8003C">=</font> <font color="#C8003C">::</font><font color="#000000">CreateSomething</font><font color="#C8003C">(...);</font><br /><font color="#0000FF">if</font> <font color="#C8003C">(!</font><font color="#000000">hSomething</font><font color="#C8003C">)</font><br /><font color="#C8003C">{</font><br /> <font color="#000000">DWORD</font> <font color="#000000">dwError</font> <font color="#C8003C">=</font> <font color="#000000">GetLastError</font><font color="#C8003C">();</font><br /> <font color="#0000FF">throw</font> <font color="#000000">std</font><font color="#C8003C">::</font><font color="#000000">runtime_error</font><font color="#C8003C">(</font><font color="#006400">"Cannot create something: "</font> <font color="#C8003C">+</font> <font color="#000000">some_utils</font><font color="#C8003C">::</font><font color="#000000">FormatError</font><font color="#C8003C">(</font><font color="#000000">dwError</font><font color="#C8003C">));</font><br /><font color="#C8003C">}</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td></tr></table><br />....<br />До тех пор, пока, совершенно случайно, не наткнулся на тот факт, что утверждение<blockquote>... HeapAlloc. Который пренепременно вызовет SetLastError(NO_ERROR) в случае успешного выделения памяти.<br /></blockquote>не является истинным.<br /><br />MSDN <a href = "http://msdn.microsoft.com/en-us/library/aa366597(VS.85).aspx">утверждает</a>, что HeapAlloc вообще никогда не зовет SetLastError, а HeapReAlloc зовет ее только в случае неудачного выделения памяти. Тестами подтверждается. <br /><br />Да и вообще, как выяснилось, количество API функций, которые устанавливают SetLastError(NO_ERROR) по поводу и без повода не так уж и велико: сюда входит файловое API, функции работы с ini файлами, с ресурсами, GlobalUnlock/LocalUnlock, и, почему-то, EqualSid(???). Все.<br /><br />Поэтому, перезатереть значение NtCurrentTeb()->LastErrorValue в нашем случае - некому. Минус одна старая параноидальная привычка (когда-то я таки обжегся на таких сайд эффектах, но код уже и не припомню).ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com1tag:blogger.com,1999:blog-7239389252315107433.post-68278355903151943522010-08-17T04:26:00.000-07:002010-08-17T23:25:06.949-07:00DLL_PROCESS_DETACH и С++При разработке dll приходится мириться с тем фактом, что как правило программы прекращают свое существование, используя для этого вызов функции ExitProcess. Причем многие из них могут вызывать эту функцию в тот момент, когда ваша dll еще загружена. <br /><br />Функция ExitProcess, в свою очередь, известна тем, что сначала останавливает все потоки, кроме вызывающего (используя NtTerminateProcess), а потом вызывает EntryPoint для всех dll с флагом DLL_PROCESS_DETACH. В С++ обычно точка входа называется DllMainCRTStartup. DllMainCRTStartup вызывает функцию DllMain и после нее все деструкторы глобальных объектов, расположенных в DLL. <br /><br />Разумеется, что после удаления некоторого количества потоков, отличного от нуля, выполнение любого кода становится чрезвычайно опасным мероприятием, чреватым дедлоками и крешами. Некоторые комрады также утверждают, что после вызова ExitProcess перестают работать критические секции, и случаются многие другие <a href=http://blogs.msdn.com/b/oldnewthing/archive/2007/05/03/2383346.aspx>Ужасные Вещи</a>.<br /><br />Поэтому, популярный паттерн использования DLL_PROCESS_DETACH выглядит так:<br /><table width = "100%" bgcolor="#F2F2F2"><tr><td><pre><font color="#000000">BOOL</font> <font color="#000000">WINAPI</font> <font color="#000000">DllMain</font><font color="#C8003C">(</font><br /> <font color="#000000">IN</font> <font color="#000000">HINSTANCE</font> <font color="#000000">hinstDll</font><font color="#C8003C">,</font><br /> <font color="#000000">IN</font> <font color="#000000">DWORD</font><font color="#000000">fdwReason</font><font color="#C8003C">,</font><br /> <font color="#000000">LPVOID</font> <font color="#000000">lpvReserved</font><br /> <font color="#C8003C">)</font><br /><font color="#C8003C">{</font><br /> <font color="#C8003C">....</font><br /><br /> <font color="#0000FF">case</font> <font color="#000000">DLL_PROCESS_DETACH</font><font color="#C8003C">:</font><br /><br /> <font color="#0000FF">if</font><font color="#C8003C">(</font> <font color="#000000">lpvReserved</font> <font color="#C8003C">==</font> <font color="#000000">NULL</font> <font color="#C8003C">)</font><br /> <font color="#C8003C">{</font><br /> <i><font color="#808080">// FreeLibrary is called and it is safe to free resources</font></i><br /> <i><font color="#808080">// All critical sections and other primitives should work fine</font></i><br /> <font color="#000000">FreeResources1</font><font color="#C8003C">();</font><br /> <font color="#000000">FreeResources2</font><font color="#C8003C">();</font><br /> <font color="#C8003C">...</font><br /> <font color="#000000">FreeResourcesN</font><font color="#C8003C">();</font><br /> <font color="#C8003C">}</font><br /> <i><font color="#808080">// else { ExitProcess is called, process is terminating, so do nothing }</font></i><br /> <font color="#0000FF">break</font><font color="#C8003C">;</font><br /><font color="#C8003C">}</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td></tr></table><br />Параметр lpvReserved описан в MSDN следующим образом:<br /><blockquote>If fdwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if FreeLibrary has been called or the DLL load failed and non-NULL if the process is terminating.<br />(с) MSDN </blockquote><br /><br />В случае использования С++, код нашей идеальной Dll должен выглядеть так:<table width = "100%" bgcolor="#F2F2F2"><tr><td><pre><font color="#0000FF">static</font> <font color="#000000">std</font><font color="#C8003C">::</font><font color="#000000">auto_ptr</font><font color="#C8003C"><</font><font color="#000000">CMyDll</font><font color="#C8003C">></font> <font color="#000000">g_myDll</font><font color="#C8003C">;</font><br /><br /><font color="#000000">BOOL</font> <font color="#000000">WINAPI</font> <font color="#000000">DllMain</font><font color="#C8003C">(</font><br /> <font color="#000000">IN</font> <font color="#000000">HINSTANCE</font> <font color="#000000">hinstDll</font><font color="#C8003C">,</font><br /> <font color="#000000">IN</font> <font color="#000000">DWORD</font> <font color="#000000">fdwReason</font><font color="#C8003C">,</font><br /> <font color="#000000">LPVOID</font> <font color="#000000">lpvReserved</font><br /> <font color="#C8003C">)</font><br /><font color="#C8003C">{</font><br /> <font color="#C8003C">....</font><br /><br /> <font color="#0000FF">case</font> <font color="#000000">DLL_PROCESS_DETACH</font><font color="#C8003C">:</font><br /><br /> <font color="#0000FF">if</font><font color="#C8003C">(</font> <font color="#000000">lpvReserved</font> <font color="#C8003C">==</font> <font color="#000000">NULL</font> <font color="#C8003C">)</font><br /> <font color="#C8003C">{</font><br /> <font color="#000000">g_myDll</font><font color="#C8003C">.</font><font color="#000000">reset</font><font color="#C8003C">(</font><font color="#40B440">0</font><font color="#C8003C">);</font><br /> <font color="#C8003C">}</font><br /> <font color="#000000">g_myDll</font><font color="#C8003C">.</font><font color="#000000">release</font><font color="#C8003C">();</font><br /> <font color="#0000FF">break</font><font color="#C8003C">;</font><br /><font color="#C8003C">}</font></pre></td></tr><tr><td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td></tr></table> <br />В приведенном коде нет особых проблем, но нельзя упускать тот факт, что наша идеальная dll может подключать и, как правило, подключает множество статических библиотек. Которые вполне могут содержать глобальные переменные-объекты.<br /><br />Выводы крайне тривиальны: использование глобальных переменных-объектов - есть зло, особенно в статических библиотеках. Но если вы уже разрабатываете статическую библиотеку на С++ с глобальными переменными внутри, стоит предоставить функцию для их корректного фатального освобождения, с семантикой, аналогичной g_myDll.release().ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0tag:blogger.com,1999:blog-7239389252315107433.post-60913946471178152022010-06-11T12:58:00.000-07:002010-06-11T13:04:19.738-07:00В очередной раз столкнулся с CryptoPPУдивительно, как можно было написать такую библиотеку: максимально быструю, гибкую, но при этом чрезмерно сложную и торчащую всем своим непростым внутренним миром наружу. <br />Можно в школе преподавать.<br />Если принять такое утверждение, что проектирование это борьба со сложностью, то CryptoPP - это безоговорочная капитуляция.ligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com2tag:blogger.com,1999:blog-7239389252315107433.post-35477913356587335352010-03-04T02:55:00.000-08:002010-03-04T04:35:49.481-08:00x64 dumps64 битный windows радует<br />Первое впечатление - как можно что-то понять по дампу если все передается в регистрах?<pre>fffff980`0091f953 4c8bcb mov r9,rbx<br />fffff980`0091f956 4d8bc6 mov r8,r14<br />fffff980`0091f959 4c8bb42498010000 mov r14,[rsp+0x198]<br />fffff980`0091f961 498bd6 mov rdx,r14<br />fffff980`0091f964 498bcc mov rcx,r12<br />fffff980`0091f967 e84490feff call Ntfs!NtfsOpenFile (fffff980009089b0)<br />fffff980`0091f96c 8bd8 mov ebx,eax</pre><br />Второе еще смешнее. Раньше я всегда искал фрейм функции используя команду scan:<br /><br /><span style="font-weight:bold;">0: kd> s -d esp L100 адрес_возврата_из_функции</span><br /><br />Например, так:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKJ1e9zfVWDr4Tnlnl5ZR0GWibeiwBwDX08v2SiImHusets0Gr96WRhNr8GO-YRzdS3KOtsPrStbZi_IOInpGDXdoMOsndsEYZcgYPPRzMieDzyCD3UN9jooO10x8tpzwWYwI__oy3GdQ/s1600-h/sample1.PNG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 181px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKJ1e9zfVWDr4Tnlnl5ZR0GWibeiwBwDX08v2SiImHusets0Gr96WRhNr8GO-YRzdS3KOtsPrStbZi_IOInpGDXdoMOsndsEYZcgYPPRzMieDzyCD3UN9jooO10x8tpzwWYwI__oy3GdQ/s320/sample1.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5444748791335100434" /></a><br /><br />Как можно видеть на изображении, эту команду довольно удобно использовать для получения доступа к параметрам функции. <br />Но! К моему удивлению, под x64 та же команда<br /><br /><span style="font-weight:bold;">0: kd> s -q rsp L1000 адрес_возврата_из_функции</span><br /><br />не вернула ровным счетом ничего. Мистика. <br />Какое-то время я был в замешательстве, пока ситуацию не прояснила немного команда kv:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXAtkhHofQyrvMnh7K1FSqsd2Z5gWws-SAnNpnjxNt29kr98oE-FJQfg7NRF3EMnXx_0wGu_ffhl7TTGP_sXLM0dXakQWAUW5nzoWK0ur4K8S_PjkjL8jZ7Gkk5Ke61hvYS5rUi8XCXq4/s1600-h/sample2.PNG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 133px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXAtkhHofQyrvMnh7K1FSqsd2Z5gWws-SAnNpnjxNt29kr98oE-FJQfg7NRF3EMnXx_0wGu_ffhl7TTGP_sXLM0dXakQWAUW5nzoWK0ur4K8S_PjkjL8jZ7Gkk5Ke61hvYS5rUi8XCXq4/s320/sample2.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5444751208324127714" /></a><br /><br />Если посмотреть на первую колонку Child-SP, то можно заметить прекрасное явление: вначале стек растет как ему и положено в сторону уменьшения адресов от <span style="font-weight:bold;">fffff980`0f0e0c20</span> до <span style="font-weight:bold;">fffff980`0f0dfa50</span>, но потом случается Странная Вещь. Стек продолжает расти в сторону уменьшения адресов, но уже начиная с адреса <span style="font-weight:bold;">fffff980`10349d60</span>!<br /><br />Если присмотреться, то можно заметить, чем же вызвано такое странное поведение системы. Оказывается, что драйвер <span style="font-weight:bold;">ntfs.sys</span> вызвал функцию ядра <a href="http://msdn.microsoft.com/en-us/library/ee817017.aspx"><span style="font-weight:bold;">KeExpandKernelStackAndCalloutEx</span></a>, которая, собственно и сотворило сие магическое действо:<br /><blockquote>"The KeExpandKernelStackAndCalloutEx routine calls a routine and guarantees that a specified amount of stack space is available for this call." (с) MSDN</blockquote><br />Интересно что эта функция меняет значения стека Init, Current и Base на новый сегмент, т.е. в нашем случае они стали начинаться на fffff9801034###:<pre>0: kd> !thread -1<br />THREAD fffffa80015874e0 Cid 03f8.0abc Teb: 000007fffff90000 Win32Thread: 0000000000000000 RUNNING on processor 0<br />IRP List:<br /> fffffa80023dc010: (0006,03a0) Flags: 00000884 Mdl: 00000000<br />Unable to read Impersonation Information at 0<br />Owning Process fffffa8001cda040 Image: svchost.exe<br />Wait Start TickCount 66603034 Ticks: 261 (0:00:00:04.078)<br />Context Switch Count 10716 <br />UserTime 00:00:00.0109<br />KernelTime 00:00:18.0546<br />Start Address 0x0000000076edc6c0<br />Win32 Start Address 0x000007fef7a75530<br />Stack Init fffff98010349db0 Current fffff98010348910<br />Base fffff9801034a000 Limit fffff98010344000 Call 0</pre><br /><br />Вот такие вот модные тенденцииligenhttp://www.blogger.com/profile/03304798634077305741noreply@blogger.com0