[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / utilcode / clrconfig.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //*****************************************************************************
5 // CLRConfig.cpp
6 // 
7
8 //
9 // Unified method of accessing configuration values from environment variables,
10 // registry and config file. See file:../inc/CLRConfigValues.h for details on how to add config values.
11 // 
12 //*****************************************************************************
13
14 #include "stdafx.h"
15 #include "clrconfig.h"
16
17 #ifndef ERANGE
18 #define ERANGE 34
19 #endif
20
21 //
22 // Initialize the EEConfig::GetConfiguration function pointer to NULL. If EEConfig isn't init'ed, this will
23 // stay NULL and CLRConfig will ignore config files.
24 //
25 CLRConfig::GetConfigValueFunction CLRConfig::s_GetConfigValueCallback = NULL;
26
27 // 
28 // Creating structs using the macro table in CLRConfigValues.h
29 // 
30
31 // These macros intialize ConfigDWORDInfo structs.
32 #define RETAIL_CONFIG_DWORD_INFO(symbol, name, defaultValue, description) \
33     const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, CLRConfig::EEConfig_default};
34 #define RETAIL_CONFIG_DWORD_INFO_EX(symbol, name, defaultValue, description, lookupOptions) \
35     const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, lookupOptions};
36
37 // These macros intialize ConfigStringInfo structs.
38 #define RETAIL_CONFIG_STRING_INFO(symbol, name, description) \
39     const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, CLRConfig::EEConfig_default};
40 #define RETAIL_CONFIG_STRING_INFO_EX(symbol, name, description, lookupOptions) \
41     const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, lookupOptions};
42
43 // TEMPORARY macros that intialize strings for config value accesses that haven't been moved over to
44 // CLRConfig yet. Once all accesses have been moved, these macros (and corresponding instantiations in
45 // file:../utilcode/CLRConfig.h) should be removed.
46 #define RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(symbol, name, description) \
47     const LPCWSTR CLRConfig::symbol = name;
48 #define RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(symbol, name, description) \
49     const LPCWSTR CLRConfig::symbol = name;
50 // 
51 // Debug versions of the macros
52 // 
53 #ifdef _DEBUG
54     #define CONFIG_DWORD_INFO(symbol, name, defaultValue, description) \
55         const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, CLRConfig::EEConfig_default};
56     #define CONFIG_DWORD_INFO_EX(symbol, name, defaultValue, description, lookupOptions) \
57         const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, lookupOptions};
58     #define CONFIG_STRING_INFO(symbol, name, description) \
59         const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, CLRConfig::EEConfig_default};
60     #define CONFIG_STRING_INFO_EX(symbol, name, description, lookupOptions) \
61         const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, lookupOptions};
62     #define CONFIG_DWORD_INFO_DIRECT_ACCESS(symbol, name, description) \
63         const LPCWSTR CLRConfig::symbol = name;
64     #define CONFIG_STRING_INFO_DIRECT_ACCESS(symbol, name, description) \
65         const LPCWSTR CLRConfig::symbol = name;
66 #else
67     #define CONFIG_DWORD_INFO(symbol, name, defaultValue, description)
68     #define CONFIG_DWORD_INFO_EX(symbol, name, defaultValue, description, lookupOptions)
69     #define CONFIG_STRING_INFO(symbol, name, description)
70     #define CONFIG_STRING_INFO_EX(symbol, name, description, lookupOptions)
71     #define CONFIG_DWORD_INFO_DIRECT_ACCESS(symbol, name, description)
72     #define CONFIG_STRING_INFO_DIRECT_ACCESS(symbol, name, description)
73 #endif // _DEBUG
74     
75     // Now that we have defined what what the macros in file:../inc/CLRConfigValues.h mean, include it to generate the code.
76     #include "clrconfigvalues.h"
77
78 #undef RETAIL_CONFIG_DWORD_INFO
79 #undef RETAIL_CONFIG_STRING_INFO
80 #undef RETAIL_CONFIG_DWORD_INFO_EX
81 #undef RETAIL_CONFIG_STRING_INFO_EX    
82 #undef RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS
83 #undef RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS
84 #undef CONFIG_DWORD_INFO
85 #undef CONFIG_STRING_INFO
86 #undef CONFIG_DWORD_INFO_EX
87 #undef CONFIG_STRING_INFO_EX    
88 #undef CONFIG_DWORD_INFO_DIRECT_ACCESS
89 #undef CONFIG_STRING_INFO_DIRECT_ACCESS
90
91
92
93
94 // Return if a quirk is a enabled.
95 // This will also return enabled as true when the quirk has a value set.
96 BOOL CLRConfig::IsConfigEnabled(const ConfigDWORDInfo & info)
97 {
98     CONTRACTL
99     {
100         NOTHROW;
101         GC_NOTRIGGER;
102         FORBID_FAULT;
103     }
104     CONTRACTL_END;
105
106     DWORD result = info.defaultValue;
107
108     //
109     // Set up REGUTIL options.
110     // 
111     REGUTIL::CORConfigLevel level = GetConfigLevel(info.options);
112     BOOL prependCOMPlus = !CheckLookupOption(info, DontPrependCOMPlus_);
113     
114     // 
115     // If we aren't favoring config files, we check REGUTIL here.
116     // 
117     if(CheckLookupOption(info, FavorConfigFile) == FALSE)
118     {
119         REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPlus);
120         if(result>0)
121             return TRUE;
122         LPWSTR result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPlus, level);
123         if(result != NULL && result[0] != 0)
124         {
125             return TRUE;
126         }
127     }
128
129     // 
130     // Check config files through EEConfig.
131     // 
132     if(CheckLookupOption(info, IgnoreConfigFiles) == FALSE && // Check that we aren't ignoring config files.
133         s_GetConfigValueCallback != NULL)// Check that GetConfigValueCallback function has been registered.
134     {        
135         LPCWSTR pvalue;
136
137         // EEConfig lookup options.
138         BOOL systemOnly = CheckLookupOption(info, ConfigFile_SystemOnly) ? TRUE : FALSE;
139         BOOL applicationFirst = CheckLookupOption(info, ConfigFile_ApplicationFirst) ? TRUE : FALSE;
140         
141         if(SUCCEEDED(s_GetConfigValueCallback(info.name, &pvalue, systemOnly, applicationFirst)) && pvalue != NULL)
142         {
143             WCHAR * end;
144             errno = 0;
145             result = wcstoul(pvalue, &end, 0);
146             
147             // errno is ERANGE if the number is out of range, and end is set to pvalue if
148             // no valid conversion exists.
149             if (errno == ERANGE || end == pvalue)
150             {
151                 if(pvalue[0]!=0)
152                     return TRUE;
153
154                 result = info.defaultValue; 
155             }
156             
157             if(result>0)
158                 return TRUE;
159         }
160     }
161
162     // 
163     // If we are favoring config files and we don't have a result from EEConfig, we check REGUTIL here.
164     // 
165     if(CheckLookupOption(info, FavorConfigFile) == TRUE)
166     {
167         REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPlus);
168         if(result>0)
169             return TRUE;
170         LPWSTR result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPlus, level);
171         if(result != NULL && result[0] != 0)
172         {
173             return TRUE;
174         }
175     }
176
177     if(info.defaultValue>0)
178         return TRUE;
179     else
180         return FALSE;
181 }
182
183 // 
184 // Look up a DWORD config value.
185 // 
186 // Arguments:
187 //     * info - see file:../inc/CLRConfig.h for details.
188 //
189 //     * useDefaultIfNotSet - if true, fall back to the default value if the value is not set.
190 //
191 //     * acceptExplicitDefaultFromRegutil - if false, only accept a value returned by REGUTIL if it is
192 //           different from the default value. This parameter is useful as a way to preserve existing
193 //           behavior.
194 //
195 //     * result - the result.
196 //
197 // Return value:
198 //     * true for success, false otherwise.
199 // 
200 // static
201 DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info, bool acceptExplicitDefaultFromRegutil, /* [Out] */ bool *isDefault)
202 {
203     CONTRACTL
204     {
205         NOTHROW;
206         GC_NOTRIGGER;
207         FORBID_FAULT;
208     }
209     CONTRACTL_END;
210
211     _ASSERTE (isDefault != nullptr);
212
213
214     //
215     // Set up REGUTIL options.
216     // 
217     REGUTIL::CORConfigLevel level = GetConfigLevel(info.options);
218     BOOL prependCOMPlus = !CheckLookupOption(info, DontPrependCOMPlus_);
219     
220     // 
221     // If we aren't favoring config files, we check REGUTIL here.
222     // 
223     if (CheckLookupOption(info, FavorConfigFile) == FALSE)
224     {
225         DWORD resultMaybe;
226         HRESULT hr = REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &resultMaybe, level, prependCOMPlus);
227
228         if (!acceptExplicitDefaultFromRegutil)
229         {
230             // Ignore the default value even if it's set explicitly.
231             if (resultMaybe != info.defaultValue)
232             {
233                 *isDefault = false;
234                 return resultMaybe;
235             }
236         }
237         else
238         {
239             // If we are willing to accept the default value when it's set explicitly,
240             // checking the HRESULT here is sufficient. E_FAIL is returned when the
241             // default is used.
242             if (SUCCEEDED(hr))
243             {
244                 *isDefault = false;
245                 return resultMaybe;
246             }
247         }
248     }
249
250     // 
251     // Check config files through EEConfig.
252     // 
253     if (CheckLookupOption(info, IgnoreConfigFiles) == FALSE && // Check that we aren't ignoring config files.
254         s_GetConfigValueCallback != NULL)// Check that GetConfigValueCallback function has been registered.
255     {
256         LPCWSTR pvalue;
257
258         // EEConfig lookup options.
259         BOOL systemOnly = CheckLookupOption(info, ConfigFile_SystemOnly) ? TRUE : FALSE;
260         BOOL applicationFirst = CheckLookupOption(info, ConfigFile_ApplicationFirst) ? TRUE : FALSE;
261
262         if (SUCCEEDED(s_GetConfigValueCallback(info.name, &pvalue, systemOnly, applicationFirst)) && pvalue != NULL)
263         {
264             WCHAR * end;
265             errno = 0;
266             DWORD resultMaybe = wcstoul(pvalue, &end, 0);
267
268             // errno is ERANGE if the number is out of range, and end is set to pvalue if
269             // no valid conversion exists.
270             if (errno != ERANGE && end != pvalue)
271             {
272                 *isDefault = false;
273                 return resultMaybe;
274             }
275             else
276             {
277                 // If an invalid value is defined we treat it as the default value.
278                 // i.e. we don't look further.
279                 *isDefault = true;
280                 return info.defaultValue;
281             }
282         }
283     }
284
285     // 
286     // If we are favoring config files and we don't have a result from EEConfig, we check REGUTIL here.
287     // 
288     if (CheckLookupOption(info, FavorConfigFile) == TRUE)
289     {
290         DWORD resultMaybe;
291         HRESULT hr = REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &resultMaybe, level, prependCOMPlus);
292
293         if (!acceptExplicitDefaultFromRegutil)
294         {
295             // Ignore the default value even if it's set explicitly.
296             if (resultMaybe != info.defaultValue)
297             {
298                 *isDefault = false;
299                 return resultMaybe;
300             }
301         }
302         else
303         {
304             // If we are willing to accept the default value when it's set explicitly,
305             // checking the HRESULT here is sufficient. E_FAIL is returned when the
306             // default is used.
307             if (SUCCEEDED(hr))
308             {
309                 *isDefault = false;
310                 return resultMaybe;
311             }
312         }
313     }
314
315     *isDefault = true;
316     return info.defaultValue;
317 }
318
319 // 
320 // Look up a DWORD config value.
321 // 
322 // Arguments:
323 //     * info - see file:../inc/CLRConfig.h for details
324 //     
325 // static
326 DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info)
327 {
328     // We pass false for 'acceptExplicitDefaultFromRegutil' to maintain the existing behavior of this function.
329     // Callers who don't need that behavior should switch to the other version of this function and pass true.
330     bool unused;
331     return GetConfigValue(info, false /* acceptExplicitDefaultFromRegutil */, &unused);
332 }
333
334 // 
335 // Look up a String config value.
336 // 
337 // Arguments:
338 //     * info - see file:../inc/CLRConfig.h for details
339 //     
340 // Return value:
341 //     * Pointer to the string value, if found. You own the string that's returned. Returns NULL if the value
342 //         is not found.
343 // 
344 // static
345 LPWSTR CLRConfig::GetConfigValue(const ConfigStringInfo & info)
346 {
347     CONTRACTL
348     {
349         NOTHROW;
350         GC_NOTRIGGER;
351         FORBID_FAULT;
352     }
353     CONTRACTL_END;
354     
355     LPWSTR result = NULL;
356     
357     // TODO: We swallow OOM exception here. Is this OK?
358     FAULT_NOT_FATAL();
359
360     // If this fails, result will stay NULL.
361     GetConfigValue(info, &result);
362
363     return result;
364 }
365
366 // 
367 // Look up a string config value, passing it out through a pointer reference.
368 // 
369 // Return value:
370 //     * Reports out of memory errors (HRESULT E_OUTOFMEMORY).
371 //     
372 // Arguments:
373 //     * info - see file:../inc/CLRConfig.h for details
374 //     * outVal - Set to the result string. You own the string that's returned. Set to NULL if the value is
375 //         not found.
376 // 
377 // static
378 HRESULT CLRConfig::GetConfigValue(const ConfigStringInfo & info, __deref_out_z LPWSTR * outVal)
379 {
380     CONTRACT(HRESULT) {
381         NOTHROW;
382         GC_NOTRIGGER;
383         INJECT_FAULT (CONTRACT_RETURN E_OUTOFMEMORY);
384         POSTCONDITION(CheckPointer(outVal, NULL_OK)); // TODO: Should this check be *outVal instead of outVal?
385     } CONTRACT_END;
386
387     LPWSTR result = NULL;
388
389
390     //
391     // Set up REGUTIL options.
392     // 
393     REGUTIL::CORConfigLevel level = GetConfigLevel(info.options);
394     BOOL prependCOMPlus = !CheckLookupOption(info, DontPrependCOMPlus_);
395
396     // 
397     // If we aren't favoring config files, we check REGUTIL here.
398     // 
399     if(result == NULL && CheckLookupOption(info, FavorConfigFile) == FALSE)
400     {        
401         result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPlus, level);
402     }
403
404     // 
405     // Check config files through EEConfig.
406     // 
407     if(result == NULL && // Check that we don't have a value from REGUTIL
408         CheckLookupOption(info, IgnoreConfigFiles) == FALSE && // Check that we aren't ignoring config files.
409         s_GetConfigValueCallback != NULL) // Check that GetConfigValueCallback function has been registered.
410     {
411         LPCWSTR pResult;
412
413         // EEConfig lookup options.
414         BOOL systemOnly = CheckLookupOption(info, ConfigFile_SystemOnly) ? TRUE : FALSE;
415         BOOL applicationFirst = CheckLookupOption(info, ConfigFile_ApplicationFirst) ? TRUE : FALSE;
416
417         if(SUCCEEDED(s_GetConfigValueCallback(info.name, &pResult, systemOnly, applicationFirst)) && pResult != NULL)
418         {
419             size_t len = wcslen(pResult) + 1;
420             result = new (nothrow) WCHAR[len];
421             if (result == NULL)
422             {            
423                 RETURN E_OUTOFMEMORY;
424             }
425             wcscpy_s(result, len, pResult);
426         }
427     }
428
429     // 
430     // If we are favoring config files and we don't have a result from EEConfig, we check REGUTIL here.
431     // 
432     if(result==NULL && 
433         CheckLookupOption(info, FavorConfigFile) == TRUE)
434     {
435         result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPlus, level);
436     }
437
438     if ((result != NULL) && CheckLookupOption(info, TrimWhiteSpaceFromStringValue))
439     {
440         // If this fails, result remains untouched, so we'll just return the untrimmed
441         // value.
442         LPWSTR wszTrimmedResult = NULL;
443         if (SUCCEEDED(TrimWhiteSpace(result, &wszTrimmedResult)) &&
444             (wszTrimmedResult != NULL))
445         {
446             // wszTrimmedResult should be the result we return.  Delete the untrimmed
447             // result.
448             delete [] result;
449             result = wszTrimmedResult;
450         }
451     }
452
453     *outVal = result;
454     RETURN S_OK;
455 }
456
457 // 
458 // Check whether an option is specified (e.g. explicitly listed) in any location
459 // 
460 // Arguments:
461 //     * name - the name field of the desired ConfigDWORDInfo/ConfigStringInfo
462 //     
463 // static
464 BOOL CLRConfig::IsConfigOptionSpecified(LPCWSTR name)
465 {
466     CONTRACTL
467     {
468         NOTHROW;
469         GC_NOTRIGGER;
470     }
471     CONTRACTL_END;
472
473     // Check config files
474     {
475         LPCWSTR result = NULL;
476
477         if (s_GetConfigValueCallback != NULL && 
478             SUCCEEDED(s_GetConfigValueCallback(name, &result, FALSE, FALSE)) && 
479             result != NULL)
480         {
481             return TRUE;
482         }
483     }
484
485     // Check REGUTIL, both with and without the COMPlus_ prefix
486     {
487         LPWSTR result = NULL;
488     
489         result = REGUTIL::GetConfigString_DontUse_(name, TRUE);
490         if (result != NULL)
491         {
492             FreeConfigString(result);
493             return TRUE;
494         }
495
496         result = REGUTIL::GetConfigString_DontUse_(name, FALSE);
497         if (result != NULL)
498         {
499             FreeConfigString(result);
500             return TRUE;
501         }
502
503     }
504
505     return FALSE;
506 }
507
508 //---------------------------------------------------------------------------------------
509 //
510 // Given an input string, returns a newly-allocated string equal to the input but with
511 // leading and trailing whitespace trimmed off. If input is already trimmed, or if
512 // trimming would result in an empty string, this function sets the output string to NULL
513 // 
514 // Caller must free *pwszTrimmed if non-NULL
515 //
516 // Arguments:
517 //      * wszOrig - String to trim
518 //      * pwszTrimmed - [out]: On return, points to newly allocated, trimmed string (or
519 //          NULL)
520 //
521 // Return Value:
522 //     HRESULT indicating success or failure.
523 //
524 HRESULT CLRConfig::TrimWhiteSpace(LPCWSTR wszOrig, __deref_out_z LPWSTR * pwszTrimmed)
525 {
526     CONTRACTL
527     {
528         NOTHROW;
529         GC_NOTRIGGER;
530     }
531     CONTRACTL_END;
532
533     _ASSERTE(wszOrig != NULL);
534     _ASSERTE(pwszTrimmed != NULL);
535
536     // In case we return early, set [out] to NULL by default
537     *pwszTrimmed = NULL;
538
539     // Get pointers into internal string that show where to do the trimming.
540     size_t cchOrig = wcslen(wszOrig);
541     if (!FitsIn<DWORD>(cchOrig))
542         return COR_E_OVERFLOW;
543     DWORD cchAfterTrim = (DWORD) cchOrig;
544     LPCWSTR wszAfterTrim = wszOrig;
545     ::TrimWhiteSpace(&wszAfterTrim, &cchAfterTrim);
546     
547     // Is input string already trimmed?  If so, save an allocation and just return.
548     if ((wszOrig == wszAfterTrim) && (cchOrig == cchAfterTrim))
549     {
550         // Yup, just return success
551         return S_OK;
552     }
553
554     if (cchAfterTrim == 0)
555     {
556         // After trimming, there's nothing left, so just return NULL
557         return S_OK;
558     }
559
560     // Create a new buffer to hold a copy of the trimmed string.  Caller will be
561     // responsible for this buffer if we return it.
562     NewArrayHolder<WCHAR> wszTrimmedCopy(new (nothrow) WCHAR[cchAfterTrim + 1]);
563     if (wszTrimmedCopy == NULL)
564     {
565         return E_OUTOFMEMORY;
566     }
567
568     errno_t err = wcsncpy_s(wszTrimmedCopy, cchAfterTrim + 1, wszAfterTrim, cchAfterTrim);
569     if (err != 0)
570     {
571         return E_FAIL;
572     }
573
574     // Successfully made a copy of the trimmed string.  Return it. Caller will be responsible for
575     // deleting it.
576     wszTrimmedCopy.SuppressRelease();
577     *pwszTrimmed = wszTrimmedCopy;
578     return S_OK;
579 }
580
581
582 // 
583 // Deallocation function for code:CLRConfig::FreeConfigString
584 //
585 void CLRConfig::FreeConfigString(__in_z LPWSTR str)
586 {
587     LIMITED_METHOD_CONTRACT;
588     
589     delete [] str;
590 }
591
592 // 
593 // Register EEConfig's GetConfigValueCallback function so CLRConfig can look in config files.
594 // 
595 //static
596 void CLRConfig::RegisterGetConfigValueCallback(GetConfigValueFunction func)
597 {
598     LIMITED_METHOD_CONTRACT;
599     s_GetConfigValueCallback = func;
600 }
601
602 // 
603 // Helper method to translate LookupOptions to REGUTIL::CORConfigLevel.
604 // 
605 //static 
606 REGUTIL::CORConfigLevel CLRConfig::GetConfigLevel(LookupOptions options)
607 {
608     LIMITED_METHOD_CONTRACT;
609     
610     REGUTIL::CORConfigLevel level = (REGUTIL::CORConfigLevel) 0;
611
612     if(CheckLookupOption(options, IgnoreEnv) == FALSE)
613         level = static_cast<REGUTIL::CORConfigLevel>(level | REGUTIL::COR_CONFIG_ENV);
614     
615     if(CheckLookupOption(options, IgnoreHKCU) == FALSE)
616         level = static_cast<REGUTIL::CORConfigLevel>(level | REGUTIL::COR_CONFIG_USER);
617     
618     if(CheckLookupOption(options, IgnoreHKLM) == FALSE)
619         level = static_cast<REGUTIL::CORConfigLevel>(level | REGUTIL::COR_CONFIG_MACHINE);
620     
621     return level;
622 }