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
Preprocessor incorrectly parses define arguments #780
Comments
Original Redmine Comment This works for me. This smells like a flex bug as spacing is pretty opaque to the Verilator code. What OS are you on? What does flex --version print? Can you attach the output of bin/verilator -E file.v --debug --debugi-V3PreShell 9 |
Original Redmine Comment Wilson Snyder wrote:
I'm am on OSX Mavericks, using the builtin version of flex and clang:
Note that I had previously tried to compile with a newer version of flex installed via MacPorts, but Verilator would not compile with that due to the error described here: Output of "bin/verilator -E file.v --debug --debugi-V3PreShell 9" is attached. |
Original Redmine Comment
Compare this to the text above which passed and this didn't print "Got Arg"=2/3. If you go to line V3PreProc.cpp you'll see this is just looping over the text that was printed in defineSubstIn which does have 4 arguments. So it's some sort of corruption issue. You'll need to add prints or use valgrind or similar to figure it out at your site since I don't see it. |
Original Redmine Comment It seems the first visit to defineSubst parses the arguments of the definition fine, but the second visit to defineSubst only parses the first two arguments of the definition correctly. The third argument it is getting the argument value provided in the call, not the argument variable in the definition!
|
Original Redmine Comment It looks like the problem is in the trimWhitespace function in V3PreProc
This outputs
Why should the version of flex would affect this? |
Original Redmine Comment
It shouldn't, that's was just a guess. Obviously you still haven't shown why it's messed up - presumably it worked correctly in the earlier call to that function. |
Original Redmine Comment As a quick aside, I tried recompiling Verilator on OSX Mavericks using macports gcc and macports flex and I no longer encountered this bug on the provided test case.
Note that macports gcc won't compile without the macports flex, it throws a Flex header error several minutes into the compile:
This does seem to strongly hint the problem is in flex, but I will poke into trimWhitespace a bit more. |
Original Redmine Comment Inside of V3PreProcImp::trimWhitespace() there is a dynamic allocation of a string variable named out. During the processing of the third parameter of the second call to macro `TESTA , the memory that variable out is allocated overlaps the memory pointed to by pointer cp in V3PreProcImp::defineSubst(). This overwrites the contents of the cp variable, which is supposed to contain the macro definition. Instead, the memory pointed to by cp now contains the out string, which happens to be the third parameter provided during the macro call.
I think the problem is line 596 of V3PreProc.cpp where cp is declared:
The pointer cp is never allocated any memory, instead it's simply given the reference returned by string::c_str(). The C++ docs indicate that this pointer could potentially be invalidated by other functions that modify the string. A couple posts on StackOverflow seem to indicate that its best to always make a copy of c_str() and not rely on the pointer it returns.
Applying the following fix did indeed solve the problem:
There is another reference to a c_str() later in the function that should probably be fixed too:
All that being said, I couldn't find any modifications to refp->params() inside of V3PreProcImp::defineSubst() that would cause it to invalidate the c_str() pointer. In addition, trying to print the pointer location returned by refp->params().c_str() suddenly made the error disappear; as did adding a memory watchpoint in LLDB. I'm curious if the problem here is actually LLVM; I'm not familiar enough with the C++ spec to know if what is going on here is "reasonable" behavior or a compiler bug. |
Original Redmine Comment I brought up this issue with developers on #llvm to figure out if this was a compiler bug or not; they noted that in this context cp will certainly reference freed memory. refp->params() returns a std::string object, which is a +copy+ of the m_params object within V3Define. This means for the following statement:
refp->params() returns a std::string object that is destroyed as soon as the c_str() call completes. This means cp will always point to freed memory! It was mentioned that the correct way to handle this is to keep params alive:
|
Original Redmine Comment Thanks for debugging! I think a nicer fix would be to use string iterators/ functions. Might you attempt a patch like that too? Meanwhile I will need to audit the code to make sure I do not have similar issues elsewhere. |
Original Redmine Comment Wilson Snyder wrote:
I've attached a minimal patch that replaces c_str() with a string iterator in defineSubst. I otherwise did not modify the logic, and split some of my changes into two lines if they exceeded the 80 character limit. I did a quick audit of the rest of the file and also replaced three other instances of "some_object->method_call().c_str()" that were in debug statements. (Note that diff was created inside of the src directory, so it probably needs to be applied from there?) |
Original Redmine Comment In git towards 3.861. Audited all of the code, and also Verilog-Perl and SystemPerl. Only a few other spots that are potentially problems, but overfixed to never call a function then c_str() anywhere and added a lint check for the future. Thanks much for debugging this. |
Original Redmine Comment Wilson Snyder wrote:
No problem! We rely on Verilator pretty heavily, I'm happy to be able to contribute something useful. |
Original Redmine Comment In 3.862. |
Author Name: Derek Lockhart
Original Redmine Issue: 780 from https://www.veripool.org
Original Date: 2014-06-06
Original Assignee: Derek Lockhart
Calling define macros that take multiple arguments will be parsed incorrectly depending on the indentation. The following code shows the error:
Note that the difference between the first call to TESTA and the second call to TESTA differ only by a single space on the second line. Also note that TESTB when called also passes, and differs to TESTA only by the name of the first variable, which is shorter by one character. This is a very difficult bug to catch!
This single space difference between the two calls to TESTA results in the following error:
Adding printfs to V3PreProc.cpp to display refp->name() and refp->args() generates the following output:
The text was updated successfully, but these errors were encountered: