/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/assembly.cs

http://github.com/icsharpcode/ILSpy · C# · 1257 lines · 949 code · 205 blank · 103 comment · 272 complexity · c382a7c8436f5f93110a050cd81d264a MD5 · raw file

  1. //
  2. // assembly.cs: Assembly declaration and specifications
  3. //
  4. // Authors:
  5. // Miguel de Icaza (miguel@ximian.com)
  6. // Marek Safar (marek.safar@gmail.com)
  7. //
  8. // Copyright 2001, 2002, 2003 Ximian, Inc.
  9. // Copyright 2004-2011 Novell, Inc.
  10. // Copyright 2011-2013 Xamarin Inc
  11. //
  12. using System;
  13. using System.IO;
  14. using System.Collections.Generic;
  15. using System.Globalization;
  16. using System.Security;
  17. using System.Security.Cryptography;
  18. using System.Security.Permissions;
  19. using Mono.Security.Cryptography;
  20. using Mono.CompilerServices.SymbolWriter;
  21. #if STATIC
  22. using IKVM.Reflection;
  23. using IKVM.Reflection.Emit;
  24. using SecurityType = System.Collections.Generic.List<IKVM.Reflection.Emit.CustomAttributeBuilder>;
  25. #else
  26. using SecurityType = System.Collections.Generic.Dictionary<System.Security.Permissions.SecurityAction, System.Security.PermissionSet>;
  27. using System.Reflection;
  28. using System.Reflection.Emit;
  29. #endif
  30. namespace Mono.CSharp
  31. {
  32. public interface IAssemblyDefinition
  33. {
  34. string FullName { get; }
  35. bool IsCLSCompliant { get; }
  36. bool IsMissing { get; }
  37. string Name { get; }
  38. byte[] GetPublicKeyToken ();
  39. bool IsFriendAssemblyTo (IAssemblyDefinition assembly);
  40. }
  41. public abstract class AssemblyDefinition : IAssemblyDefinition
  42. {
  43. // TODO: make it private and move all builder based methods here
  44. public AssemblyBuilder Builder;
  45. protected AssemblyBuilderExtension builder_extra;
  46. MonoSymbolFile symbol_writer;
  47. bool is_cls_compliant;
  48. bool wrap_non_exception_throws;
  49. bool wrap_non_exception_throws_custom;
  50. bool has_user_debuggable;
  51. protected ModuleContainer module;
  52. readonly string name;
  53. protected readonly string file_name;
  54. byte[] public_key, public_key_token;
  55. bool delay_sign;
  56. // Holds private/public key pair when private key
  57. // was available
  58. StrongNameKeyPair private_key;
  59. Attribute cls_attribute;
  60. Method entry_point;
  61. protected List<ImportedModuleDefinition> added_modules;
  62. SecurityType declarative_security;
  63. Dictionary<ITypeDefinition, Attribute> emitted_forwarders;
  64. AssemblyAttributesPlaceholder module_target_attrs;
  65. // Win32 version info values
  66. string vi_product, vi_product_version, vi_company, vi_copyright, vi_trademark;
  67. protected AssemblyDefinition (ModuleContainer module, string name)
  68. {
  69. this.module = module;
  70. this.name = Path.GetFileNameWithoutExtension (name);
  71. wrap_non_exception_throws = true;
  72. delay_sign = Compiler.Settings.StrongNameDelaySign;
  73. //
  74. // Load strong name key early enough for assembly importer to be able to
  75. // use the keys for InternalsVisibleTo
  76. // This should go somewhere close to ReferencesLoading but don't have the place yet
  77. //
  78. if (Compiler.Settings.HasKeyFileOrContainer) {
  79. LoadPublicKey (Compiler.Settings.StrongNameKeyFile, Compiler.Settings.StrongNameKeyContainer);
  80. }
  81. }
  82. protected AssemblyDefinition (ModuleContainer module, string name, string fileName)
  83. : this (module, name)
  84. {
  85. this.file_name = fileName;
  86. }
  87. #region Properties
  88. public Attribute CLSCompliantAttribute {
  89. get {
  90. return cls_attribute;
  91. }
  92. }
  93. public CompilerContext Compiler {
  94. get {
  95. return module.Compiler;
  96. }
  97. }
  98. //
  99. // Assembly entry point, aka Main method
  100. //
  101. public Method EntryPoint {
  102. get {
  103. return entry_point;
  104. }
  105. set {
  106. entry_point = value;
  107. }
  108. }
  109. public string FullName {
  110. get {
  111. return Builder.FullName;
  112. }
  113. }
  114. public bool HasCLSCompliantAttribute {
  115. get {
  116. return cls_attribute != null;
  117. }
  118. }
  119. // TODO: This should not exist here but will require more changes
  120. public MetadataImporter Importer {
  121. get; set;
  122. }
  123. public bool IsCLSCompliant {
  124. get {
  125. return is_cls_compliant;
  126. }
  127. }
  128. bool IAssemblyDefinition.IsMissing {
  129. get {
  130. return false;
  131. }
  132. }
  133. public bool IsSatelliteAssembly { get; private set; }
  134. public string Name {
  135. get {
  136. return name;
  137. }
  138. }
  139. public bool WrapNonExceptionThrows {
  140. get {
  141. return wrap_non_exception_throws;
  142. }
  143. }
  144. protected Report Report {
  145. get {
  146. return Compiler.Report;
  147. }
  148. }
  149. public MonoSymbolFile SymbolWriter {
  150. get {
  151. return symbol_writer;
  152. }
  153. }
  154. #endregion
  155. public void AddModule (ImportedModuleDefinition module)
  156. {
  157. if (added_modules == null) {
  158. added_modules = new List<ImportedModuleDefinition> ();
  159. added_modules.Add (module);
  160. }
  161. }
  162. public void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
  163. {
  164. if (a.IsValidSecurityAttribute ()) {
  165. a.ExtractSecurityPermissionSet (ctor, ref declarative_security);
  166. return;
  167. }
  168. if (a.Type == pa.AssemblyCulture) {
  169. string value = a.GetString ();
  170. if (value == null || value.Length == 0)
  171. return;
  172. if (Compiler.Settings.Target == Target.Exe) {
  173. Report.Error (7059, a.Location, "Executables cannot be satellite assemblies. Remove the attribute or keep it empty");
  174. return;
  175. }
  176. if (value == "neutral")
  177. value = "";
  178. if (Compiler.Settings.Target == Target.Module) {
  179. SetCustomAttribute (ctor, cdata);
  180. } else {
  181. builder_extra.SetCulture (value, a.Location);
  182. }
  183. IsSatelliteAssembly = true;
  184. return;
  185. }
  186. if (a.Type == pa.AssemblyVersion) {
  187. string value = a.GetString ();
  188. if (value == null || value.Length == 0)
  189. return;
  190. var vinfo = IsValidAssemblyVersion (value, true);
  191. if (vinfo == null) {
  192. Report.Error (7034, a.Location, "The specified version string `{0}' does not conform to the required format - major[.minor[.build[.revision]]]",
  193. value);
  194. return;
  195. }
  196. if (Compiler.Settings.Target == Target.Module) {
  197. SetCustomAttribute (ctor, cdata);
  198. } else {
  199. builder_extra.SetVersion (vinfo, a.Location);
  200. }
  201. return;
  202. }
  203. if (a.Type == pa.AssemblyAlgorithmId) {
  204. const int pos = 2; // skip CA header
  205. uint alg = (uint) cdata [pos];
  206. alg |= ((uint) cdata [pos + 1]) << 8;
  207. alg |= ((uint) cdata [pos + 2]) << 16;
  208. alg |= ((uint) cdata [pos + 3]) << 24;
  209. if (Compiler.Settings.Target == Target.Module) {
  210. SetCustomAttribute (ctor, cdata);
  211. } else {
  212. builder_extra.SetAlgorithmId (alg, a.Location);
  213. }
  214. return;
  215. }
  216. if (a.Type == pa.AssemblyFlags) {
  217. const int pos = 2; // skip CA header
  218. uint flags = (uint) cdata[pos];
  219. flags |= ((uint) cdata [pos + 1]) << 8;
  220. flags |= ((uint) cdata [pos + 2]) << 16;
  221. flags |= ((uint) cdata [pos + 3]) << 24;
  222. // Ignore set PublicKey flag if assembly is not strongnamed
  223. if ((flags & (uint) AssemblyNameFlags.PublicKey) != 0 && public_key == null)
  224. flags &= ~(uint) AssemblyNameFlags.PublicKey;
  225. if (Compiler.Settings.Target == Target.Module) {
  226. SetCustomAttribute (ctor, cdata);
  227. } else {
  228. builder_extra.SetFlags (flags, a.Location);
  229. }
  230. return;
  231. }
  232. if (a.Type == pa.TypeForwarder) {
  233. TypeSpec t = a.GetArgumentType ();
  234. if (t == null || TypeManager.HasElementType (t)) {
  235. Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute");
  236. return;
  237. }
  238. if (emitted_forwarders == null) {
  239. emitted_forwarders = new Dictionary<ITypeDefinition, Attribute> ();
  240. } else if (emitted_forwarders.ContainsKey (t.MemberDefinition)) {
  241. Report.SymbolRelatedToPreviousError (emitted_forwarders[t.MemberDefinition].Location, null);
  242. Report.Error (739, a.Location, "A duplicate type forward of type `{0}'",
  243. t.GetSignatureForError ());
  244. return;
  245. }
  246. emitted_forwarders.Add (t.MemberDefinition, a);
  247. if (t.MemberDefinition.DeclaringAssembly == this) {
  248. Report.SymbolRelatedToPreviousError (t);
  249. Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly",
  250. t.GetSignatureForError ());
  251. return;
  252. }
  253. if (t.IsNested) {
  254. Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type",
  255. t.GetSignatureForError ());
  256. return;
  257. }
  258. builder_extra.AddTypeForwarder (t.GetDefinition (), a.Location);
  259. return;
  260. }
  261. if (a.Type == pa.Extension) {
  262. a.Error_MisusedExtensionAttribute ();
  263. return;
  264. }
  265. if (a.Type == pa.InternalsVisibleTo) {
  266. string assembly_name = a.GetString ();
  267. if (assembly_name == null) {
  268. Report.Error (7030, a.Location, "Friend assembly reference cannot have `null' value");
  269. return;
  270. }
  271. if (assembly_name.Length == 0)
  272. return;
  273. #if STATIC
  274. ParsedAssemblyName aname;
  275. ParseAssemblyResult r = Fusion.ParseAssemblyName (assembly_name, out aname);
  276. if (r != ParseAssemblyResult.OK) {
  277. Report.Warning (1700, 3, a.Location, "Friend assembly reference `{0}' is invalid and cannot be resolved",
  278. assembly_name);
  279. return;
  280. }
  281. if (aname.Version != null || aname.Culture != null || aname.ProcessorArchitecture != ProcessorArchitecture.None) {
  282. Report.Error (1725, a.Location,
  283. "Friend assembly reference `{0}' is invalid. InternalsVisibleTo declarations cannot have a version, culture or processor architecture specified",
  284. assembly_name);
  285. return;
  286. }
  287. if (public_key != null && !aname.HasPublicKey) {
  288. Report.Error (1726, a.Location,
  289. "Friend assembly reference `{0}' is invalid. Strong named assemblies must specify a public key in their InternalsVisibleTo declarations",
  290. assembly_name);
  291. return;
  292. }
  293. #endif
  294. } else if (a.Type == pa.RuntimeCompatibility) {
  295. wrap_non_exception_throws_custom = true;
  296. } else if (a.Type == pa.AssemblyFileVersion) {
  297. vi_product_version = a.GetString ();
  298. if (string.IsNullOrEmpty (vi_product_version) || IsValidAssemblyVersion (vi_product_version, false) == null) {
  299. Report.Warning (7035, 1, a.Location, "The specified version string `{0}' does not conform to the recommended format major.minor.build.revision",
  300. vi_product_version, a.Name);
  301. return;
  302. }
  303. // File version info decoding from blob is not supported
  304. var cab = new CustomAttributeBuilder ((ConstructorInfo) ctor.GetMetaInfo (), new object[] { vi_product_version });
  305. Builder.SetCustomAttribute (cab);
  306. return;
  307. } else if (a.Type == pa.AssemblyProduct) {
  308. vi_product = a.GetString ();
  309. } else if (a.Type == pa.AssemblyCompany) {
  310. vi_company = a.GetString ();
  311. } else if (a.Type == pa.AssemblyDescription) {
  312. // TODO: Needs extra api
  313. } else if (a.Type == pa.AssemblyCopyright) {
  314. vi_copyright = a.GetString ();
  315. } else if (a.Type == pa.AssemblyTrademark) {
  316. vi_trademark = a.GetString ();
  317. } else if (a.Type == pa.Debuggable) {
  318. has_user_debuggable = true;
  319. }
  320. SetCustomAttribute (ctor, cdata);
  321. }
  322. //
  323. // When using assembly public key attributes InternalsVisibleTo key
  324. // was not checked, we have to do it later when we actually know what
  325. // our public key token is
  326. //
  327. void CheckReferencesPublicToken ()
  328. {
  329. // TODO: It should check only references assemblies but there is
  330. // no working SRE API
  331. foreach (var entry in Importer.Assemblies) {
  332. var a = entry as ImportedAssemblyDefinition;
  333. if (a == null || a.IsMissing)
  334. continue;
  335. if (public_key != null && !a.HasStrongName) {
  336. Report.Error (1577, "Referenced assembly `{0}' does not have a strong name",
  337. a.FullName);
  338. }
  339. var ci = a.Assembly.GetName ().CultureInfo;
  340. if (!ci.Equals (CultureInfo.InvariantCulture)) {
  341. Report.Warning (8009, 1, "Referenced assembly `{0}' has different culture setting of `{1}'",
  342. a.Name, ci.Name);
  343. }
  344. if (!a.IsFriendAssemblyTo (this))
  345. continue;
  346. var attr = a.GetAssemblyVisibleToName (this);
  347. var atoken = attr.GetPublicKeyToken ();
  348. if (ArrayComparer.IsEqual (GetPublicKeyToken (), atoken))
  349. continue;
  350. Report.SymbolRelatedToPreviousError (a.Location);
  351. Report.Error (281,
  352. "Friend access was granted to `{0}', but the output assembly is named `{1}'. Try adding a reference to `{0}' or change the output assembly name to match it",
  353. attr.FullName, FullName);
  354. }
  355. }
  356. protected AssemblyName CreateAssemblyName ()
  357. {
  358. var an = new AssemblyName (name);
  359. if (public_key != null && Compiler.Settings.Target != Target.Module) {
  360. if (delay_sign) {
  361. an.SetPublicKey (public_key);
  362. } else {
  363. if (public_key.Length == 16) {
  364. Report.Error (1606, "Could not sign the assembly. ECMA key can only be used to delay-sign assemblies");
  365. } else if (private_key == null) {
  366. Error_AssemblySigning ("The specified key file does not have a private key");
  367. } else {
  368. an.KeyPair = private_key;
  369. }
  370. }
  371. }
  372. return an;
  373. }
  374. public virtual ModuleBuilder CreateModuleBuilder ()
  375. {
  376. if (file_name == null)
  377. throw new NotSupportedException ("transient module in static assembly");
  378. var module_name = Path.GetFileName (file_name);
  379. // Always initialize module without symbolInfo. We could be framework dependent
  380. // but returned ISymbolWriter does not have all what we need therefore some
  381. // adaptor will be needed for now we alwayas emit MDB format when generating
  382. // debug info
  383. return Builder.DefineDynamicModule (module_name, module_name, false);
  384. }
  385. public virtual void Emit ()
  386. {
  387. if (Compiler.Settings.Target == Target.Module) {
  388. module_target_attrs = new AssemblyAttributesPlaceholder (module, name);
  389. module_target_attrs.CreateContainer ();
  390. module_target_attrs.DefineContainer ();
  391. module_target_attrs.Define ();
  392. module.AddCompilerGeneratedClass (module_target_attrs);
  393. } else if (added_modules != null) {
  394. ReadModulesAssemblyAttributes ();
  395. }
  396. if (Compiler.Settings.GenerateDebugInfo) {
  397. symbol_writer = new MonoSymbolFile ();
  398. }
  399. module.EmitContainer ();
  400. if (module.HasExtensionMethod) {
  401. var pa = module.PredefinedAttributes.Extension;
  402. if (pa.IsDefined) {
  403. SetCustomAttribute (pa.Constructor, AttributeEncoder.Empty);
  404. }
  405. }
  406. if (!IsSatelliteAssembly) {
  407. if (!has_user_debuggable && Compiler.Settings.GenerateDebugInfo) {
  408. var pa = module.PredefinedAttributes.Debuggable;
  409. if (pa.IsDefined) {
  410. var modes = System.Diagnostics.DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints;
  411. if (!Compiler.Settings.Optimize)
  412. modes |= System.Diagnostics.DebuggableAttribute.DebuggingModes.DisableOptimizations;
  413. pa.EmitAttribute (Builder, modes);
  414. }
  415. }
  416. if (!wrap_non_exception_throws_custom) {
  417. PredefinedAttribute pa = module.PredefinedAttributes.RuntimeCompatibility;
  418. if (pa.IsDefined && pa.ResolveBuilder ()) {
  419. var prop = module.PredefinedMembers.RuntimeCompatibilityWrapNonExceptionThrows.Get ();
  420. if (prop != null) {
  421. AttributeEncoder encoder = new AttributeEncoder ();
  422. encoder.EncodeNamedPropertyArgument (prop, new BoolLiteral (Compiler.BuiltinTypes, true, Location.Null));
  423. SetCustomAttribute (pa.Constructor, encoder.ToArray ());
  424. }
  425. }
  426. }
  427. if (declarative_security != null) {
  428. #if STATIC
  429. foreach (var entry in declarative_security) {
  430. Builder.__AddDeclarativeSecurity (entry);
  431. }
  432. #else
  433. throw new NotSupportedException ("Assembly-level security");
  434. #endif
  435. }
  436. }
  437. CheckReferencesPublicToken ();
  438. SetEntryPoint ();
  439. }
  440. public byte[] GetPublicKeyToken ()
  441. {
  442. if (public_key == null || public_key_token != null)
  443. return public_key_token;
  444. HashAlgorithm ha = SHA1.Create ();
  445. byte[] hash = ha.ComputeHash (public_key);
  446. // we need the last 8 bytes in reverse order
  447. public_key_token = new byte[8];
  448. Buffer.BlockCopy (hash, hash.Length - 8, public_key_token, 0, 8);
  449. Array.Reverse (public_key_token, 0, 8);
  450. return public_key_token;
  451. }
  452. //
  453. // Either keyFile or keyContainer has to be non-null
  454. //
  455. void LoadPublicKey (string keyFile, string keyContainer)
  456. {
  457. if (keyContainer != null) {
  458. try {
  459. private_key = new StrongNameKeyPair (keyContainer);
  460. public_key = private_key.PublicKey;
  461. } catch {
  462. Error_AssemblySigning ("The specified key container `" + keyContainer + "' does not exist");
  463. }
  464. return;
  465. }
  466. bool key_file_exists = File.Exists (keyFile);
  467. //
  468. // For attribute based KeyFile do additional lookup
  469. // in output assembly path
  470. //
  471. if (!key_file_exists && Compiler.Settings.StrongNameKeyFile == null) {
  472. //
  473. // The key file can be relative to output assembly
  474. //
  475. string test_path = Path.Combine (Path.GetDirectoryName (file_name), keyFile);
  476. key_file_exists = File.Exists (test_path);
  477. if (key_file_exists)
  478. keyFile = test_path;
  479. }
  480. if (!key_file_exists) {
  481. Error_AssemblySigning ("The specified key file `" + keyFile + "' does not exist");
  482. return;
  483. }
  484. using (FileStream fs = new FileStream (keyFile, FileMode.Open, FileAccess.Read)) {
  485. byte[] snkeypair = new byte[fs.Length];
  486. fs.Read (snkeypair, 0, snkeypair.Length);
  487. // check for ECMA key
  488. if (snkeypair.Length == 16) {
  489. public_key = snkeypair;
  490. return;
  491. }
  492. try {
  493. // take it, with or without, a private key
  494. RSA rsa = CryptoConvert.FromCapiKeyBlob (snkeypair);
  495. // and make sure we only feed the public part to Sys.Ref
  496. byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
  497. // AssemblyName.SetPublicKey requires an additional header
  498. byte[] publicKeyHeader = new byte[8] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00 };
  499. // Encode public key
  500. public_key = new byte[12 + publickey.Length];
  501. Buffer.BlockCopy (publicKeyHeader, 0, public_key, 0, publicKeyHeader.Length);
  502. // Length of Public Key (in bytes)
  503. int lastPart = public_key.Length - 12;
  504. public_key[8] = (byte) (lastPart & 0xFF);
  505. public_key[9] = (byte) ((lastPart >> 8) & 0xFF);
  506. public_key[10] = (byte) ((lastPart >> 16) & 0xFF);
  507. public_key[11] = (byte) ((lastPart >> 24) & 0xFF);
  508. Buffer.BlockCopy (publickey, 0, public_key, 12, publickey.Length);
  509. } catch {
  510. Error_AssemblySigning ("The specified key file `" + keyFile + "' has incorrect format");
  511. return;
  512. }
  513. if (delay_sign)
  514. return;
  515. try {
  516. // TODO: Is there better way to test for a private key presence ?
  517. CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
  518. private_key = new StrongNameKeyPair (snkeypair);
  519. } catch { }
  520. }
  521. }
  522. void ReadModulesAssemblyAttributes ()
  523. {
  524. foreach (var m in added_modules) {
  525. var cattrs = m.ReadAssemblyAttributes ();
  526. if (cattrs == null)
  527. continue;
  528. module.OptAttributes.AddAttributes (cattrs);
  529. }
  530. }
  531. public void Resolve ()
  532. {
  533. if (Compiler.Settings.Unsafe && module.PredefinedTypes.SecurityAction.Define ()) {
  534. //
  535. // Emits [assembly: SecurityPermissionAttribute (SecurityAction.RequestMinimum, SkipVerification = true)]
  536. // when -unsafe option was specified
  537. //
  538. Location loc = Location.Null;
  539. MemberAccess system_security_permissions = new MemberAccess (new MemberAccess (
  540. new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Security", loc), "Permissions", loc);
  541. var req_min = module.PredefinedMembers.SecurityActionRequestMinimum.Resolve (loc);
  542. Arguments pos = new Arguments (1);
  543. pos.Add (new Argument (req_min.GetConstant (null)));
  544. Arguments named = new Arguments (1);
  545. named.Add (new NamedArgument ("SkipVerification", loc, new BoolLiteral (Compiler.BuiltinTypes, true, loc)));
  546. Attribute g = new Attribute ("assembly",
  547. new MemberAccess (system_security_permissions, "SecurityPermissionAttribute"),
  548. new Arguments[] { pos, named }, loc, false);
  549. g.AttachTo (module, module);
  550. // Disable no-location warnings (e.g. obsolete) for compiler generated attribute
  551. Compiler.Report.DisableReporting ();
  552. try {
  553. var ctor = g.Resolve ();
  554. if (ctor != null) {
  555. g.ExtractSecurityPermissionSet (ctor, ref declarative_security);
  556. }
  557. } finally {
  558. Compiler.Report.EnableReporting ();
  559. }
  560. }
  561. if (module.OptAttributes == null)
  562. return;
  563. // Ensure that we only have GlobalAttributes, since the Search isn't safe with other types.
  564. if (!module.OptAttributes.CheckTargets())
  565. return;
  566. cls_attribute = module.ResolveAssemblyAttribute (module.PredefinedAttributes.CLSCompliant);
  567. if (cls_attribute != null) {
  568. is_cls_compliant = cls_attribute.GetClsCompliantAttributeValue ();
  569. }
  570. if (added_modules != null && Compiler.Settings.VerifyClsCompliance && is_cls_compliant) {
  571. foreach (var m in added_modules) {
  572. if (!m.IsCLSCompliant) {
  573. Report.Error (3013,
  574. "Added modules must be marked with the CLSCompliant attribute to match the assembly",
  575. m.Name);
  576. }
  577. }
  578. }
  579. Attribute a = module.ResolveAssemblyAttribute (module.PredefinedAttributes.RuntimeCompatibility);
  580. if (a != null) {
  581. var val = a.GetNamedValue ("WrapNonExceptionThrows") as BoolConstant;
  582. if (val != null)
  583. wrap_non_exception_throws = val.Value;
  584. }
  585. }
  586. protected void ResolveAssemblySecurityAttributes ()
  587. {
  588. string key_file = null;
  589. string key_container = null;
  590. if (module.OptAttributes != null) {
  591. foreach (Attribute a in module.OptAttributes.Attrs) {
  592. // cannot rely on any resolve-based members before you call Resolve
  593. if (a.ExplicitTarget != "assembly")
  594. continue;
  595. // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
  596. // However, this is invoked by CodeGen.Init, when none of the namespaces
  597. // are loaded yet.
  598. // TODO: Does not handle quoted attributes properly
  599. switch (a.Name) {
  600. case "AssemblyKeyFile":
  601. case "AssemblyKeyFileAttribute":
  602. case "System.Reflection.AssemblyKeyFileAttribute":
  603. if (Compiler.Settings.StrongNameKeyFile != null) {
  604. Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
  605. Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
  606. "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
  607. } else {
  608. string value = a.GetString ();
  609. if (!string.IsNullOrEmpty (value)) {
  610. Error_ObsoleteSecurityAttribute (a, "keyfile");
  611. key_file = value;
  612. }
  613. }
  614. break;
  615. case "AssemblyKeyName":
  616. case "AssemblyKeyNameAttribute":
  617. case "System.Reflection.AssemblyKeyNameAttribute":
  618. if (Compiler.Settings.StrongNameKeyContainer != null) {
  619. Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
  620. Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
  621. "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
  622. } else {
  623. string value = a.GetString ();
  624. if (!string.IsNullOrEmpty (value)) {
  625. Error_ObsoleteSecurityAttribute (a, "keycontainer");
  626. key_container = value;
  627. }
  628. }
  629. break;
  630. case "AssemblyDelaySign":
  631. case "AssemblyDelaySignAttribute":
  632. case "System.Reflection.AssemblyDelaySignAttribute":
  633. bool b = a.GetBoolean ();
  634. if (b) {
  635. Error_ObsoleteSecurityAttribute (a, "delaysign");
  636. }
  637. delay_sign = b;
  638. break;
  639. }
  640. }
  641. }
  642. // We came here only to report assembly attributes warnings
  643. if (public_key != null)
  644. return;
  645. //
  646. // Load the strong key file found in attributes when no
  647. // command line key was given
  648. //
  649. if (key_file != null || key_container != null) {
  650. LoadPublicKey (key_file, key_container);
  651. } else if (delay_sign) {
  652. Report.Warning (1607, 1, "Delay signing was requested but no key file was given");
  653. }
  654. }
  655. public void EmbedResources ()
  656. {
  657. //
  658. // Add Win32 resources
  659. //
  660. if (Compiler.Settings.Win32ResourceFile != null) {
  661. Builder.DefineUnmanagedResource (Compiler.Settings.Win32ResourceFile);
  662. } else {
  663. Builder.DefineVersionInfoResource (vi_product, vi_product_version, vi_company, vi_copyright, vi_trademark);
  664. }
  665. if (Compiler.Settings.Win32IconFile != null) {
  666. builder_extra.DefineWin32IconResource (Compiler.Settings.Win32IconFile);
  667. }
  668. if (Compiler.Settings.Resources != null) {
  669. if (Compiler.Settings.Target == Target.Module) {
  670. Report.Error (1507, "Cannot link resource file when building a module");
  671. } else {
  672. int counter = 0;
  673. foreach (var res in Compiler.Settings.Resources) {
  674. if (!File.Exists (res.FileName)) {
  675. Report.Error (1566, "Error reading resource file `{0}'", res.FileName);
  676. continue;
  677. }
  678. if (res.IsEmbeded) {
  679. Stream stream;
  680. if (counter++ < 10) {
  681. stream = File.OpenRead (res.FileName);
  682. } else {
  683. // TODO: SRE API requires resource stream to be available during AssemblyBuilder::Save
  684. // we workaround it by reading everything into memory to compile projects with
  685. // many embedded resource (over 3500) references
  686. stream = new MemoryStream (File.ReadAllBytes (res.FileName));
  687. }
  688. module.Builder.DefineManifestResource (res.Name, stream, res.Attributes);
  689. } else {
  690. Builder.AddResourceFile (res.Name, Path.GetFileName (res.FileName), res.Attributes);
  691. }
  692. }
  693. }
  694. }
  695. }
  696. public void Save ()
  697. {
  698. PortableExecutableKinds pekind = PortableExecutableKinds.ILOnly;
  699. ImageFileMachine machine;
  700. switch (Compiler.Settings.Platform) {
  701. case Platform.X86:
  702. pekind |= PortableExecutableKinds.Required32Bit;
  703. machine = ImageFileMachine.I386;
  704. break;
  705. case Platform.X64:
  706. pekind |= PortableExecutableKinds.PE32Plus;
  707. machine = ImageFileMachine.AMD64;
  708. break;
  709. case Platform.IA64:
  710. machine = ImageFileMachine.IA64;
  711. break;
  712. case Platform.AnyCPU32Preferred:
  713. #if STATIC
  714. pekind |= PortableExecutableKinds.Preferred32Bit;
  715. machine = ImageFileMachine.I386;
  716. break;
  717. #else
  718. throw new NotSupportedException ();
  719. #endif
  720. case Platform.Arm:
  721. #if STATIC
  722. machine = ImageFileMachine.ARM;
  723. break;
  724. #else
  725. throw new NotSupportedException ();
  726. #endif
  727. case Platform.AnyCPU:
  728. default:
  729. machine = ImageFileMachine.I386;
  730. break;
  731. }
  732. Compiler.TimeReporter.Start (TimeReporter.TimerType.OutputSave);
  733. try {
  734. if (Compiler.Settings.Target == Target.Module) {
  735. SaveModule (pekind, machine);
  736. } else {
  737. Builder.Save (module.Builder.ScopeName, pekind, machine);
  738. }
  739. } catch (Exception e) {
  740. Report.Error (16, "Could not write to file `" + name + "', cause: " + e.Message);
  741. }
  742. Compiler.TimeReporter.Stop (TimeReporter.TimerType.OutputSave);
  743. // Save debug symbols file
  744. if (symbol_writer != null && Compiler.Report.Errors == 0) {
  745. // TODO: it should run in parallel
  746. Compiler.TimeReporter.Start (TimeReporter.TimerType.DebugSave);
  747. var filename = file_name + ".mdb";
  748. try {
  749. // We mmap the file, so unlink the previous version since it may be in use
  750. File.Delete (filename);
  751. } catch {
  752. // We can safely ignore
  753. }
  754. module.WriteDebugSymbol (symbol_writer);
  755. using (FileStream fs = new FileStream (filename, FileMode.Create, FileAccess.Write)) {
  756. symbol_writer.CreateSymbolFile (module.Builder.ModuleVersionId, fs);
  757. }
  758. Compiler.TimeReporter.Stop (TimeReporter.TimerType.DebugSave);
  759. }
  760. }
  761. protected virtual void SaveModule (PortableExecutableKinds pekind, ImageFileMachine machine)
  762. {
  763. Report.RuntimeMissingSupport (Location.Null, "-target:module");
  764. }
  765. void SetCustomAttribute (MethodSpec ctor, byte[] data)
  766. {
  767. if (module_target_attrs != null)
  768. module_target_attrs.AddAssemblyAttribute (ctor, data);
  769. else
  770. Builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), data);
  771. }
  772. void SetEntryPoint ()
  773. {
  774. if (!Compiler.Settings.NeedsEntryPoint) {
  775. if (Compiler.Settings.MainClass != null)
  776. Report.Error (2017, "Cannot specify -main if building a module or library");
  777. return;
  778. }
  779. PEFileKinds file_kind;
  780. switch (Compiler.Settings.Target) {
  781. case Target.Library:
  782. case Target.Module:
  783. file_kind = PEFileKinds.Dll;
  784. break;
  785. case Target.WinExe:
  786. file_kind = PEFileKinds.WindowApplication;
  787. break;
  788. default:
  789. file_kind = PEFileKinds.ConsoleApplication;
  790. break;
  791. }
  792. if (entry_point == null) {
  793. string main_class = Compiler.Settings.MainClass;
  794. if (main_class != null) {
  795. // TODO: Handle dotted names
  796. var texpr = module.GlobalRootNamespace.LookupType (module, main_class, 0, LookupMode.Probing, Location.Null);
  797. if (texpr == null) {
  798. Report.Error (1555, "Could not find `{0}' specified for Main method", main_class);
  799. return;
  800. }
  801. var mtype = texpr.MemberDefinition as ClassOrStruct;
  802. if (mtype == null) {
  803. Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", main_class);
  804. return;
  805. }
  806. Report.Error (1558, mtype.Location, "`{0}' does not have a suitable static Main method", mtype.GetSignatureForError ());
  807. } else {
  808. string pname = file_name == null ? name : Path.GetFileName (file_name);
  809. Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
  810. pname);
  811. }
  812. return;
  813. }
  814. Builder.SetEntryPoint (entry_point.MethodBuilder, file_kind);
  815. }
  816. void Error_ObsoleteSecurityAttribute (Attribute a, string option)
  817. {
  818. Report.Warning (1699, 1, a.Location,
  819. "Use compiler option `{0}' or appropriate project settings instead of `{1}' attribute",
  820. option, a.Name);
  821. }
  822. void Error_AssemblySigning (string text)
  823. {
  824. Report.Error (1548, "Error during assembly signing. " + text);
  825. }
  826. public bool IsFriendAssemblyTo (IAssemblyDefinition assembly)
  827. {
  828. return false;
  829. }
  830. static Version IsValidAssemblyVersion (string version, bool allowGenerated)
  831. {
  832. string[] parts = version.Split ('.');
  833. if (parts.Length < 1 || parts.Length > 4)
  834. return null;
  835. var values = new int[4];
  836. for (int i = 0; i < parts.Length; ++i) {
  837. if (!int.TryParse (parts[i], out values[i])) {
  838. if (parts[i].Length == 1 && parts[i][0] == '*' && allowGenerated) {
  839. if (i == 2) {
  840. // Nothing can follow *
  841. if (parts.Length > 3)
  842. return null;
  843. // Generate Build value based on days since 1/1/2000
  844. TimeSpan days = DateTime.Today - new DateTime (2000, 1, 1);
  845. values[i] = System.Math.Max (days.Days, 0);
  846. i = 3;
  847. }
  848. if (i == 3) {
  849. // Generate Revision value based on every other second today
  850. var seconds = DateTime.Now - DateTime.Today;
  851. values[i] = (int) seconds.TotalSeconds / 2;
  852. continue;
  853. }
  854. }
  855. return null;
  856. }
  857. if (values[i] > ushort.MaxValue)
  858. return null;
  859. }
  860. return new Version (values[0], values[1], values[2], values[3]);
  861. }
  862. }
  863. public class AssemblyResource : IEquatable<AssemblyResource>
  864. {
  865. public AssemblyResource (string fileName, string name)
  866. : this (fileName, name, false)
  867. {
  868. }
  869. public AssemblyResource (string fileName, string name, bool isPrivate)
  870. {
  871. FileName = fileName;
  872. Name = name;
  873. Attributes = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
  874. }
  875. public ResourceAttributes Attributes { get; private set; }
  876. public string Name { get; private set; }
  877. public string FileName { get; private set; }
  878. public bool IsEmbeded { get; set; }
  879. #region IEquatable<AssemblyResource> Members
  880. public bool Equals (AssemblyResource other)
  881. {
  882. return Name == other.Name;
  883. }
  884. #endregion
  885. }
  886. //
  887. // A placeholder class for assembly attributes when emitting module
  888. //
  889. class AssemblyAttributesPlaceholder : CompilerGeneratedContainer
  890. {
  891. static readonly string TypeNamePrefix = "<$AssemblyAttributes${0}>";
  892. public static readonly string AssemblyFieldName = "attributes";
  893. Field assembly;
  894. public AssemblyAttributesPlaceholder (ModuleContainer parent, string outputName)
  895. : base (parent, new MemberName (GetGeneratedName (outputName)), Modifiers.STATIC | Modifiers.INTERNAL)
  896. {
  897. assembly = new Field (this, new TypeExpression (parent.Compiler.BuiltinTypes.Object, Location), Modifiers.PUBLIC | Modifiers.STATIC,
  898. new MemberName (AssemblyFieldName), null);
  899. AddField (assembly);
  900. }
  901. public void AddAssemblyAttribute (MethodSpec ctor, byte[] data)
  902. {
  903. assembly.SetCustomAttribute (ctor, data);
  904. }
  905. public static string GetGeneratedName (string outputName)
  906. {
  907. return string.Format (TypeNamePrefix, outputName);
  908. }
  909. }
  910. //
  911. // Extension to System.Reflection.Emit.AssemblyBuilder to have fully compatible
  912. // compiler. This is a default implementation for framework System.Reflection.Emit
  913. // which does not implement any of the methods
  914. //
  915. public class AssemblyBuilderExtension
  916. {
  917. readonly CompilerContext ctx;
  918. public AssemblyBuilderExtension (CompilerContext ctx)
  919. {
  920. this.ctx = ctx;
  921. }
  922. public virtual System.Reflection.Module AddModule (string module)
  923. {
  924. ctx.Report.RuntimeMissingSupport (Location.Null, "-addmodule");
  925. return null;
  926. }
  927. public virtual void AddPermissionRequests (PermissionSet[] permissions)
  928. {
  929. ctx.Report.RuntimeMissingSupport (Location.Null, "assembly declarative security");
  930. }
  931. public virtual void AddTypeForwarder (TypeSpec type, Location loc)
  932. {
  933. ctx.Report.RuntimeMissingSupport (loc, "TypeForwardedToAttribute");
  934. }
  935. public virtual void DefineWin32IconResource (string fileName)
  936. {
  937. ctx.Report.RuntimeMissingSupport (Location.Null, "-win32icon");
  938. }
  939. public virtual void SetAlgorithmId (uint value, Location loc)
  940. {
  941. ctx.Report.RuntimeMissingSupport (loc, "AssemblyAlgorithmIdAttribute");
  942. }
  943. public virtual void SetCulture (string culture, Location loc)
  944. {
  945. ctx.Report.RuntimeMissingSupport (loc, "AssemblyCultureAttribute");
  946. }
  947. public virtual void SetFlags (uint flags, Location loc)
  948. {
  949. ctx.Report.RuntimeMissingSupport (loc, "AssemblyFlagsAttribute");
  950. }
  951. public virtual void SetVersion (Version version, Location loc)
  952. {
  953. ctx.Report.RuntimeMissingSupport (loc, "AssemblyVersionAttribute");
  954. }
  955. }
  956. abstract class AssemblyReferencesLoader<T> where T : class
  957. {
  958. protected readonly CompilerContext compiler;
  959. protected readonly List<string> paths;
  960. protected AssemblyReferencesLoader (CompilerContext compiler)
  961. {
  962. this.compiler = compiler;
  963. paths = new List<string> ();
  964. paths.Add (Directory.GetCurrentDirectory ());
  965. paths.AddRange (compiler.Settings.ReferencesLookupPaths);
  966. }
  967. public abstract bool HasObjectType (T assembly);
  968. protected abstract string[] GetDefaultReferences ();
  969. public abstract T LoadAssemblyFile (string fileName, bool isImplicitReference);
  970. public abstract void LoadReferences (ModuleContainer module);
  971. protected void Error_FileNotFound (string fileName)
  972. {
  973. compiler.Report.Error (6, "Metadata file `{0}' could not be found", fileName);
  974. }
  975. protected void Error_FileCorrupted (string fileName)
  976. {
  977. compiler.Report.Error (9, "Metadata file `{0}' does not contain valid metadata", fileName);
  978. }
  979. protected void Error_AssemblyIsModule (string fileName)
  980. {
  981. compiler.Report.Error (1509,
  982. "Referenced assembly file `{0}' is a module. Consider using `-addmodule' option to add the module",
  983. fileName);
  984. }
  985. protected void Error_ModuleIsAssembly (string fileName)
  986. {
  987. compiler.Report.Error (1542,
  988. "Added module file `{0}' is an assembly. Consider using `-r' option to reference the file",
  989. fileName);
  990. }
  991. protected void LoadReferencesCore (ModuleContainer module, out T corlib_assembly, out List<Tuple<RootNamespace, T>> loaded)
  992. {
  993. compiler.TimeReporter.Start (TimeReporter.TimerType.ReferencesLoading);
  994. loaded = new List<Tuple<RootNamespace, T>> ();
  995. //
  996. // Load mscorlib.dll as the first
  997. //
  998. if (module.Compiler.Settings.StdLib) {
  999. corlib_assembly = LoadAssemblyFile ("mscorlib.dll", true);
  1000. } else {
  1001. corlib_assembly = default (T);
  1002. }
  1003. T a;
  1004. foreach (string r in module.Compiler.Settings.AssemblyReferences) {
  1005. a = LoadAssemblyFile (r, false);
  1006. if (a == null || EqualityComparer<T>.Default.Equals (a, corlib_assembly))
  1007. continue;
  1008. var key = Tuple.Create (module.GlobalRootNamespace, a);
  1009. if (loaded.Contains (key))
  1010. continue;
  1011. loaded.Add (key);
  1012. }
  1013. if (corlib_assembly == null) {
  1014. //
  1015. // Requires second pass because HasObjectType can trigger assembly load event
  1016. //
  1017. for (int i = 0; i < loaded.Count; ++i) {
  1018. var assembly = loaded [i];
  1019. //
  1020. // corlib assembly is the first referenced assembly which contains System.Object
  1021. //
  1022. if (HasObjectType (assembly.Item2)) {
  1023. corlib_assembly = assembly.Item2;
  1024. loaded.RemoveAt (i);
  1025. break;
  1026. }
  1027. }
  1028. }
  1029. foreach (var entry in module.Compiler.Settings.AssemblyReferencesAliases) {
  1030. a = LoadAssemblyFile (entry.Item2, false);
  1031. if (a == null)
  1032. continue;
  1033. var key = Tuple.Create (module.CreateRootNamespace (entry.Item1), a);
  1034. if (loaded.Contains (key))
  1035. continue;
  1036. loaded.Add (key);
  1037. }
  1038. if (compiler.Settings.LoadDefaultReferences) {
  1039. foreach (string r in GetDefaultReferences ()) {
  1040. a = LoadAssemblyFile (r, true);
  1041. if (a == null)
  1042. continue;
  1043. var key = Tuple.Create (module.GlobalRootNamespace, a);
  1044. if (loaded.Contains (key))
  1045. continue;
  1046. loaded.Add (key);
  1047. }
  1048. }
  1049. compiler.TimeReporter.Stop (TimeReporter.TimerType.ReferencesLoading);
  1050. }
  1051. }
  1052. }