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

Segmentation fault when "#pragma\n" is encountered #188

Closed
mfep opened this issue Jul 13, 2023 · 6 comments
Closed

Segmentation fault when "#pragma\n" is encountered #188

mfep opened this issue Jul 13, 2023 · 6 comments

Comments

@mfep
Copy link

mfep commented Jul 13, 2023

System info

  • Boost version: 1.82.0
  • Compiler: g++ 13.0.1-x86_64-redhat-linux
  • Both in optimized and unoptimized build

Actual behaviour

Preprocessing C++ source code with a #pragma statement immediately followed by a newline (\n) using Wave crashes the program with a segmentation fault.

Expected behaviour

The preprocessor lets the #pragma statement through to the output as unrecognized. Or throw a recoverable error.

Minimal reproducer

Minimal reproducer based on the "Quick start" section in the documentation:

#include <boost/wave/cpplexer/cpp_lex_iterator.hpp>
#include <boost/wave.hpp>

#include <iostream>
#include <string>

int main()
{
    std::string input =
        R"(int main()
{
#pragma
    return 0;
}
)";

    typedef boost::wave::cpplexer::lex_iterator<
        boost::wave::cpplexer::lex_token<>>
        lex_iterator_type;
    typedef boost::wave::context<
        std::string::iterator, lex_iterator_type>
        context_type;

    context_type ctx(input.begin(), input.end());

    context_type::iterator_type first = ctx.begin();
    context_type::iterator_type last = ctx.end();

    try
    {
        while (first != last)
        {
            std::cout << (*first).get_value();
            ++first;
        }
    }
    catch (const boost::wave::preprocess_exception &ex)
    {
        std::cout << "ERROR: " << ex.description() << std::endl;
        return -1;
    }
}
@hkaiser
Copy link
Collaborator

hkaiser commented Jul 14, 2023

Thanks for reporting, I'll try to have a look.

@jefftrull
Copy link
Collaborator

Thanks for the very clear bug report.

It looks like the code that implements pragmas assumes there is always at least one token (the space) after #pragma and when it is not present we can dereference invalid memory. You can see this here where we unconditionally increment the iterator representing the start of the token sequence and then dereference it.

It looks like there's a simple fix: testing for an empty token sequence and returning early. It may not be the best fix, but it should be a usable workaround. Add this at the start of on_pragma:

    if (begin == end)
        return true;

@hkaiser
Copy link
Collaborator

hkaiser commented Jul 15, 2023

I think another possible fix would be to change this:

pppragma
= no_node_d
[
ch_p(T_PP_PRAGMA)
[ store_found_directive_type(self.found_directive) ]
]
>> *( anychar_p -
(ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
)
;

to use + instead of *. This change would cause it to report an illformed preprocessor directive for the code above.

Also, I should go back to read the standard to see what it has to say about #pragma preprocessor directives.

@hkaiser
Copy link
Collaborator

hkaiser commented Jul 15, 2023

Also, I should go back to read the standard to see what it has to say about #pragma preprocessor directives.

Well, here we go: https://eel.is/c++draft/cpp.pragma. My suggested fix is incorrect, then. A line with just a #pragma directive is perfectly fine. @jefftrull you suggested the correct fix above. Thanks!

@jefftrull
Copy link
Collaborator

A fix for this has been merged into master and will be released as part of Boost 1.84

@mfep
Copy link
Author

mfep commented Oct 26, 2023

Thank you, @jefftrull!

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

3 participants