﻿<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>Ayende @ Rahien</title><link>http://ayende.com</link><description>Ayende @ Rahien</description><copyright>Copyright (C) Ayende Rahien  2004 - 2021 (c) 2026</copyright><ttl>60</ttl><item><title>Sasha Goldshtein commented on What is wrong with this code?</title><description>@Chris Smith: I suspect a naive loop comparing a single byte at a time be *much* slower than memcmp. One of the reasons is that memory operations on bytes take the same time as memory operations on a whole memory word (and depending on cache considerations, even more than that). Besides, memcmp is probably optimized to take advantage of SSE/SSE2 instructions.</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment14</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment14</guid><pubDate>Mon, 17 Oct 2011 08:47:53 GMT</pubDate></item><item><title>Chris Smith commented on What is wrong with this code?</title><description>That's a valid case then.  Thanks.

Can't you just do it in managed code then you don't have to worry about pinning, pinvoke and all that?  It's probably not much slower (I can't claim to have tried it or worked out what the CLR assembles it to though).

bool memcmp(byte[] a, byte[]b, int len) {
    for (int i = 0; i &gt;= 0; i++)
        if (a[i] != b[i]) return false;
    return true;
}

That's rougly what a platform independent C implementation does albeit with less pointer magic and minus some optimisations (that glibc does at least) which do it in aligned 4/8 byte blocks for CPU efficiency.</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment13</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment13</guid><pubDate>Fri, 14 Oct 2011 18:10:29 GMT</pubDate></item><item><title>Ayende Rahien commented on What is wrong with this code?</title><description>Chris.
For example, when I need to compare data that comes from unmanaged code.
I have an index that output data that I need to sort based on their memcmp values</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment12</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment12</guid><pubDate>Fri, 14 Oct 2011 07:29:02 GMT</pubDate></item><item><title>Chris Smith commented on What is wrong with this code?</title><description>&gt; Can anyone give an example of when this might be used in production .NET code.

That's exactly my problem.  This seems an overly hypothetical question.</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment11</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment11</guid><pubDate>Fri, 14 Oct 2011 07:27:42 GMT</pubDate></item><item><title>configurator commented on What is wrong with this code?</title><description>1. Your declaration of memcmp doesn't match the one in pinvoke.net, which is usually correct It has the wrong calling convention, parameter type (although it is the same size so should be safe), and return type (IntPtr instead of int)

[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern int memcmp(byte[] b1, byte[] b2, UIntPtr count);

You are likely to get a PInvoke stack imbalance in one of x86 or x64.

2. b2.Length could be more than b1.Length; if b2 is equal to the first b2.Length bytes of b1, memcmp would continue after the end of the array.

3. Both b1 and b2 could be null; b1 would cause a NullReferenceException, b2 would cause a segfault.

4. If the b1 is over 2GB in size, b1.Length would break. Use LongLength instead; it is safe to cast it to an IntPtr because an array couldn't be larger than int.MaxValue on a 32-bit system.</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment10</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment10</guid><pubDate>Thu, 13 Oct 2011 14:54:41 GMT</pubDate></item><item><title>Steven Proctor commented on What is wrong with this code?</title><description>I am seeing the failure due to the byte stream potentially being longer than what an int can hold.</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment9</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment9</guid><pubDate>Thu, 13 Oct 2011 14:14:13 GMT</pubDate></item><item><title>tobi commented on What is wrong with this code?</title><description>memcmp returns an int, not an IntPtr. Will probably cause some stack corruption. The GC is not a problem though.</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment8</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment8</guid><pubDate>Thu, 13 Oct 2011 13:45:42 GMT</pubDate></item><item><title>Sergey M commented on What is wrong with this code?</title><description>The obvious problem is that b2 can contain lesser bytes than b1.
And not so obvious is that using IntPtr instead of UintPtr may produce stack imbalance on x86 platforms.</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment7</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment7</guid><pubDate>Thu, 13 Oct 2011 11:52:00 GMT</pubDate></item><item><title>Frank Quednau commented on What is wrong with this code?</title><description>Could be a problem that IntPtr don't have the same size on a 32 or 64-bit process. Since  a.NET dll may be compiled to run in processes of any address size this could potentially drive you silly when you e.g. coolly run shit on a big server and do tests with MSTest.

When I look at the memcmp docs, it actually wants pointers? I am wondering if that is not a source of mishap...</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment6</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment6</guid><pubDate>Thu, 13 Oct 2011 11:11:02 GMT</pubDate></item><item><title>Mix commented on What is wrong with this code?</title><description>Null reference exception - if b1 is null b1.Length will boom. If b2 is null well, I'm not sure, but it will probably crash. Returning IntPtr makes no sense whatsoever - it should be plain int - I'm not sure now if this will return 0 as IntPtr.Zero (probably will)

There's actually usage example on pinvoke.net:
http://www.pinvoke.net/default.aspx/msvcrt.memcmp</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment5</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment5</guid><pubDate>Thu, 13 Oct 2011 10:38:34 GMT</pubDate></item><item><title>Damien commented on What is wrong with this code?</title><description>@Max - objects passed to P/Invoke don't need to be pinned, unless the unmanaged code is going to be keeping a reference - the GC won't move them during the P/Invoke call.</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment4</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment4</guid><pubDate>Thu, 13 Oct 2011 10:26:04 GMT</pubDate></item><item><title>Greg B commented on What is wrong with this code?</title><description>Can anyone give an example of when this might be used in production .NET code.

Thanks</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment3</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment3</guid><pubDate>Thu, 13 Oct 2011 10:25:32 GMT</pubDate></item><item><title>Damien commented on What is wrong with this code?</title><description>Well, simple one is the assumption that b2 is at least as long as b1 (otherwise, you're wandering into other memory, possibly crossing a page boundary into memory that isn't there)</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment2</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment2</guid><pubDate>Thu, 13 Oct 2011 10:18:20 GMT</pubDate></item><item><title>Max commented on What is wrong with this code?</title><description>Well, the memory for the byte arrays is not pinned, so if the GC moves the byte arrays during a garbage collection you will get some really strange results, which could include a segfault.

Furthermore, even if the GC doesn't move the arrays, you may get a segfault if the length of b2 is less than that of b1. If the length of b2 is less than that of b1 then you may just get a wrong result.

Lastly, I'm not sure if the representation of a byte[] is guaranteed to be the same as char* but I guess it is not - in particular it must include at least the length. So the check may return a bogus result even if the GC doesn't move things AND the byte arrays are the same length.</description><link>http://ayende.com/118785/what-is-wrong-with-this-code#comment1</link><guid>http://ayende.com/118785/what-is-wrong-with-this-code#comment1</guid><pubDate>Thu, 13 Oct 2011 10:16:31 GMT</pubDate></item></channel></rss>