Non-deterministic Behavior with TString and + operator

I was trying to add some TStrings together with the + operator and discovered some weird behavior. Unfortunately some of it seems non-deterministic (i.e. I can’t reproduce the results with the same commands in CINT!) This hints at some kind of race/memory issue maybe?

Here is the first example:

[code]* ROOT v5.34/10 *

root [0] TString s1(“foo”)
root [1] TString s2(“bar”)
root [2] s1+s2
(class TString)"“
root [3] s1+s2
(class TString)”“
root [4] s1+s2
(class TString)”“
root [5] s1
(class TString)“foo"
root [6] s2
(class TString)“bar"
root [7] s1+s2
(class TString)”?”???-???”!!!n0.-??“
root [8] s1+s2
(class TString)”"
[/code]
After that s1 and s2 (and their adding) was more consistent. It still gives a blank string for s1+s2 which I think is wrong, but at least it’s consistent! Doing the same order of s1 and s2 operations in a new CINT session does not make the same ???-type TString appear.

Here is another example:

[code]* ROOT v5.34/10 *

root [0] TString s1(“foo”)
root [1] s1 + “bar”
(class TString)"" # Two more times this is consistent, now I try a std::string
root [4] std::string s2(“foo”)
root [5] s2 + “bar”

*** Break *** segmentation violation
Root >
root [6] s2 + “bar”

*** Break *** segmentation violation
Root >
root [7] s2 # I guess std::strings won’t work, but wait. it’s actually a TString?!
(class TString)"foo"
root [8] s1
(class TString)“foo"
root [11] s1 + “bar” # Non-reproducible behavior again, I get ??-type strings!
(class TString)”?:???"
root [12] s2 + “bar”

*** Break *** segmentation violation
Root >
root [13]
[/code]

Every time I try to reproduce this behavior it returns to the useless-but-consistent behavior that adding TStrings together with “+” results in an empty TString, as does adding a TString with a char * literal, and adding an std::string with a char * literal gives a seg fault. The last one is apparently actually incorrect as adding std::strings with char * literals should give a new std::string, but CINT claims that the std::string is actually a TString, but this TString behaves differently than “actual” TStrings (which don’t seg fault when you try to add char *s).

Can someone help me figure out what’s going on? I’m using ROOT 5.34/10 from MacPorts compiled with Clang 3.2 (also from MacPorts), on Mac OSX 10.7.5.

Jean-François

I do not see why you want to do “s1+s2” at the ROOT prompt without storing the result in a 3rd TString.
Is it useful ?
I would do:

root [7] TString s3=s1+s2
root [8] s3
(class TString)"foobar"
root [9] 

[quote=“jfcaron”]This hints at some kind of race/memory issue maybe?
[/quote]

This probably hints at the fact that s1 + s2 is a temporary object which dies immediately at the end of a full expression.

And yes, Olivier made a nice comment - what do you want to do with such an expiring string?
Do you have a code which relies on some specific CINT’s output?

Ah, and yes, I have a ROOT v. 5.34.10 and it behaves in a very deterministic way: every time it prints
(class TString)"" as expected:

root [0] TString s1("aaa") root [1] TString s2("bbb") root [2] s1 + s2 (class TString)"" root [3] s1 + "aaa" (class TString)"" root [4] s1 + "aaa" (class TString)"" root [5] s1 (class TString)"aaa" root [6] s2 (class TString)"bbb" root [7] s1 + s2 (class TString)"" root [8] s1 + "aa" (class TString)""

I’m not familiar with CINT’s internals, but I’m pretty sure: after CINT parses your expression s1 + s2,
it calls the compiled function from libCore (or whatever library): operator + (const TString & lhs, const TString & rhs) or similar function. And the library function looks like this:

SomeClass operator + (const SomeClass & a, const SomeClass & b) { SomeClass result; .... return result; }
as you can see the result IS NOT CREATED IN DYNAMIC MEMORY (though string’s buffer probably is), so it would be (IMHO) strange to require from CINT to copy AGAIN the result into some object in dynamic memory just to print the result for you and delete it immediately.

If you do
s1 += s2 you’ll have a non-empty resulting string, since the object is still alive (while the semantic is a bit different, of course).

I wasn’t trying to get any specific functionality out of CINT printing values. I was trying to figure out the best way to concatenate TStrings and (foolishly) tried a few different ways in CINT.

