StructType for dispatch_object_t changed by Linker

Hi, everyone. I’ve run into a strange problem generating code that contains the dispatch_object_t type.

The problem happens when a program does these steps (all with the global LLVMContext):

  1. Loads a module (otherModule) that uses dispatch_object_t.
  2. Generates code that calls dispatch_release, which takes a dispatch_object_t argument, into a module (mainModule).
  3. Links otherModule into mainModule.
  4. Generates more code that calls dispatch_release.

In Step 4, the following failure occurs on the CallInst::Create call for dispatch_release:

Assertion failed: ((i >= FTy->getNumParams() || FTy->getParamType(i) == Args[i]->getType()) && “Calling a function with a bad signature!”), function init, file Instructions.cpp, line 274.

This happens because the StructType returned by mod->getTypeByName("union.dispatch_object_t") is different between Step 2 and Step 4. According to Type::dump(), it is:

Step 2: %union.dispatch_object_t = type { %struct.dispatch_object_s* }
Step 4: %union.dispatch_object_t = type { %struct.dispatch_object_s.1* }

Code that reproduces the problem is at http://pastebin.com/pxveBUJa and http://pastebin.com/GDb9n9xA.

A workaround is to call StructType::create(mod->getContext(), "union.dispatch_object_t") before doing Step 1.

This sounds like what Chris was talking about in his blog post on the LLVM 3.0 type system, “The Linker ‘links’ types and retypes IR objects”. Except that I would have expected the Linker to recognize that the dispatch_object_t type in the loaded module and the generated code are the same. Am I doing something wrong, or is this a bug in LLVM? (I have LLVM 3.1, Mac OS X 10.6.)

Thanks for your time.

Hi Jaymie,

...
> Step 2: %union.dispatch_object_t = type { %struct.dispatch_object_s* }

Step 4: %union.dispatch_object_t = type { %struct.dispatch_object_s.1* }

Code that reproduces the problem is at http://pastebin.com/pxveBUJa and
http://pastebin.com/GDb9n9xA.

A workaround is to call
`StructType::create(mod->getContext(), "union.dispatch_object_t")` before doing
Step 1.

This sounds like what Chris was talking about in his blog post on the LLVM 3.0
type system <http://blog.llvm.org/2011/11/llvm-30-type-system-rewrite.html>,
"The Linker 'links' types and retypes IR objects".

exactly, this is where it is coming from.

  Except that I would have

expected the Linker to recognize that the `dispatch_object_t` type in the loaded
module and the generated code are the same. Am I doing something wrong, or is
this a bug in LLVM? (I have LLVM 3.1, Mac OS X 10.6.)

Probably the types are not defined precisely the same in each module (maybe you
could send the exact definitions in each module to the mailing list?), but I
think there were also some bugs in this area that were fixed in 3.2.

Ciao, Duncan.

Duncan, thanks for your reply.

Probably the types are not defined precisely the same in each module (maybe you
could send the exact definitions in each module to the mailing list?),

In the module loaded in Step 1 (otherModule):

%struct.dispatch_group_s = type opaque
%union.dispatch_object_t = type { %struct.dispatch_object_s* }
%struct.dispatch_object_s = type opaque

In the module generated in Step 2 (mainModule):

%struct.dispatch_group_s = type {}
%union.dispatch_object_t = type { %struct.dispatch_object_s* }
%struct.dispatch_object_s = type {}

(The LLVM API calls to generate mainModule were generated by calling llc -march=cpp on otherModule.)

but I
think there were also some bugs in this area that were fixed in 3.2.

Great, I’ll also test on 3.2 when I get a chance. Thanks.

Duncan, thanks for your reply.

Probably the types are not defined precisely the same in each module (maybe you
could send the exact definitions in each module to the mailing list?),

In the module loaded in Step 1 (otherModule):

%struct.dispatch_group_s = type opaque
%union.dispatch_object_t = type { %struct.dispatch_object_s* }
%struct.dispatch_object_s = type opaque

In the module generated in Step 2 (mainModule):

%struct.dispatch_group_s = type {}
%union.dispatch_object_t = type { %struct.dispatch_object_s* }
%struct.dispatch_object_s = type {}

(The LLVM API calls to generate mainModule were generated by calling llc -march=cpp on otherModule.)

Is there any chance one module was compiled in C mode and the other one in C++ mode ?

The dispatch_object declarations are not the same for both languages:

#if defined(__cplusplus)
/*

  • Dispatch objects are NOT C++ objects. Nevertheless, we can at least keep C++
  • aware of type compatibility.
    */
    typedef struct dispatch_object_s {
    private:
    dispatch_object_s();
    ~dispatch_object_s();
    dispatch_object_s(const dispatch_object_s &);
    void operator=(const dispatch_object_s &);
    } *dispatch_object_t;

but I
think there were also some bugs in this area that were fixed in 3.2.

Great, I’ll also test on 3.2 when I get a chance. Thanks.


LLVM Developers mailing list
LLVMdev@cs.uiuc.edu http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev

– Jean-Daniel

Jean-Daniel,

Probably the types are not defined precisely the same in each module (maybe you
could send the exact definitions in each module to the mailing list?),

In the module loaded in Step 1 (otherModule):

%struct.dispatch_group_s = type opaque
%union.dispatch_object_t = type { %struct.dispatch_object_s* }
%struct.dispatch_object_s = type opaque

In the module generated in Step 2 (mainModule):

%struct.dispatch_group_s = type {}
%union.dispatch_object_t = type { %struct.dispatch_object_s* }
%struct.dispatch_object_s = type {}

(The LLVM API calls to generate mainModule were generated by calling llc -march=cpp on otherModule.)

Is there any chance one module was compiled in C mode and the other one in C++ mode ?

The dispatch_object declarations are not the same for both languages:

Good question, but I don’t think that’s it. When otherModule is compiled as C++ code, the types are completely different:

%struct.dispatch_group_s = type { i8 }

%struct.dispatch_object_s = type { i8 }

-Jaymie