I have observed a strange behaviour when comparing two strings with ==.
A little bit of context: The following code is from an application which should act as server and it should validate the thumbprint of the clientcertificate.
I have a client application with a certificate with the following thumbprint: "2074529C99D93D5955FEECA859AEAC6092741205". When I call the server this method returns Valid:
static CertificateValidationResult ValidateClientCertificate(X509Certificate2 clientcertificate)
{
return clientcertificate.Thumbprint == "2074529C99D93D5955FEECA859AEAC6092741205"
? CertificateValidationResult.Valid
: CertificateValidationResult.Rejected;
}
After I changed to a clientcertificate with the thumbprint "F9A021D2EFDCD3BD13671CE1D25CFE51BA5BA38E" and changed the server code the following method returns Rejected:
static CertificateValidationResult ValidateClientCertificate(X509Certificate2 clientcertificate)
{
return clientcertificate.Thumbprint == "F9A021D2EFDCD3BD13671CE1D25CFE51BA5BA38E"
? CertificateValidationResult.Valid
: CertificateValidationResult.Rejected;
}
In each case the strings are exactly the same, but only the first one returned Valid. Why is this happening?
If you copied / pasted the Thumbprint you may have accidentally copied a hidden character / symbol. Often these don't appear in the Visual Studio IDE even if you enable "Show Whitespace". This can cause all sorts of strange side-effects as you have witnessed.
The best approach is to manually type out the thumbprint into Visual Studio which will ensure no funny characters have slipped in. This can be a bit of a pain but the only way of guaranteeing you are actually comparing like for like.
Related
I am programming a C# application which will be used to program and test STM32 microcontrollers during production. I would like to program and verify the chip, then write some configuration to the flash memory and finally set the read-out protection. As a backend I decided to use OpenOCD and its Tcl interface running at port 6666.
The problem: I am able to execute commands and get their results, but I don't know how to check if the command was successfully executed or not. E.g. the reset command returns empty string no matters the target is connected or not... Some other commands like mdw return data or error string, but I am looking for some generic way how to check if the command succeeded or not.
Thank you for your ideas.
Assuming your Tcl code has a bit in its heart doing sendBack [eval $script], you'd change it to do this:
set code [catch {eval $script} result]
sendBack [list $code $result]
or even this:
set code [catch {eval $script} result options]
sendBack [list $code $result $options]
You'll need to unpack that list on the other side. The first element is the result code (0 for success, 1 for error, a few others theoretically but you probably won't see them), the second is the result value or the error message, and the third (if you use the second code snippet) is an options dictionary that can contain various things useful for debugging (including structured error codes, a stack trace, etc.)
Passing back the full result tuple is how you transfer the entire result from one context to another. A number of remote debugging tools for Tcl use pretty much exactly the same trick.
I have the following code:
string.Compare(value, expression.MatchValue, StringComparison.Ordinal) > 0;
This line creates the following SonarLint warning:
S1449: Define the locale to be used in this String operation.
I would assume that, because I specified the StringComparsion.Ordinal value, I did specify which local to use, and the S1449 warning should not be raised.
Is this correct? If so, is there any way to create bugs for SonarLint (I created an account at https://jira.sonarsource.com/browse/SLVS/ but it appears I do not have the privileges to create an account).
Thanks!
This issue has been recently fixed in SonarLint: https://jira.sonarsource.com/browse/SLVS-782
It will be part of the next release (version 1.8.0) due today or in the upcoming days.
I've run into a peculiar case where I get the following error when creating certain types of string:
Unexpected error writing debug information -- 'Error HRESULT E_FAIL has been returned from a call to a COM component.'
This error is not new to Stack Overflow (see this question and this question), but the problems presented have nothing to do with this one.
For me, this is happening when I create a const string of a certain length that includes a null-terminating character (\0) somewhere near the beginning.
To reproduce, first generate a string of appropriate length, e.g. using:
var s = new string('a', 3000);
Grab the resulting string at runtime (e.g. Immediate Window or by hovering over the variable and copying its value). Then, make a const out of it:
const string history = "aaaaaa...aaaaa";
Finally, put a \0 in there somewhere:
const string history = "aaaaaaaaaaaa\0aa...aaaaa";
Some things I noticed:
if you put the \0 near the end, the error doesn't happen.
Reproduced using .NET Framework 4.6.1 and 4.5
Doesn't happen if the string is short.
Edit: even more precious info available in the comments below.
Any idea why this is happening? Is it some kind of bug?
Edit: Bug filed, including info from comments. Thanks everybody.
I'll noodle about this issue a little bit. This issue occurs both in VS2015 and earlier versions. So nothing directly to do with the C# compiler itself, this goes wrong in the ISymUnmanagedWriter2::DefineConstant2() implementation method. ISymUnmanagedWriter2 is a COM interface, part of the .NET infrastructure that all compilers use. And used both by Roslyn and the legacy C# compiler.
The comments in the Roslyn source code (actually dates back to the CCI project) that uses the method are illuminating enough, that there is trouble with this method was discovered before:
// EDMAURER If defining a string constant and it is too long (length limit is undocumented), this method throws
// an ArgumentException.
// (see EMITTER::EmitDebugLocalConst)
try
{
this.symWriter.DefineConstant2(name, value, constantSignatureToken);
}
catch (ArgumentException)
{
// writing the constant value into the PDB failed because the string value was most probably too long.
// We will report a warning for this issue and continue writing the PDB.
// The effect on the debug experience is that the symbol for the constant will not be shown in the local
// window of the debugger. Nor will the user be able to bind to it in expressions in the EE.
//The triage team has deemed this new warning undesirable. The effects are not significant. The warning
//is showing up in the DevDiv build more often than expected. We never warned on it before and nobody cared.
//The proposed warning is not actionable with no source location.
}
catch (Exception ex)
{
throw new PdbWritingException(ex);
}
Swallowing exceptions, tsk, tsk. It dies on the last catch clause in your case. They did dig a little deeper to reverse-engineer the string length problem:
internal const int PdbLengthLimit = 2046; // Empirical, based on when ISymUnmanagedWriter2 methods start throwing.
Which is fairly close to where the \0 starts throwing, I got 2034. Nothing much that you or anybody else here can do about this of course. All you can reasonably do is report the bug at connect.microsoft.com. But hopefully you see the writing on the wall, the odds that it will get fixed are rather small. This is code that nobody maintains anymore, it now has 'undocumented' status and judging from other comments this goes back long before .NET. Not Ed Maurer either :)
Workaround ought to be easy enough, glue this string together at runtime.
I was able to repro the issue as coded. Then I changed the declaration to:
const string history = #"aaa\0aaa...lots and lots of aaa...aaa";
Tried again and it compiles just fine.
I spent 100s of hours researching this subject, and other senior programmer who coded the original project also could not make it work. I have an xml with a parameter of SignatureValue, Certificate (X509Certificate2) and Digest Value. The created and given Signature value stated in the same xml was made by converting concatinated fields (equal to Digest Value) into a hash (SHA1), then encrypted via private key. Private key is taken out of the certificate for privacy and I only have the Public key within. Now, no matter how I code around it, I always get a false value back (as in VerifyHash/verifyHashResult is false). Here is the code I am using:
// Need your help please.
static void VerifyHash(string sigVal , string digestVal, System.Security.Cryptography.X509Certificates.X509Certificate2 cert)
{
sigValInBytes = Convert.FromBase64String(sigVal);
try
{
using (RSACryptoServiceProvider rsaProviderDecrypt = (RSACryptoServiceProvider)cert.PublicKey.Key)
{
// Line below always return value of FALSE no matter how I code it. Here I want to verify the hashed freshly calculated digest value that is now hashed with the signature value
rsaProviderDecrypt.Decrypt(sigValInBytes, false);
rsaProviderDecrypt.Dispose();
}
}
}
// At the main program I get the certificate from the xml given and call the method above:
main
{
// Code below gets the certificate details from a given xml, details of each variable confirmed to be accurate.
char[] Base64_x509ByteArray;
Base64_x509ByteArray = t.DigitalSignatures.First().X509Data.ToCharArray();
byte[] x509ByteArray;
x509ByteArray = Convert.FromBase64CharArray(Base64_x509ByteArray, 0, Base64_x509ByteArray.Length);
// Here am creating the certificate from the gathered data/certificate:
System.Security.Cryptography.X509Certificates.X509Certificate2 cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(x509ByteArray);
VerifyHash(t.DigitalSignatures.FirstOrDefault().SignatureValue.Trim(), concatenatedFieldValues, cert);
}
Some shots in the dark:
Find the piece that is broken: Try doing the entire "encrypt / hash check" process in code without transfering anything over XML. If you can hash a string locally, and the hashes match, then the problem is in XML. Otherwise, the problem is in the cert or decryptor.
If the problem is on the cert / encryptor side, try hash matching with a local .NET cryptography class. If that fails, the problem is an encryption setting. Otherwise, it is the cert.
BIG shot in the dark: The call to Dispose right after the hash check. It shouldn't matter, but that caused an issue while I was decrypting using the Rijndael algorithm. Best guess was the optimizer was closing the stream early or something weird like that. Moving the constructor out of the using statement and manually calling Dispose after accessing the result fixed that "optimization".
Might try a reversable encryption algorithm. Rinjdael is native to .NET, and is reversable. Good for debug and proof of concept work. (Note: it uses Time as part of the salt, so RJ doesn't match hashes, it decrypts. So not good for passwords in Production environments.)
If the XML is the cause, check the encodings. Encryption is very sensitive to encodings, and XML serializers are finnicky beasts to begin with. The strings may look the same, but represented differently, or extra control characters added. Sql Server nvarchars are UCS-2, varchars are iso-8859-1, C# strings are utf-8, etc. Easy for encodings to mis-match, and an encoding change would easily cause this. Try converting the original value to utf-16 before inserting into the Xml, and set the Xml Declaration Encoding to utf-16. Just to be safe.
Note about NotePad: if you have opened the Xml in Notepad to take a quick look or edit, and saved it, there are probably extra "end of line" characters on your strings now. If you did the same in Word... oh my... Might want to try an original copy.
Failing that, try generating new encrypted values and see if they match.
How can I clear all interned strings in linqpad?
Looking at this example :
//var asd="asd";
string s = new string(new []{'a','s','d'});
Console.WriteLine (string.IsInterned(s));
It always return null , which is fine.
But once I un-remark the first line it always yield "asd" even if I remark it again.
It seems that the only solution is to close the program and start it again.
p.s. : in visual studio it's always returns the desired results (console mode).
LINQPad maintains the AppDomain between runs, so everything that's static will remain in memory. You can change this behavior by going to Edit > Preferences > Advanced > Always use fresh application domains.
While the above is true, it seems string interning is performed at a process level (see here). So there's no way to reset that besides restarting.