AFAIK CINT is supposed to print out values that would otherwise have been discarded, right? That’s why s1 and s2 are printed, and that’s why ROOT tutorials say things like “you can use ROOT as a pocket calculator!” I assumed that it would at least bother keeping the object-to-be-printed around long enough to do the printing, kind of like how the Python interpreter does it.

Am I wrong to keep expecting CINT to represent the actual behavior in C++? If TString s3 = s1+s2 puts the right values in s3, then just doing s1+s2 at the ROOT prompt should somewhere show up as “foobar”, and CINT should print that, not an empty string and not some garbage string! I know CINT != compiled C++, but I would consider this behavior a bug in CINT.

Thanks for suggesting putting the s1+s2 into an actual string, of course I’d do that in my macro and compiled codes. I was using CINT to do simple experimentation and sanity-checks before putting the string manips into my real code, but then I got confusing-looking behavior.

Jean-François

Hi Timur and Olivier,

I am not sure if questioning the usefulness of what Jean-François did here is your best possible answer. After all he pointed you to a potential bug.

I am attaching the valgrind output of below simple interaction with v5-34-00-patches@c58f36 on a 32bit SL5 system.

root [0] TString s1("foo"), s2("bar");
root [1] s1+s2;
(class TString)""
root [2] .q

If your answer is ‘lol u stupid’ I don’t really care.
valgrind.log_extension_for_phpBB.C (16.2 KB)

Why foolishly? Even in CINT with all its limitations TString concatenation WORKS. So if you write a valid and reasonable C++ code … it works more or less as expected. And after all, if you type (s1 + s2).Data() you’ll have your “foobar”.

Hmmm. On your pocket calculator you do not execute C++ statements, do not concatenate strings (TStrings or std::strings) so we can simply ignore this passage, ok? CINT has its limitations and is not your pocket calculator. Hehe, and I’m pretty sure CINT can do ALL what you pocket calculator can :slight_smile:

[quote]I assumed that it would at least bother keeping the object-to-be-printed around long enough to do the
printing, kind of like how the Python interpreter does it. [/quote]

Yes, and it looks like CINT can’t do this with temporary objects like TString or std::string. Ah … and CINT is not a python interpreter, and C++ has quite different semantics and CINT does not have a special variable named ‘_’ for the last evaluated expression and etc. etc…

Hmm, the actual behavior in C++ would be to destroy a temporary at the end of the full expression s1 + s2 (if we’re talking about C++ and TStrings and ignoring the fact that in C++ you can have only declarations at the translation-unit level == top-level). That’s what CINT’s doing (well, I guess so). It’s nice though, that with .Data() it still can print something reasonable.

[quote]If TString s3 = s1+s2 puts the right values in s3, then just doing s1+s2 at the ROOT prompt should
somewhere show up as “foobar”, and CINT should print that, not an empty string and not some garbage string! I know CINT != compiled C++, but I would consider this behavior a bug in CINT.[/quote]

TString s3 survives its declaration and lives, I think, till the end of an interactive session:) Temporary object dies at the end of full expression.

Ok, with s1 + s2 … you consider this as a bug, I consider this as … well, it’s how its implemented by CINT in its current incarnation. If I was writing an interpreter, I would probably do as you expected, but … as there is no formal specification of what and how CINT should do/print after executing some … pseudo C++ statement, I can not call this behavior bug :slight_smile:

[quote]Thanks for suggesting putting the s1+s2 into an actual string, of course I’d do that in my macro and
compiled codes. I was using CINT to do simple experimentation and sanity-checks before putting the string manips into my real code, but then I got confusing-looking behavior.[/quote]

You do not have to put it into a named object, see my suggestion above - you can help CINT a little.

[IMHO] There are a lot of real problems with CINT and what you demonstrated is not one of them, since this limitation/feature does not really affect your code. But even more … nowadays it does not really help to complain about CINT’s limitations/bugs :frowning:. As you probably know, ROOT has moved to cling and it’s VERY POSSIBLE that the limitation you found simply does not exist with cling and ROOT/cling works the way you need/expect. So, wait a little, cling is coming soon and it’s very possible it’ll fulfill the promise to be “your pocket calculator” :slight_smile: [/IMHO]

I’m not able to reproduce it, but I have only Mac OS X 64 bit and Ubuntu 64 bit. I suggest you submit a bug report to JIRA.

