Compiler.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. //------------------------------------------------------------------------------
  2. // <copyright file="Compiler.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">Microsoft</owner>
  6. //------------------------------------------------------------------------------
  7. namespace System.Xml.Serialization {
  8. using System.Reflection;
  9. using System.Reflection.Emit;
  10. using System.Collections;
  11. using System.IO;
  12. using System;
  13. using System.Text;
  14. using System.ComponentModel;
  15. using System.CodeDom.Compiler;
  16. using System.Security;
  17. using System.Security.Permissions;
  18. using System.Diagnostics;
  19. using System.Security.Principal;
  20. using System.Security.Policy;
  21. using System.Threading;
  22. using System.Xml.Serialization.Configuration;
  23. using System.Globalization;
  24. using System.Runtime.Versioning;
  25. using System.Runtime.CompilerServices;
  26. internal class Compiler {
  27. bool debugEnabled = DiagnosticsSwitches.KeepTempFiles.Enabled;
  28. Hashtable imports = new Hashtable();
  29. StringWriter writer = new StringWriter(CultureInfo.InvariantCulture);
  30. [ResourceExposure(ResourceScope.Machine)]
  31. protected string[] Imports {
  32. get {
  33. string[] array = new string[imports.Values.Count];
  34. imports.Values.CopyTo(array, 0);
  35. return array;
  36. }
  37. }
  38. // SxS: This method does not take any resource name and does not expose any resources to the caller.
  39. // It's OK to suppress the SxS warning.
  40. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  41. [ResourceExposure(ResourceScope.None)]
  42. internal void AddImport(Type type, Hashtable types) {
  43. if (type == null)
  44. return;
  45. if (TypeScope.IsKnownType(type))
  46. return;
  47. if (types[type] != null)
  48. return;
  49. types[type] = type;
  50. Type baseType = type.BaseType;
  51. if (baseType != null)
  52. AddImport(baseType, types);
  53. Type declaringType = type.DeclaringType;
  54. if (declaringType != null)
  55. AddImport(declaringType, types);
  56. foreach (Type intf in type.GetInterfaces())
  57. AddImport(intf, types);
  58. ConstructorInfo[] ctors = type.GetConstructors();
  59. for (int i = 0; i < ctors.Length; i++) {
  60. ParameterInfo[] parms = ctors[i].GetParameters();
  61. for (int j = 0; j < parms.Length; j++) {
  62. AddImport(parms[j].ParameterType, types);
  63. }
  64. }
  65. if (type.IsGenericType) {
  66. Type[] arguments = type.GetGenericArguments();
  67. for (int i = 0; i < arguments.Length; i++) {
  68. AddImport(arguments[i], types);
  69. }
  70. }
  71. TempAssembly.FileIOPermission.Assert();
  72. Module module = type.Module;
  73. Assembly assembly = module.Assembly;
  74. if (DynamicAssemblies.IsTypeDynamic(type)) {
  75. DynamicAssemblies.Add(assembly);
  76. return;
  77. }
  78. object[] typeForwardedFromAttribute = type.GetCustomAttributes(typeof(TypeForwardedFromAttribute), false);
  79. if (typeForwardedFromAttribute.Length > 0)
  80. {
  81. TypeForwardedFromAttribute originalAssemblyInfo = typeForwardedFromAttribute[0] as TypeForwardedFromAttribute;
  82. Assembly originalAssembly = Assembly.Load(originalAssemblyInfo.AssemblyFullName);
  83. imports[originalAssembly] = originalAssembly.Location;
  84. }
  85. imports[assembly] = assembly.Location;
  86. }
  87. // SxS: This method does not take any resource name and does not expose any resources to the caller.
  88. // It's OK to suppress the SxS warning.
  89. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  90. [ResourceExposure(ResourceScope.None)]
  91. internal void AddImport(Assembly assembly) {
  92. TempAssembly.FileIOPermission.Assert();
  93. imports[assembly] = assembly.Location;
  94. }
  95. internal TextWriter Source {
  96. get { return writer; }
  97. }
  98. internal void Close() { }
  99. [ResourceConsumption(ResourceScope.Machine)]
  100. [ResourceExposure(ResourceScope.Machine)]
  101. internal static string GetTempAssemblyPath(string baseDir, Assembly assembly, string defaultNamespace) {
  102. if (assembly.IsDynamic) {
  103. throw new InvalidOperationException(Res.GetString(Res.XmlPregenAssemblyDynamic));
  104. }
  105. PermissionSet perms = new PermissionSet(PermissionState.None);
  106. perms.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
  107. perms.AddPermission(new EnvironmentPermission(PermissionState.Unrestricted));
  108. perms.Assert();
  109. try {
  110. if (baseDir != null && baseDir.Length > 0) {
  111. // check that the dirsctory exists
  112. if (!Directory.Exists(baseDir)) {
  113. throw new UnauthorizedAccessException(Res.GetString(Res.XmlPregenMissingDirectory, baseDir));
  114. }
  115. }
  116. else {
  117. baseDir = Path.GetTempPath();
  118. // check that the dirsctory exists
  119. if (!Directory.Exists(baseDir)) {
  120. throw new UnauthorizedAccessException(Res.GetString(Res.XmlPregenMissingTempDirectory));
  121. }
  122. }
  123. #if MONO
  124. baseDir = Path.Combine (baseDir, GetTempAssemblyName(assembly.GetName(), defaultNamespace));
  125. #else
  126. if (baseDir.EndsWith("\\", StringComparison.Ordinal))
  127. baseDir += GetTempAssemblyName(assembly.GetName(), defaultNamespace);
  128. else
  129. baseDir += "\\" + GetTempAssemblyName(assembly.GetName(), defaultNamespace);
  130. #endif
  131. }
  132. finally {
  133. CodeAccessPermission.RevertAssert();
  134. }
  135. return baseDir + ".dll";
  136. }
  137. internal static string GetTempAssemblyName(AssemblyName parent, string ns) {
  138. return parent.Name + ".XmlSerializers" + (ns == null || ns.Length == 0 ? "" : "." + ns.GetHashCode());
  139. }
  140. // SxS: This method does not take any resource name and does not expose any resources to the caller.
  141. // It's OK to suppress the SxS warning.
  142. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  143. [ResourceExposure(ResourceScope.None)]
  144. internal Assembly Compile(Assembly parent, string ns, XmlSerializerCompilerParameters xmlParameters, Evidence evidence) {
  145. CodeDomProvider codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
  146. CompilerParameters parameters = xmlParameters.CodeDomParameters;
  147. parameters.ReferencedAssemblies.AddRange(Imports);
  148. if (debugEnabled) {
  149. parameters.GenerateInMemory = false;
  150. parameters.IncludeDebugInformation = true;
  151. parameters.TempFiles.KeepFiles = true;
  152. }
  153. PermissionSet perms = new PermissionSet(PermissionState.None);
  154. if (xmlParameters.IsNeedTempDirAccess) {
  155. perms.AddPermission(TempAssembly.FileIOPermission);
  156. }
  157. perms.AddPermission(new EnvironmentPermission(PermissionState.Unrestricted));
  158. perms.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode));
  159. perms.AddPermission(new SecurityPermission(SecurityPermissionFlag.ControlEvidence));
  160. perms.Assert();
  161. if (parent != null && (parameters.OutputAssembly == null || parameters.OutputAssembly.Length ==0)) {
  162. string assemblyName = AssemblyNameFromOptions(parameters.CompilerOptions);
  163. if (assemblyName == null)
  164. assemblyName = GetTempAssemblyPath(parameters.TempFiles.TempDir, parent, ns);
  165. //
  166. parameters.OutputAssembly = assemblyName;
  167. }
  168. if (parameters.CompilerOptions == null || parameters.CompilerOptions.Length == 0)
  169. parameters.CompilerOptions = "/nostdlib";
  170. else
  171. parameters.CompilerOptions += " /nostdlib";
  172. parameters.CompilerOptions += " /D:_DYNAMIC_XMLSERIALIZER_COMPILATION";
  173. #pragma warning disable 618
  174. parameters.Evidence = evidence;
  175. #pragma warning restore 618
  176. CompilerResults results = null;
  177. Assembly assembly = null;
  178. try {
  179. results = codeProvider.CompileAssemblyFromSource(parameters, writer.ToString());
  180. // check the output for errors or a certain level-1 warning (1595)
  181. if (results.Errors.Count > 0) {
  182. StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
  183. stringWriter.WriteLine(Res.GetString(Res.XmlCompilerError, results.NativeCompilerReturnValue.ToString(CultureInfo.InvariantCulture)));
  184. bool foundOne = false;
  185. foreach (CompilerError e in results.Errors) {
  186. // clear filename. This makes ToString() print just error number and message.
  187. e.FileName = "";
  188. if (!e.IsWarning || e.ErrorNumber == "CS1595") {
  189. foundOne = true;
  190. stringWriter.WriteLine(e.ToString());
  191. }
  192. }
  193. if (foundOne) {
  194. throw new InvalidOperationException(stringWriter.ToString());
  195. }
  196. }
  197. assembly = results.CompiledAssembly;
  198. }
  199. catch (UnauthorizedAccessException) {
  200. // try to get the user token
  201. string user = GetCurrentUser();
  202. if (user == null || user.Length == 0) {
  203. throw new UnauthorizedAccessException(Res.GetString(Res.XmlSerializerAccessDenied));
  204. }
  205. else {
  206. throw new UnauthorizedAccessException(Res.GetString(Res.XmlIdentityAccessDenied, user));
  207. }
  208. }
  209. catch (FileLoadException fle) {
  210. throw new InvalidOperationException(Res.GetString(Res.XmlSerializerCompileFailed), fle);
  211. }
  212. finally {
  213. CodeAccessPermission.RevertAssert();
  214. }
  215. // somehow we got here without generating an assembly
  216. if (assembly == null) throw new InvalidOperationException(Res.GetString(Res.XmlInternalError));
  217. return assembly;
  218. }
  219. static string AssemblyNameFromOptions(string options) {
  220. if (options == null || options.Length == 0)
  221. return null;
  222. string outName = null;
  223. string[] flags = options.ToLower(CultureInfo.InvariantCulture).Split(null);
  224. for (int i = 0; i < flags.Length; i++) {
  225. string val = flags[i].Trim();
  226. if (val.StartsWith("/out:", StringComparison.Ordinal)) {
  227. outName = val.Substring(5);
  228. }
  229. }
  230. return outName;
  231. }
  232. internal static string GetCurrentUser()
  233. {
  234. #if !FEATURE_PAL
  235. try {
  236. WindowsIdentity id = WindowsIdentity.GetCurrent();
  237. if (id != null && id.Name != null)
  238. return id.Name;
  239. }
  240. catch (Exception e) {
  241. if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
  242. throw;
  243. }
  244. }
  245. #endif // !FEATURE_PAL
  246. return "";
  247. }
  248. }
  249. }