难道不安全code对安全code有什么影响? [英] Does unsafe code have any effect on safe code?

查看:102
本文介绍了难道不安全code对安全code有什么影响?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我所知,这标志着一种方法不安全将禁用某些上code CLR的检查,但是这是否对系统安全的其他任何影响,不是事实,DLL等/ EXE不能运行在一个不受信任的环境。

As I understand it, marking an method as unsafe will disable some of the CLR checks on that code, but does this have any effect on the rest of the system which is safe, other than the fact that the DLL/EXE can not run in a untrusted environment.

在具体地,

  1. 他们是任何安全检查,这将不完整的DLL工作,因为它被标记为不安全?
  2. 如果一个DLL被标记为不安全的,但标记为不安全的方法 实际上不叫,这是一样的,如果该DLL被标记为 安全吗?
  3. 他们是在保持不安全code在任何​​运行时的好处 单独的DLL?
  1. Are they are any safety checks that will not work on the complete dll because it is marked as unsafe?
  2. If a DLL is marked as unsafe, but the methods marked as unsafe are not actually called, is this the same as if the DLL is marked as safe?
  3. Are they any run-time benefits on keeping the unsafe code in a separate DLL?

我有重绘在64位Windows嵌套控件的详细问题<一href="http://blogs.msdn.com/b/alejacma/archive/2008/11/20/controls-won-t-get-resized-once-the-nesting-hierarchy-of-windows-exceeds-a-certain-depth-x64.aspx"相对=nofollow>此处和一个解决方案(即似乎工作一)涉及不安全code,我想明白,这增加code有我的项目的效果。

I have the problem with redrawing nested controls on 64-bit windows as detailed here and the one the solutions (the one that appears to work) involves unsafe code and I would like to understand the effect that adding this code has to my project.

推荐答案

在回答你的问题是:在不安全关键字并不意味着不安全的,这意味着潜在的不安全。编译器和框架不能工作做出一定的,它是安全的。它是由你来做出肯定的是,code不能执行不安全读取或写入内存。

The answer to your question is: The unsafe keyword does not mean "unsafe", it means "potentially unsafe". The compiler and framework cannot work to make certain that it's safe. It is up to you to make certain that the code cannot perform unsafe reads or writes to memory.

我强烈建议你遵循这个建议在您链接的文章中给出:

I would strongly encourage you to follow this advice given in the article you linked:

1)重新设计应用程序有少容器减少嵌套级别数

1) Redesign the application to have less containers and reduce the number of nesting levels.

如果您使用的是容器的控制权安排的唯一目的,写你自己的容器,可以做所有的安排与一个级别。

If you're using containers for the sole purpose of control arrangement, write your own container that can do all the arrangement with one level.

更新

您可以修改code在那篇文章中,这样它不使用指针(即不需要不安全的关键字)。请记住,这现在需要编组,这意味着额外的拷贝。这可能是一件好事,因为原来的code从操作系统的BeginInvoke不相同调度事件的操作系统产生的指针在执行传递WINDOWPOS指针。换句话说,即code是臭了。

You can modify the code in that article so that it doesn't use pointers (i.e. doesn't require the unsafe keyword). Keep in mind that this will now require marshalling which means extra copying. This is probably a good thing because the original code is passing a WINDOWPOS pointer from the OS to BeginInvoke which does not execute during the same dispatch event that the OS generated the pointer in. In other words, that code was smelly already.

internal class MyTabPage : TabPage
{
    private const int WM_WINDOWPOSCHANGING = 70;
    private const int WM_SETREDRAW = 0xB;
    private const int SWP_NOACTIVATE = 0x0010;
    private const int SWP_NOZORDER = 0x0004;
    private const int SWP_NOSIZE = 0x0001;
    private const int SWP_NOMOVE = 0x0002;

    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    extern static int SendMessage(HandleRef hWnd, int msg, int wParam, int lParam);

