简体   繁体   English

是不是在DLL / C-Connect中禁用了指针类型检查,这样可以吗?

[英]Isn't pointer type checking disabled in DLL/C-Connect, and is that OK?

After this somehow related question Why can't I pass an UninterpretedBytes to a void* thru DLL/C-Connect? 在这个与问题相关的问题之后, 为什么我不能通过DLL / C-Connect将UninterpretedBytes传递给void *? where we saw that I could not pass a Smalltalk array of bits to a void * parameter, I further analyzed the method responsible for checking the compatibility of formal pointer description with effective object passed as argument, and I think that I discovered another questionable piece: 我们看到我无法将Smalltalk的位数组传递给void *参数,我进一步分析了负责检查形式化指针说明与作为参数传递的有效对象的兼容性的方法,并且我认为我发现了另一个有问题的部分:

CPointerType>>coerceForArgument: anObject
    ...snip...
    (anObject isKindOf: self defaultDatumClass)
        ifTrue: [
            (referentType = anObject type referentType
                or: [(referentType isVoid
                    and: [anObject type referentType isConstant not])
                or: [anObject type isArray not
                    or: [anObject type baseArrayType = referentType]]])
            ifTrue: [^anObject asPointer]].
    ...snip...

It means the following: 这意味着:

  1. It first checks if the argument is CDatum (a proxy to some C-formatted rawdata and associated CType). 它首先检查参数是否为CDatum(某些C格式的原始数据和关联的CType的代理)。

  2. If so, it checks whether the type is the same as the formal definition in external method prototype (self). 如果是这样,它将检查类型是否与外部方法原型(自身)中的形式定义相同。

  3. If not, it could be that the argument is void *, in which case any kind of pointer is accepted (it has been checked that it is a pointer in the code that I snipped), except if it is pointer on a const thing. 如果不是,则该参数可能是void *,在这种情况下,可以接受任何类型的指针(已检查它是否为我摘录的代码中的指针),除非它是const事物上的指针。
    There is a first discrepancy: it should check if the formal definition is const void * and accept any pointer on const in this case... But that does not matter much, we rarely have actual argument declared const. 首先有一个差异:它应该检查形式定义是否为const void *并在这种情况下接受const上的任何指针...但这没什么大不了,我们很少有实际的参数声明为const。

  4. If not, it checks if either not an array (for example, int foo[2]), or an array whose type matches (same base type and dimension). 如果不是,则检查是否不是数组(例如int foo [2])或类型匹配的数组(基本类型和维数相同)。

So, if the formal definition is for example struct {int a; char *b} *foo 因此,如果形式定义是例如struct {int a; char *b} *foo struct {int a; char *b} *foo , and that I pass a double * bar , the type does not match, there is no const qualifier mismatch, and the parameter is not an array, conclusion: we can safely pass it without any further checking! struct {int a; char *b} *foo ,并且我传递了double * bar ,类型不匹配,没有const限定符不匹配,并且参数不是数组,因此得出结论:我们可以安全地传递它,而无需任何进一步检查!

That's a kind of pointer aliasing. 这是一种指针别名。 We do not have an optimizing compiler making any speculation about the absence of such aliasing in Smalltalk, so that won't be the source of undefined behaviour. 我们没有经过优化的编译器,无法猜测Smalltalk中是否缺少这种别名,因此不会成为未定义行为的来源。 It could be that we deliberately want to force this sort of dirty reinterpret_cast for obscure reasons (since we can explicitly cast a CDatum, I would prefer the explicit way). 可能是由于晦涩的原因,我们有意要强制执行这种肮脏的reinterpret_cast(因为我们可以显式地转换CDatum,所以我更喜欢显式的方式)。

BUT, it might be that we completely messed up and passed the wrong object, with wrong type, wrong dimension, and that the address foo->b in my example above will contain either some re-interpreted garbage if pointer is 32bits aligned, or be completely undefined on 64 bits machine (because beyond the sizeof double). 但是,可能是我们完全弄乱了错误的对象,并传递了错误的类型,错误的尺寸,并且在上面的示例中,地址foo-> b将包含一些重新解释的垃圾如果指针是32位对齐的,或者在64位计算机上是完全未定义的(因为超出了double的大小)。

