weggli-rs / weggli

weggli is a fast and robust semantic search tool for C and C++ codebases. It is designed to help security researchers identify interesting functionality in large codebases.
Apache License 2.0
2.32k stars 127 forks source link

How do I search for all else {} blocks that contain a return or a throw? #17

Closed 0x8000-0000 closed 2 years ago

0x8000-0000 commented 2 years ago

First of all, thank you for sharing such a useful tool!

I am trying to find patterns in the code like this:

  if (condition)
  {
      /* do */
      /* many */
      /* things */
  }
  else
  {
      throw PreconditionNotSatisified{};   // or return -ERROR, 
  }

so they can be refactored to return early and reduce code indentation.

I have tried:

  weggli 'if (_) else { throw }' .

  weggli 'if (_) { _ } else { throw $something; }' .

but nothing seems to work. Help!

Thank you.

felixwilhelm commented 2 years ago

Thanks for trying weggli out.

A query like weggli --cpp 'if (_) {} else { throw _;}' /tmp/test.tmp.cc should work. The latest commit (3e063dc) improves the printing of keyword only queries, so you should use HEAD to get useful results.

Please note the use of the --cpp flag to enable C++ support and the requirement to use ';' behind statements to make the query syntax valid (as in C/C++).

Hope that helps :)

0x8000-0000 commented 2 years ago

Thank you @felixwilhelm - it works great!

0x8000-0000 commented 2 years ago

Now, for bonus points, is it possible to search for the same pattern, unless it is in a chain for if {} else if {} else if {} ?

So, I still want to find these:

if (condition)
{
    /* do */
    /* many */
    /* things */
}
else
{
    throw PreconditionNotSatisified{};   // or return -ERROR
}

but not these:

if (condition1)
{
    /* do */
}
else if (condition2)
{
    /* many */
}
else if (condition3)
{
    /* things */
}
else
{
    throw ConditionSetExhausted{};
}

Thank you again!

0x8000-0000 commented 2 years ago

Also, for double bonus points, is it possible to only report when the last else {} contains a single statement only (either throw or return) ?

So, I want to find these:

if (condition)
{
    /* do */
    /* many */
    /* things */
}
else
{
    throw PreconditionNotSatisified{};   // or return -ERROR
}

but not these:

if (condition)
{
    /* do */
    /* many */
    /* things */
}
else
{
    if (someOtherCondition)
    {
        // try something else
    }
    else
    {
         throw PreconditionNotSatisified{};   // or return -ERROR
    }
}

I hope you will find these challenges as interesting as I found this tool so very useful for large scale review and refactoring. Thank you for designing it and for opening it up!