for review: fix for linkage mismatch bug
Fergus Henderson
fjh at cs.mu.OZ.AU
Thu Sep 3 19:20:41 AEST 1998
Tyson, could you please review this one?
--------------------
Estimated hours taken: 1
Ensure that the declarations and definitions for data constants
specify the same linkage (extern or static), because the C standard
says that if the linkage is different, then the behaviour is undefined.
This bug resulted in undefined symbol link errors for the RS/6000 AIX port.
compiler/llds_out.m:
When printing out declarations for data constants,
compute the linkage from the data_name, rather than
always assuming `extern'. When printing out definitions,
add a sanity check to ensure that the linkage that would be
computed from the data_name is the same as the linkage used
for the definition.
compiler/base_type_layout.m:
Make base_type_functors and base_type_info structures
always local to the module, rather than exported.
This is necessary to ensure that the linkage can be
computed from the data_name.
compiler/base_typeclass_info.m:
compiler/llds.m:
compiler/stack_layout.m:
Add comments pointing to the new predicate linkage/2 in
llds_out.m, to ensure that future maintenance doesn't break
the assumptions it makes.
Index: compiler/base_type_layout.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/base_type_layout.m,v
retrieving revision 1.32
diff -u -r1.32 base_type_layout.m
--- base_type_layout.m 1998/08/04 02:13:44 1.32
+++ base_type_layout.m 1998/09/03 08:08:35
@@ -346,7 +346,7 @@
base_type_layout__construct_base_type_data([BaseGenInfo | BaseGenInfos],
LayoutInfo0, LayoutInfo) :-
BaseGenInfo = base_gen_layout(TypeId, ModuleName, TypeName, TypeArity,
- Status, HldsType),
+ _Status, HldsType),
base_type_layout__set_type_id(LayoutInfo0, TypeId, LayoutInfo1),
hlds_data__get_type_defn_body(HldsType, TypeBody),
(
@@ -401,13 +401,16 @@
)
)
),
- (
- ( Status = exported ; Status = abstract_exported )
- ->
- Exported = yes
- ;
- Exported = no
- ),
+
+ %
+ % Note: base_type_layouts and base_type_functors are never exported,
+ % because they should only be accessed via the base_type_info in
+ % the same module.
+ % Accesses to the base_type_layout for a type exported from a
+ % different module should be done via that type's base_type_info,
+ % which will be exported if the type was exported/abstract_exported.
+ %
+ Exported = no,
% pure abstract types have no layout definition.
(
Index: compiler/base_typeclass_info.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/base_typeclass_info.m,v
retrieving revision 1.4
diff -u -r1.4 base_typeclass_info.m
--- base_typeclass_info.m 1998/03/03 17:33:34 1.4
+++ base_typeclass_info.m 1998/09/03 07:51:17
@@ -106,6 +106,8 @@
Rvals = Rvals0,
% XXX Need we always export it from the module?
+ % (Note that linkage/2 in llds_out.m assumes
+ % that we do.)
Status = yes,
CModule = c_data(ModuleName, DataName, Status, Rvals, Procs),
Index: compiler/llds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/llds.m,v
retrieving revision 1.227
diff -u -r1.227 llds.m
--- llds.m 1998/07/29 08:53:14 1.227
+++ llds.m 1998/09/03 07:52:22
@@ -84,6 +84,9 @@
% qualified with the basename.
bool, % Should this item be exported
% from this Mercury module?
+ % XXX Actually this field is
+ % redundant; see linkage/2
+ % in llds_out.m.
list(maybe(rval)), % The arguments of the create.
list(pred_proc_id) % The procedures referenced.
% Used by dead_proc_elim.
Index: compiler/llds_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/llds_out.m,v
retrieving revision 1.87
diff -u -r1.87 llds_out.m
--- llds_out.m 1998/07/29 08:53:20 1.87
+++ llds_out.m 1998/09/03 08:07:41
@@ -484,6 +484,24 @@
io__write_string("\n"),
{ DataAddr = data_addr(data_addr(ModuleName, VarName)) },
output_cons_arg_decls(ArgVals, "", "", 0, _, DeclSet0, DeclSet1),
+
+ %
+ % sanity check: check that the (redundant) ExportedFromModule field
+ % in the c_data, which we use for the definition, matches the linkage
+ % computed by linkage/2 from the dataname, which we use for any
+ % prior declarations.
+ %
+ { linkage(VarName, Linkage) },
+ {
+ ( Linkage = extern, ExportedFromModule = yes
+ ; Linkage = static, ExportedFromModule = no
+ )
+ ->
+ true
+ ;
+ error("linkage mismatch")
+ },
+
% The code for data local to a Mercury module
% should normally be visible only within the C file
% generated for that module. However, if we generate
@@ -2132,7 +2150,26 @@
FirstIndent, LaterIndent, N0, N) -->
output_indent(FirstIndent, LaterIndent, N0),
{ N is N0 + 1 },
- io__write_string("extern "),
+
+ %
+ % Previously we used to always write `extern' here, but
+ % declaring something `extern' and then later defining it as
+ % `static' causes undefined behavior -- on many systems, it
+ % works, but on some systems such as RS/6000s running AIX
+ % it results in link errors.
+ %
+ { linkage(VarName, Linkage) },
+ globals__io_lookup_bool_option(split_c_files, SplitFiles),
+ (
+ ( { Linkage = extern }
+ ; { SplitFiles = yes }
+ )
+ ->
+ io__write_string("extern ")
+ ;
+ io__write_string("static ")
+ ),
+
globals__io_get_globals(Globals),
% Don't make decls of base_type_infos `const' if we
@@ -2152,6 +2189,27 @@
io__write_string("\t"),
output_data_addr(ModuleName, VarName),
io__write_string(";\n").
+
+%
+% Note that we need to know the linkage not just at the definition,
+% but also at every use, because if the use is prior to the definition,
+% then we need to declare the name first, and the linkage used in that
+% declaration must be consistent with the linkage in the definition.
+% For this reason, the field in c_data (which holds the information about
+% the definition) which says whether or not a data name is exported
+% is not useful. Instead, we need to determine whether or not something
+% is exported from its `data_name'.
+%
+
+:- type linkage ---> extern ; static.
+
+:- pred linkage(data_name::in, linkage::out) is det.
+linkage(base_typeclass_info(_, _), extern).
+linkage(base_type(info, _, _), extern).
+linkage(base_type(layout, _, _), static).
+linkage(base_type(functors, _, _), static).
+linkage(common(_), static).
+linkage(stack_layout(_), static).
%-----------------------------------------------------------------------------%
Index: compiler/stack_layout.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/stack_layout.m,v
retrieving revision 1.17
diff -u -r1.17 stack_layout.m
--- stack_layout.m 1998/07/20 10:01:26 1.17
+++ stack_layout.m 1998/09/03 07:53:52
@@ -317,6 +317,8 @@
{ Exported = no }, % XXX With the new profiler, we will need to
% set this to `yes' if the profiling option
% is given and if the procedure is exported.
+ % Beware however that linkage/2 in llds_out.m
+ % assumes that this is `no'.
{ CModule = c_data(ModuleName, stack_layout(EntryLabel), Exported,
MaybeRvals, []) },
stack_layout__add_cmodule(CModule, EntryLabel).
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3 | -- the last words of T. S. Garp.
More information about the developers
mailing list