    [DllImport("User32.dll", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    extern static bool SetWindowPos(HandleRef hWnd, HandleRef hWndInsertAfter,
    int x, int y, int cx, int cy, int flags);

    [StructLayout(LayoutKind.Sequential)]
    private class WINDOWPOS
    {
        public IntPtr hwnd;
        public IntPtr hwndInsertAfter;
        public int x;
        public int y;
        public int cx;
        public int cy;
        public int flags;
    };

    private delegate void ResizeChildDelegate(WINDOWPOS wpos);

    private void ResizeChild(WINDOWPOS wpos)
    {
        // verify if it's the right instance of MyPanel if needed
        if ((this.Controls.Count == 1) && (this.Controls[0] is Panel))
        {
            Panel child = this.Controls[0] as Panel;

            // stop window redraw to avoid flicker
            SendMessage(new HandleRef(child, child.Handle), WM_SETREDRAW, 0, 0);

            // start a new stack of SetWindowPos calls
            SetWindowPos(new HandleRef(child, child.Handle), new HandleRef(null, IntPtr.Zero),
            0, 0, wpos.cx, wpos.cy, SWP_NOACTIVATE | SWP_NOZORDER);

            // turn window repainting back on 
            SendMessage(new HandleRef(child, child.Handle), WM_SETREDRAW, 1, 0);

            // send repaint message to this control and its children
            this.Invalidate(true);
        }
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_WINDOWPOSCHANGING)
        {
            WINDOWPOS wpos = new WINDOWPOS();
            Marshal.PtrToStructure(m.LParam, wpos);

            Debug.WriteLine("WM_WINDOWPOSCHANGING received by " + this.Name + " flags " + wpos.flags);

            if (((wpos.flags & (SWP_NOZORDER | SWP_NOACTIVATE)) == (SWP_NOZORDER | SWP_NOACTIVATE)) &&
            ((wpos.flags & ~(SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE)) == 0))
            {
                if ((wpos.cx != this.Width) || (wpos.cy != this.Height))
                {
                    BeginInvoke(new ResizeChildDelegate(ResizeChild), wpos);
                    return;
                }
            }
        }

        base.WndProc(ref m);
    }
}

注意:从价值型WINDOWPOS的变化,以引用类型是故意的。使用引用类型减少的份数到只有一个(初始编组)(**)

Note: The change in WINDOWPOS from value type to reference type is intentional. Using a reference type reduces the number of copies to just one (the initial marshal)(**).

更新再次 我只注意到了code最初提出的的P / Invoke声明公开。永远不要暴露P / A类(*)的调用之外。编写调用专用的P / Invoke的声明,如果你的目的是揭露所提供的功能管理方法;在这种情况下是不正确的,在p /调用是严格内部

Updated Again I just noticed that the code originally made the p/invoke declarations public. Never, ever expose p/invoke outside of a class(*). Write managed methods that invoke private p/invoke declarations if your intent is to expose the capabilities provided; which in this case is not true, the p/invoke is strictly internal.

(*)好吧,只有一个例外。你创建一个 NativeMethods UnsafeNativeMethods 等,这是建议的方式做P /通过的FxCop调用。

(*) Ok, one exception. You're creating a NativeMethods, UnsafeNativeMethods, etc. Which is the recommended way to do p/invoke by FxCop.

更新

(**)有人问我,(其他地方)来描述precicely为什么使用引用类型在这里比较好,所以我在这里补充信息。有人问我的问题是,这难道不是增加内存pressure?

(**) I was asked (elsewhere) to describe precicely why using a reference type here is better, so I've added that info here. The question I was asked was, "Doesn't this add memory pressure?"

如果 WINDOWPOS 是一个值类型,这将是事件的顺序:

If WINDOWPOS was a value type, this would be the sequence of events:

1)从非托管复制到托管内存

1) Copy from unmanaged to managed memory

WINDOWPOS wpos = Marshal.PtrToStructure(m.LParam, typeof(WINDOWPOS));

2)第二个副本?

2) Second copy?

BeginInvoke(new ResizeChildDelegate(ResizeChild), wpos);

等等! 的BeginInvoke 的签名是(代表,params对象[])。这意味着WPOS是会得到盒装。所以,是的,第二个副本都发生在这里:在装箱操作

Wait! The signature of BeginInvoke is (Delegate, params object[]). That means wpos is going to get boxed. So yes, a second copy occurs here: The boxing operation.

的BeginInvoke 将增加委托和Object []一个调用列表,并张贴注册窗口消息。当该消息是从队列中的消息泵拆除,代表将被调用的对象[]参数。

BeginInvoke will add the delegate and object[] to an invocation list and post a registered window message. When that message is removed from the queue by the message pump, the delegate will be called with the object[] parameters.

3)拆箱和副本 ResizeChild 电话。

3) Unbox and copy for ResizeChild call.

在这一点上,你可以看到,拷贝数甚至不是问题。事实上,它被转换为引用类型(盒装)意味着我们最好让开始与引用类型。

At this point you can see that the number of copies isn't even the issue. The fact that it gets converted to a reference type (boxed) means that we are better off making it a reference type to begin with.

这篇关于难道不安全code对安全code有什么影响?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