@@ -5,6 +5,7 @@ use std::path::Path;
5
5
use rustc_abi:: { Align , AlignFromBytesError , CanonAbi , Size } ;
6
6
use rustc_apfloat:: Float ;
7
7
use rustc_ast:: expand:: allocator:: alloc_error_handler_name;
8
+ use rustc_hir:: attrs:: Linkage ;
8
9
use rustc_hir:: def:: DefKind ;
9
10
use rustc_hir:: def_id:: CrateNum ;
10
11
use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
@@ -138,7 +139,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
138
139
Entry :: Occupied ( e) => e. into_mut ( ) ,
139
140
Entry :: Vacant ( e) => {
140
141
// Find it if it was not cached.
141
- let mut instance_and_crate: Option < ( ty:: Instance < ' _ > , CrateNum ) > = None ;
142
+
143
+ struct SymbolTarget < ' tcx > {
144
+ instance : ty:: Instance < ' tcx > ,
145
+ cnum : CrateNum ,
146
+ is_weak : bool ,
147
+ }
148
+ let mut symbol_target: Option < SymbolTarget < ' tcx > > = None ;
142
149
helpers:: iter_exported_symbols ( tcx, |cnum, def_id| {
143
150
let attrs = tcx. codegen_fn_attrs ( def_id) ;
144
151
// Skip over imports of items.
@@ -155,40 +162,80 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
155
162
156
163
let instance = Instance :: mono ( tcx, def_id) ;
157
164
let symbol_name = tcx. symbol_name ( instance) . name ;
165
+ let is_weak = attrs. linkage == Some ( Linkage :: WeakAny ) ;
158
166
if symbol_name == link_name. as_str ( ) {
159
- if let Some ( ( original_instance, original_cnum) ) = instance_and_crate {
160
- // Make sure we are consistent wrt what is 'first' and 'second'.
161
- let original_span = tcx. def_span ( original_instance. def_id ( ) ) . data ( ) ;
162
- let span = tcx. def_span ( def_id) . data ( ) ;
163
- if original_span < span {
164
- throw_machine_stop ! ( TerminationInfo :: MultipleSymbolDefinitions {
165
- link_name,
166
- first: original_span,
167
- first_crate: tcx. crate_name( original_cnum) ,
168
- second: span,
169
- second_crate: tcx. crate_name( cnum) ,
170
- } ) ;
171
- } else {
172
- throw_machine_stop ! ( TerminationInfo :: MultipleSymbolDefinitions {
173
- link_name,
174
- first: span,
175
- first_crate: tcx. crate_name( cnum) ,
176
- second: original_span,
177
- second_crate: tcx. crate_name( original_cnum) ,
178
- } ) ;
167
+ if let Some ( original) = & symbol_target {
168
+ // There is more than one definition with this name. What we do now
169
+ // depends on whether one or both definitions are weak.
170
+ match ( is_weak, original. is_weak ) {
171
+ ( false , true ) => {
172
+ // Original definition is a weak definition. Override it.
173
+
174
+ symbol_target = Some ( SymbolTarget {
175
+ instance : ty:: Instance :: mono ( tcx, def_id) ,
176
+ cnum,
177
+ is_weak,
178
+ } ) ;
179
+ }
180
+ ( true , false ) => {
181
+ // Current definition is a weak definition. Keep the original one.
182
+ }
183
+ ( true , true ) | ( false , false ) => {
184
+ // Either both definitions are non-weak or both are weak. In
185
+ // either case return an error. For weak definitions we error
186
+ // because it is unspecified which definition would have been
187
+ // picked by the linker.
188
+
189
+ // Make sure we are consistent wrt what is 'first' and 'second'.
190
+ let original_span =
191
+ tcx. def_span ( original. instance . def_id ( ) ) . data ( ) ;
192
+ let span = tcx. def_span ( def_id) . data ( ) ;
193
+ if original_span < span {
194
+ throw_machine_stop ! (
195
+ TerminationInfo :: MultipleSymbolDefinitions {
196
+ link_name,
197
+ first: original_span,
198
+ first_crate: tcx. crate_name( original. cnum) ,
199
+ second: span,
200
+ second_crate: tcx. crate_name( cnum) ,
201
+ }
202
+ ) ;
203
+ } else {
204
+ throw_machine_stop ! (
205
+ TerminationInfo :: MultipleSymbolDefinitions {
206
+ link_name,
207
+ first: span,
208
+ first_crate: tcx. crate_name( cnum) ,
209
+ second: original_span,
210
+ second_crate: tcx. crate_name( original. cnum) ,
211
+ }
212
+ ) ;
213
+ }
214
+ }
179
215
}
216
+ } else {
217
+ symbol_target = Some ( SymbolTarget {
218
+ instance : ty:: Instance :: mono ( tcx, def_id) ,
219
+ cnum,
220
+ is_weak,
221
+ } ) ;
180
222
}
181
- if !matches ! ( tcx. def_kind( def_id) , DefKind :: Fn | DefKind :: AssocFn ) {
182
- throw_ub_format ! (
183
- "attempt to call an exported symbol that is not defined as a function"
184
- ) ;
185
- }
186
- instance_and_crate = Some ( ( ty:: Instance :: mono ( tcx, def_id) , cnum) ) ;
187
223
}
188
224
interp_ok ( ( ) )
189
225
} ) ?;
190
226
191
- e. insert ( instance_and_crate. map ( |ic| ic. 0 ) )
227
+ // Once we identified the instance corresponding to the symbol, ensure
228
+ // it is a function. It is okay to encounter non-functions in the search above
229
+ // as long as the final instance we arrive at is a function.
230
+ if let Some ( SymbolTarget { instance, .. } ) = symbol_target {
231
+ if !matches ! ( tcx. def_kind( instance. def_id( ) ) , DefKind :: Fn | DefKind :: AssocFn ) {
232
+ throw_ub_format ! (
233
+ "attempt to call an exported symbol that is not defined as a function"
234
+ ) ;
235
+ }
236
+ }
237
+
238
+ e. insert ( symbol_target. map ( |SymbolTarget { instance, .. } | instance) )
192
239
}
193
240
} ;
194
241
match instance {
0 commit comments