AC compiler would warn me for sure about the aliasing, and prevent production of artifact with -Wall -Werror. AC编译器会就混叠问题向我发出警告,并防止使用-Wall -Werror产生伪像。
What troubles me here is that I do not even get a warning... 让我困扰的是,我什至没有得到警告。

Does it sound correct? 听起来正确吗?

Short answer: it's not OK to correct this behavior, because some low level user interface stuff depends on it (event loop). 简短的回答:不能纠正此行为,因为某些低级别的用户界面内容依赖于此(事件循环)。 We can't even introduce a Warning or anything. 我们甚至无法引入警告或其他任何内容。

Longer story: I tried to rewrite the whole method with double dispatching (ask anObject if compatible with formal CPointerType rather than testing every possible Object class with repeated isKindOf: ). 更长的故事:我试图用双重调度重写整个方法(如果与正式的CPointerType兼容,请询问anObject,而不是用重复的isKindOf:测试每个可能的Object类)。

But when ommitting the disgracious pointer aliasing tolerance, it invariably screw my Macosx 8.3 image with tons of blank windows opening, and blocked uninterruptable UI... 但是,当忽略令人讨厌的指针混叠公差时,它总是用大量空白窗口打开来固定我的Macosx 8.3图像,并阻塞了不间断的UI ...

After instrumenting, it appears that the event loop relies on it, and pass aString asNSString (which is transformed into utf16, but stored into a ByteArray and thus declared unsigned char *), to an Objective C method expecting an unsigned short *. 检测后,似乎事件循环依赖于此,并将aString asNSString(已转换为utf16,但存储到ByteArray中并因此声明为unsigned char *)传递给了一个预期为unsigned short *的Objective C方法。

It's a case where the pointer aliasing is benign, as long as we pass the good bytes. 只要我们传递良好的字节,在这种情况下指针别名是良性的。

If I try and fix asNSString with a proper cast to unsigned short *, then the UI blocks (I don't know why, but it would require debugging at VM level). 如果我尝试通过正确地将asNSString强制转换为unsigned short *,则UI会阻塞(我不知道为什么,但是需要在VM级别进行调试)。

Conclusion: it's true that some distinction such as (unsigned char *) vs (char *) can be germane and should better not be completely prohibited (whether char is signed or not is platform dependent, and not all libraries have cleanly defined APIs). 结论:的确是有区别的,例如(unsigned char *)vs(char *)可以密切相关,最好不要完全禁止(char是否签名是依赖平台的,并且并非所有库都具有明确定义的API)。 Same goes with platform dependent wide character, we have conversion methods producing the good bytes, but not the good types. 依赖平台的宽字符也是如此,我们有一些转换方法可以产生好的字节,但不能产生好的类型。 We could eventually make an exception for char * like we did for void * (before void * was introduced, char * was the way to do it anyway)... Right now, I have no good solution for this because of the event loop. 我们最终可以像对void *一样对char *进行异常处理(在引入void *之前,无论如何,char *都是这样做的方法)...现在,由于事件循环,我对此没有好的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 是否可以将[和]保留为以下消息:ifAbsent:如果您不需要完整的块? - Is it OK to leave the [ and ] out for messages like at:ifAbsent: if you don't need a full block? 为什么没有用Common Lisp编写的Common Lisp实现? - Why isn't there a Common Lisp implementation written in Common Lisp? 如何从Cocoa Notification蹦床到调用c函数指针? - How to trampoline from a Cocoa Notification to the invocation of c function pointer? 检查是否存在课程 - Checking for the presence of a class 在测试中检查类的文本表示? - Checking textual representation of a class in a test? VisualAge Smalltalk Web Connect和Nginx - VisualAge Smalltalk Web Connect and Nginx Smalltalk:检查方法是否属于某个类(或其继承层次结构) - Smalltalk: Checking if a method belongs to a class (or its inheritance hierarchy) VoyageMongo:可以在持久类中覆盖 #= 吗? - VoyageMongo: is it OK to override #= in persistent classes? 如何将指向对象的指针传递给 Squeak/Cuis 中的 FFI 调用? - How do I pass a pointer to an Object to an FFI call in Squeak/Cuis? 通过FindExecutableA对shell32.dll的API调用在UNC路径上返回“找不到特定路径” - API call to shell32.dll via FindExecutableA returns “Can not find the specific path” on UNC paths
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM