title: When pinned object is passed to native code, its address is actually not fixed
body: <h1>The Problem</h1>
  
  <p>Even though I pinned object in managed code, the actual address passed to native code rarely changes.</p>
  
  <p>How can I assure GC to pin the actual address passed to native code?</p>
  
  <p>Situation : <a href="https://youtu.be/-v8GgS6mUY0" rel="nofollow noreferrer">https://youtu.be/-v8GgS6mUY0</a>  </p>
  
  <h1>Details</h1>
  
  <p>I am writing a C# wrapper library for <code>zlib</code> based on <code>zlibnet</code>.</p>
  
  <p>But decompressing with <code>inflate()</code> always failed, returning <code>Z_STREAM_ERROR</code>.<br>
  The error was coming from <code>zlib</code>'s <code>inflateStateCheck()</code>.</p>
  
  <p><strong>ZLibWrapper\ZLibWrapper\ZLibStreams.cs: DeflateStream()</strong></p>
  
  <pre><code>_zstream = new ZStream();
  
  int ret;
  if (this._compMode == CompressionMode.Compress)
      ret = ZLibNative.DeflateInit(ref _zstream, level, WriteType);
  else
      ret = ZLibNative.InflateInit(ref _zstream, OpenType);
  </code></pre>
  
  <p><strong>ZLibWrapper\ZLibWrapper\ZLibStreams.cs: Read()</strong></p>
  
  <pre><code>int zlibError = ZLibNative.Inflate(ref _zstream, ZLibFlush.Z_NO_FLUSH); 
  </code></pre>
  
  <p><strong>zlib-1.2.11\inflate.c: inflateStateCheck()</strong></p>
  
  <pre><code>state = (struct inflate_state FAR *)strm-&gt;state;
  if (state == Z_NULL || state-&gt;strm != strm ||
      state-&gt;mode &lt; HEAD || state-&gt;mode &gt; SYNC)
      return 1; // Z_STREAM_ERROR
  </code></pre>
  
  <p><code>state-&gt;strm</code> was set at <code>inflateInit2_</code>, and <code>strm</code> was set at <code>inflate</code>.  </p>
  
  <p>C#'s garbage collector moved address of <code>_zstream</code> in between, casuing <code>Z_STREAM_ERROR</code>.</p>
  
  <p>Adding <code>GCHandle.Alloc(..., GCHandleType.Pinned)</code> to pin the address of <code>_zstream</code> addressed most of the issue, but now it is happening randomly.  </p>
  
  <p><strong>New code of DeflateStream()</strong></p>
  
  <pre><code>_zstream = new ZStream();
  _zstreamPtr = GCHandle.Alloc(_zstream, GCHandleType.Pinned); // NEW!
  
  int ret;
  if (this._compMode == CompressionMode.Compress)
      ret = ZLibNative.DeflateInit(ref _zstream, level, WriteType);
  else
      ret = ZLibNative.InflateInit(ref _zstream, OpenType);
  </code></pre>
  
  <p>After some debugging, I found out <code>_zstream</code> was pinned but the actual address passed to <code>zlib</code>'s <code>inflate()</code> sometimes changes.</p>
  
  <pre><code>[Managed Side]
  inflateInit2_ : 0x02EBDBC4
  inflate       : 0x02EBDBC4
  
  [Native Side (zlib)]
  inflateInit2_ : 0x02EBCB74 
  inflate       : 0x02BDB3E8 
  </code></pre>
  
  <p>How can I fix this?</p>
  
  <h2>Source Code</h2>
  
  <p>To reproduce this issue, clone this <a href="https://github.com/ied206/ZLibWrapper/tree/6ba68a38c7768ae3a6d86aebc411ec41d8836477" rel="nofollow noreferrer">repository</a> and run tests.  </p>
  
  <h2>Tested Envrionment</h2>
  
  <ul>
  <li>zlibwapi.dll : zlib 1.2.11, compiled with VC2017<br>
  (x86 : ReleaseWithoutAsm, x64 : Release)</li>
  <li>.Net Framework : 4.5, 4.5.2, 4.6.2, 4.7</li>
  </ul>
  
  <p>EDIT: This issue does not happen when .Net Framework's <code>clrcompression.dll</code>, stripped version of zlib 1.2.3, is used instead of zlib 1.2.11.</p>