Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deserialization into generic dictionary using WithAttemptingUnquotedStringTypeDeserialization deserializes hexadecimal value incorrectly. #943

Open
john-glover opened this issue Jul 25, 2024 · 0 comments

Comments

@john-glover
Copy link

john-glover commented Jul 25, 2024

Describe the bug
Having built a deserializer using the WithAttemptingUnquotedStringTypeDeserialization option and using generic Dictionary<object, object> deserialization, hexadecimal values can be converted into a negative value inappropriately.

To Reproduce
The issue can be clearly seen in this .Net Fiddle: https://dotnetfiddle.net/Y5PPJq (embedded at the bottom here as well).

The simplest steps are to use a value between 0x8000 and 0xFFFF (this is the range between 2 ^15 + 1 and 2 ^ 16). These values will successfully Convert.ToInt16() but the code makes a decision to interpret the first bit as the sign. The same thing happens at Int32.MaxValue + 1.

Resolution
I would be glad to contribute to the solution, but I don't want to spend time to create a pull request if it's not in keeping with your intent. I feel the appropriate solution is to simply use UInt64 rather than trying to use the smallest possible type -- this handles the most common cases, is not ambiguous (because yaml hex numbers have no concept of how wide they are).

Workaround
In my use case I've worked around the issue by writing an INodeDeserializer explicitly for hexadecimal values and using the .WithNodeDeserializer method register it instead of (wrapping) the ScalarNodeDeserializer.

Extra Bonus Bug
The octal implementation is entirely incorrect as well, but for a different reason. The Convert.ToInt16 (and other methods) won't convert a string with the 0o prefix, it has to be numbers matching the regular expression [0-7]+. The regular expression for octal is copied straight from the hex code (which is a third issue, but entirely hidden by the complete failure to parse with the 0o).

Code example showing the bug
Fiddle code also pasted here for posterity:

IDeserializer deserializer = new DeserializerBuilder()
	.WithAttemptingUnquotedStringTypeDeserialization()
	.Build();

var expected = "int16MaxValue: 0x8000";

var deserialized = deserializer.Deserialize<Dictionary<object, object>>(new StringReader(expected));
var hexValue = deserialized["int16MaxValue"];

Console.WriteLine($"{hexValue}");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant