Coder Social home page Coder Social logo

caseless's Introduction

AppVeyor Chat on Gitter NuGet Status Patrons on Open Collective

Extensible tool for weaving .net assemblies

Manipulating the IL of an assembly as part of a build requires a significant amount of plumbing code. This plumbing code involves knowledge of both the MSBuild and Visual Studio APIs. Fody attempts to eliminate that plumbing code through an extensible add-in model.

This is the codebase of core Fody engine. For more information on the larger Fody project see https://github.com/Fody/Home.

See Milestones for release notes.

Already a Patron? skip past this section

Community backed

Fody requires significant effort to maintain. As such it relies on financial support to ensure its long term viability.

It is expected that all developers using Fody become a Patron on OpenCollective.

See Licensing/Patron FAQ for more information.

Gold Sponsors

Support this project by becoming a Gold Sponsor. A large company logo will be added here with a link to your website.

PostSharp

Silver Sponsors

Support this project by becoming a Silver Sponsor. A medium company logo will be added here with a link to your website.

G-Research Particular Software

Bronze Sponsors

Support this project by becoming a Bronze Sponsor. The company avatar will show up here with a link to your OpenCollective Profile.

Patrons and sponsors

Thanks to all the backers and sponsors! Support this project by becoming a patron.

Documentation and Further Learning

Contributors

This project exists thanks to all the people who contribute.

caseless's People

Contributors

dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar eatdrinksleepcode avatar licshee avatar ltrzesniewski avatar simoncropp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

caseless's Issues

Caseless corrupts certain branch instructions

When Caseless replaces an instruction that is also the target of a branch instruction, and the new instructions are then moved as a result of an optimization, the operand is not updated accordingly, causing the resulting IL to be invalid.

Consider the following method:

public bool Conditional(string x, string y)
{
    return x.StartsWith(y ?? string.Empty);
}

Compiling this with .NET 4.5 produces this IL:

IL_0000:  nop
IL_0001:  ldarg.1
IL_0002:  ldarg.2
IL_0003:  dup
IL_0004:  brtrue.s   IL_000c
IL_0006:  pop
IL_0007:  ldsfld     string [mscorlib]System.String::Empty
IL_000c:  callvirt   instance bool [mscorlib]System.String::StartsWith(string)
IL_0011:  stloc.0
IL_0012:  br.s       IL_0014
IL_0014:  ldloc.0
IL_0015:  ret

When Mono.Cecil loads this method body, it creates an Instruction object for each instruction. For branch instructions, such as the brtrue.s instruction at IL_0004, the Operand property of the Instruction object is set to the Instruction object that is the target of the jump. So for IL_0004, the Operand is the same object that is created for IL_000c. When Caseless replaces the instruction at IL_000c as part of the weave, it does not replace the value of the Operand property of IL_0004. However, the resulting IL is still correct; the offset for IL_0004 is written from the Offset property of the Instruction in the Operand, which in this case (although orphaned) still has the correct Offset value. So the resulting IL after the weave looks like this:

IL_0000:  nop
IL_0001:  ldarg.1
IL_0002:  ldarg.2
IL_0003:  dup
IL_0004:  brtrue.s   IL_000c
IL_0006:  pop
IL_0007:  ldsfld     string [mscorlib]System.String::Empty
IL_000c:  ldc.i4.5
IL_000d:  callvirt   instance bool [mscorlib]System.String::StartsWith(string,
                                                                       valuetype [mscorlib]System.StringComparison)
IL_0012:  stloc.0
IL_0013:  br.s       IL_0015
IL_0015:  ldloc.0
IL_0016:  ret

No problem.

The same code compiled by Mono (4.4.0 beta in this case) looks like this:

IL_0000:  nop
IL_0001:  ldarg.1
IL_0002:  ldarg.2
IL_0003:  dup
IL_0004:  brtrue IL_000f
IL_0009:  pop
IL_000a:  ldsfld string [mscorlib]System.String::Empty
IL_000f:  callvirt instance bool string::StartsWith(string)
IL_0014:  stloc.0
IL_0015:  br IL_001a
IL_001a:  ldloc.0
IL_001b:  ret

It's exactly the same as the .NET version, except that the br* instructions are long-form instead of short-form. I don't know why Mono's mcs doesn't generate short-form instructions when the runtime handles them fine, but it doesn't; and that turns out to matter a lot in this case.

Caseless replaces the IL_000f instruction as part of the weave, but doesn't update the Operand of IL_0004, just like before; but then, it calls OptimizeMacros on the method body. This converts the long-form brtrue instructions to short-form brtrue.s instructions, which changes the size of the instruction and, crucially, changes the offsets of all of the following instructions, including the replaced instruction. However, the Offset of the orphaned instruction in the Operand of IL_0004 does not get updated; so when the IL gets written, it looks like this:

IL_0000:  nop
IL_0001:  ldarg.1
IL_0002:  ldarg.2
IL_0003:  dup
IL_0004:  brtrue.s IL_000f
IL_0006:  pop
IL_0007:  ldsfld string [mscorlib]System.String::Empty
IL_000c:  ldc.i4.5
IL_000d:  callvirt instance bool string::StartsWith(string, valuetype [mscorlib]System.StringComparison)
IL_0012:  stloc.0
IL_0013:  br.s IL_0015
IL_0015:  ldloc.0
IL_0016:  ret

Note that the operand of IL_0004 still points to IL_000f, which is no longer a valid instruction offset.

This particular example reproduces in Mono but not .NET because .NET generates the short form of the instruction. However, that is due to implementation details of the respective compilers that may not be true in all cases, and not guaranteed to remain the same in newer versions. It is possible for the same thing to happen in .NET, now or in the future.

There are a few possible fixes for this:

A. When replacing instructions, also replace corresponding Operands to ensure that when optimizations occur, offsets get updated correctly.
B. Remove the call to OptimizeMacros. It's not clear what benefit is gained for Caseless by calling it, and it has the potential to change the resulting IL in unintended ways (such as this one).
C. Call OptimizeMacros before and after weaving the method. This will ensure that any long-form branch instructions that can be converted to short-form will already have been converted by the time the replacement occurs, eliminating the source of the corruption.

I believe that A is the most correct solution to this problem, so I plan to submit a PR with that fix unless someone argues otherwise.

Static equality incorrectly converted to instance equality

This

public bool EqualsStaticWithNull()
{
    string x = null;
    var y = "A";
    return string.Equals(x,y);
}

Is incorrectly converted to this

public bool EqualsStaticWithNull()
{
    string x = null;
    var y = "A";
    return x.Equals(y, StringComparison.OrdinalIgnoreCase);
}

Support for .NET 5

Could this be updated to work with .NET 5?

When I attempt to install from nuget it is asking for a ton of dependencies within a .NET 5 project.

Error after update to Fody 3.0.0 and Caseless 1.8.0

Updated all nuget packages to fody 3.0.0 updated caseless to 1.8.0 and getting this error:

Fody: The weaver assembly 'Caseless.Fody, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' references an out of date version of Mono.Cecil.dll. Expected strong name token of '1C-A0-91-87-7D-12-CA-03' but got '50-CE-BF-1C-CE-B9-D0-5E'. The weaver needs to update to at least version 3.0 of FodyHelpers.

Forgotten the case insensitive comparison for character type

Using the example from: http://msdn.microsoft.com/en-us/library/bb383976.aspx

Following code with caseless didn't include the capital A on output:

    string[] strings = 
    {
        "A penny saved is a penny earned.",
        "The early bird catches the worm.",
        "The pen is mightier than the sword." 
    };



        // Split the sentence into an array of words 
        // and select those whose first letter is a vowel. 
        var earlyBirdQuery =
            from sentence in strings
            let words = sentence.Split(' ')
            from word in words
            let w = word 
            where w[0] == 'a' || w[0] == 'e'
                || w[0] == 'i' || w[0] == 'o'
                || w[0] == 'u'
            select word;

Need to convert the character to string as work-around:

        var earlyBirdQuery =
            from sentence in strings
            let words = sentence.Split(' ')
            from word in words
            let w = word[0].ToString() 
            where w == "a" || w == "e"
                || w == "i" || w == "o"
                || w == "u"
            select word;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.