EDIT: with ‘(’ and ‘)’ around expression I finally have a segmentation violation.

Now…
I do not use ‘u’ or ‘lol’ or something similar. And I’m pretty sure I’ve never said that you are stupid and never ever said anybody on this forum is stupid.

But anyway, if you care to talk about this I have to answer …

[quote]If your answer is ‘lol u stupid’ I don’t really care.
[/quote]

Thanks for this priceless information, but … I don’t really care :mrgreen:

I think you are taking my mention of the “pocket calculator” a bit too far. I am not looking to use ROOT in this way, but I am basically expecting CINT to print useful values. I am basically trying to generalize the following (apparently correct) behavior from integers to TStrings:

root [0] Int_t i = 5
root [1] i = 6
(const int)6
root [2] i
(Int_t)6
root [3] 6
(const int)6
root [4] Int_t j = 7
root [5] i+j
(Int_t)13

I get your point that using .Data() (or putting it into cout) keeps the object around enough to make it behave like I expect. That’s fine, but then why do I get non-deterministic behavior? That’s clearly an actual bug and not just a “well CINT doesn’t really do it that way”, it’s printing random bits of memory! Here, try copy & pasting this into a fresh interpreter:

TString s1("foo"),s2("bar")
cout << s1 + s2 << endl;
(s1+s2)
(s1+s2)

You might have to try it a few times (non-deterministic behavior is a bit like the Loch Ness monster). The second line makes CINT print “foobar”, the third line makes it print either an empty string “” or garbage. The garbage that is printed changes based on what else the system is doing, or on what other commands were executed by CINT before these three lines. The fourth line for me always prints “”.

If we’re not supposed to report CINT bugs until ROOT 6, it would be nice to get an official announcement to that effect. When is ROOT 6 coming anyways? The Trello page doesn’t give me a useful indication, the last update on Trello was several weeks ago. I’m not saying “hurry up”, but rather “there has been no news for a while”.

Hi,

to be sure, yes this is fixed in Cling:~/rootdev/rootgit/root (master⚡) root -l -b root [0] TString s1("foo"), s2("bar"); root [1] s1+s2 (class TString) "foobar"[6] root [2]
You can try ROOT6 out today; right now we’re working with experts of the various experiments, incorporating their feedback. More feedback is always welcome.

Thanks!

Cheers,
Wim

[quote]I think you are taking my mention of the “pocket calculator” a bit too far. I am not looking to use ROOT in this way, but I am basically expecting CINT to print useful values. I am basically trying to generalize the following (apparently correct) behavior from integers to TStrings:

root [0] Int_t i = 5 root [1] i = 6 (const int)6 root [2] i (Int_t)6 root [3] 6 (const int)6 root [4] Int_t j = 7 root [5] i+j (Int_t)13 [/quote]

I perfectly understand what you mean and my guess about why you have something different from what you expect, is just a guess, since I do not know exactly how CINT works. For me the case with complex things like TStrings is ok, it’s in my range of “expected behavior”, after all, s1 + s1 at the “top-level” and without ‘;’ is not a valid C++ at all.

[quote]I get your point that using .Data() (or putting it into cout) keeps the object around enough to make it ?
behave like I expect. That’s fine, but then why do I get non-deterministic behavior?

TString s1("foo"),s2("bar") cout << s1 + s2 << endl; (s1+s2) (s1+s2) [/quote]

Nice, this is already better - with ‘(’ and ‘)’ I also have a segmentation violation, which is CLEARLY A BUG. You did not have the parenthesis in your original post though.

[quote]
If we’re not supposed to report CINT bugs until ROOT 6, it would be nice to get an official announcement to
that effect. When is ROOT 6 coming anyways? The Trello page doesn’t give me a useful indication, the last
update on Trello was several weeks ago. I’m not saying “hurry up”, but rather “there has been no news for a while”.[/quote]

First, you probably noticed [IMHO][/IMHO] tags. I think, you can still submit a bug report. About cling/ROOT6 - we have a release this November (it will be some kind of “pre-view” AFAIK). But you can try a trunk right now (hehe, I’m afraid it also has limitations, but still … it’s a REAL C++ INTERPRETER!!! :slight_smile: )

Hi,

I filed ROOT-5606 in JIRA.

[quote=“honk”]Hi,

I filed ROOT-5606 in JIRA.[/quote]

Hi,

thank you.