I have some code that I had to write to replace a function that was literally used thousands of times. The problem with the function was that return a pointer to a static allocated buffer and was ridiculously problematic. I was finally able to prove that intermittent high load errors were caused by the bad practice.
The function I was replacing has a signature of char * paddandtruncate(char *,int), char * paddandtruncate(float,int), or char * paddandtruncat(int,int). Each function returned a pointer to a static allocated buffer which was overwritten on subsequent calls.
I had three constants one the
Code had to be replaceable with no impact on the callers.
Very little time to fix the issue.
Acceptable performance.
I wanted some opinion on the style and possible refactoring ideas.
The system is based upon fixed width fields padded with spaces, and has some architectural issues. These are not addressable since the size of the project is around 1,000,000 lines.
I was at first planning on allowing the data to be changed after creation, but thought that immutable objects offered a more secure solution.
using namespace std;
class SYSTEM_DECLSPEC CoreString
{
private:
friend ostream & operator<<(ostream &os,CoreString &cs);
stringstream m_SS ;
float m_FltData ;
long m_lngData ;
long m_Width ;
string m_strData ;
string m_FormatedData;
bool m_Formated ;
stringstream SS ;
public:
CoreString(const string &InStr,long Width):
m_Formated(false),
m_Width(Width),
m_strData(InStr)
{
long OldFlags = SS.flags();
SS.fill(' ');
SS.width(Width);
SS.flags(ios::left);
SS<<InStr;
m_FormatedData = SS.str();
}
CoreString(long longData , long Width):
m_Formated(false),
m_Width(Width),
m_lngData(longData)
{
long OldFlags = SS.flags();
SS.fill('0');
SS.precision(0);
SS.width(Width);
SS.flags(ios::right);
SS<<longData;
m_FormatedData = SS.str();
}
CoreString(float FltData, long width,long lPerprecision):
m_Formated(false),
m_Width(width),
m_FltData(FltData)
{
long OldFlags = SS.flags();
SS.fill('0');
SS.precision(lPerprecision);
SS.width(width);
SS.flags(ios::right);
SS<<FltData;
m_FormatedData = SS.str();
}
CoreString(const string &InStr):
m_Formated(false),
m_strData(InStr)
{
long OldFlags = SS.flags();
SS.fill(' ');
SS.width(32);
SS.flags(ios::left);
SS<<InStr;
m_FormatedData = SS.str();
}
public:
operator const char *() {return m_FormatedData.c_str();}
operator const string& () const {return m_FormatedData;}
const string& str() const ;
};
const string& CoreString::str() const
{
return m_FormatedData;
}
ostream & operator<<(ostream &os,CoreString &cs)
{
os<< cs.m_Formated;
return os;
}
If you really do mean "no impact on the callers", your choices are very limited. You can't return anything that needs to be freed by the caller.
At the risk of replacing one bad solution with another, the quickest and easiest solution might be this: instead of using a single static buffer, use a pool of them and rotate through them with each call of your function. Make sure the code that chooses a buffer is thread safe.
It sounds like the system is threaded, right? If it was simply a matter of it not being safe to call one of these functions again while you're still using the previous output, it should behave the same way every time.
Most compilers have a way to mark a variable as "thread-local data" so that it has a different address depending on which thread is accessing it. In gcc it's __thread, in VC++ it's __declspec(thread).
If you need to be able to call these functions multiple times from the same thread without overwriting the results, I don't see any complete solution but to force the caller to free the result. You could use a hybrid approach, where each thread has a fixed number of buffers, so that callers could make up to N calls without overwriting previous results, regardless of what other threads are doing.
The code you've posted has a one huge problem - if a caller assigns the return value to a const char *, the compiler will make a silent conversion and destroy your temporary CoreString object. Now your pointer will be invalid.
I don't know how the callers are going to be using this, but allocating buffers using new into a auto_ptr<>s might work. It may satisfy criterion 1 (I can't tell without seeing the using code), and could be a pretty fast fix. The big issue is that it uses dynamic memory a lot, and that will slow things down. There's things you can do, using placement new and the like, but that may not be quick to code.
If you can't use dynamic storage, you're limited to non-dynamic storage, and there really isn't much you can do without using a rotating pool of buffers or thread-local buffers or something like that.
The "intermittent high-load errors" are caused by race conditions where one thread tramples on the static buffer before another thread has finished using it, right?
So switch to using an output buffer per thread, using whatever thread-local storage mechanism your platform provides (Windows, I'm thinking).
There's no synchronisation contention, no interference between threads, and based on what you've said about the current implementation rotating buffers, almost certainly the calling code doesn't need to change at all. It can't be relying on the same buffer being used every time, if the current implementation uses multiple buffers.
I probably wouldn't design the API this way from scratch, but it implements your current API without changing it in a significant way, or affecting performance.
Related
I have a class that wraps C functions for reading and writing data using file descriptors
I'm currently stuck at read method.
I want to create a read method that wraps the C function ssize_t read(int fd, void *buf, size_t count);
The function above uses void *buf as an output and returns the number of bytes written in the buffer.
I want to have a method read that would return a variable size object that would contain that data or nullptr if no data was read.
What is the best way to do that?
EDIT: I already have a char array[4096] that I use to read data. I just want to return them and also give the caller the ability to know the length of the data that I return.
The char array[4096] is a member of the class that wraps C read. The reason I use it is to store the data temporarily before return them to the caller. Every time I call the wrapper read the char array will ovewriten by design. An upper layer will be responsible for concatenate the data and construct messages. This upper layer is the one that needs to know how much data has arrived.
The size of the char array[4096] is randomly chosen. It could be very small but more calls would be needed.
The object that contains the member char array will always be global.
I use C++17
Should I use std::vector or std::queue ?
The general answer here is: Don't use mutable global state. It breaks reentrancy and threading. And don't compound the issue by trying to return views of mutable global state, which makes even sequential calls a problem.
Just allocate a per-call buffer and use that; if you want to allow the caller to provide a buffer, that's also acceptable. Examples would look like:
// Some class assumed to have an fd member for reading via the C API
class Reader
{
// Define member attributes, e.g. fd
public:
std::string_view read(std::string& buf) {
ssize_t numread = read(fd, buf.data(), buf.size());
// Error checking if applicable, presumably handling negative return values
// by raising exception
return std::string_view(buf.data(), numread); // Guaranteed copy-elision
}
std::string read(size_t max_read) {
std::string buf(max_read, '\0'); // Allocate appropriately sized buffer
auto view = read(buf); // Delegate to view-based API
buf.resize(view.size()); // Resize to match amount actually read
return buf; // Likely (but not guaranteed) NRVO based copy-elision
}
}
std::string and std::string_view could be replaced with std::vector and std::span of some type in C++20 if you preferred (std::span would allow receiving a std::span instead of std::string& in C++20, making the code more generic).
This provides the caller with multiple options:
Call read with an existing pre-sized std::string (maybe change to std::span for C++20) that the caller can reuse over and over
Call read with an explicit size and get a freshly allocated std::string with few if any no copies involved (NRVO will avoid copying the std::string being returned in most cases, though if the underlying read reads very little, the resize call might reallocate the underlying storage and trigger a copy of whatever real data exists)
For maximum efficiency, many callers calling this repeatedly would choose #1 (they'd just create a local std::string of a given size, pass it in by reference, then use the returned std::string_view to limit how much of the buffer they actually work with), but for simple one-off uses, option #2 is convenient.
EDIT: I already have a char array[4096] that I use to read data. I just want to return them and also give the caller the ability to know the length of the data that I return.
Right, so the key information is that you don't want to copy that (or at least you don't want to force an additional copy).
Current preferred return type is std::span, but that's C++20 and you're still on 17.
Second preference is std::string_view. It'll work fine for binary data but may confuse people who expect it to be printable, not contain null terminators and so on.
Otherwise you can obviously return some struct or tuple with pointer & length (and possiblyerrno, which is otherwise discarded).
Returning something that might be nullptr is pretty much the least preferred option. Don't do it. It's actually harder to use correctly than the original C interface.
You could use function overloading:
void read(int fileDescriptor, short int & variable)
{
static_cast<void>(read(fileDescriptor, &variable, sizeof(variable));
}
void read(int fileDescriptor, int & variable)
{
static_cast<void>(read(fileDescriptor, &variable, sizeof(variable));
}
You may want to also look into using templates.
Consider a scenario, where std::string is used to store a secret. Once it is consumed and is no longer needed, it would be good to cleanse it, i.e overwrite the memory that contained it, thus hiding the secret.
std::string provides a function const char* data() returning a pointer to (since C++11) continous memory.
Now, since the memory is continous and the variable will be destroyed right after the cleanse due to scope end, would it be safe to:
char* modifiable = const_cast<char*>(secretString.data());
OpenSSL_cleanse(modifiable, secretString.size());
According to standard quoted here:
$5.2.11/7 - Note: Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member resulting from a const_cast that casts away a const-qualifier68 may produce undefined behavior (7.1.5.1).
That would advise otherwise, but do the conditions above (continuous, to-be-just-removed) make it safe?
The standard explicitly says you must not write to the const char* returned by data(), so don't do that.
There are perfectly safe ways to get a modifiable pointer instead:
if (secretString.size())
OpenSSL_cleanse(&secretString.front(), secretString.size());
Or if the string might have been shrunk already and you want to ensure its entire capacity is wiped:
if (secretString.capacity()) {
secretString.resize(secretString.capacity());
OpenSSL_cleanse(&secretString.front(), secretString.size());
}
It is probably safe. But not guaranteed.
However, since C++11, a std::string must be implemented as contiguous data so you can safely access its internal array using the address of its first element &secretString[0].
if(!secretString.empty()) // avoid UB
{
char* modifiable = &secretString[0];
OpenSSL_cleanse(modifiable, secretString.size());
}
std::string is a poor choice to store secrets. Since strings are copyable and sometimes copies go unnoticed, your secret may "get legs". Furthermore, string expansion techniques may cause multiple copies of fragments (or all of) your secrets.
Experience dictates a movable, non-copyable, wiped clean on destroy, unintelligent (no tricky copies under-the-hood) class.
You can use std::fill to fill the string with trash:
std::fill(str.begin(),str.end(), 0);
Do note that simply clearing or shrinking the string (with methods such clear or shrink_to_fit) does not guarantee that the string data will be deleted from the process memory. Malicious processes may dump the process memory and can extract the secret if the string is not overwritten correctly.
Bonus: Interestingly, the ability to trash the string data for security reasons forces some programming languages like Java to return passwords as char[] and not String. In Java, String is immutable, so "trashing" it will make a new copy of the string. Hence, you need a modifiable object like char[] which does not use copy-on-write.
Edit: if your compiler does optimize this call out, you can use specific compiler flags to make sure a trashing function will not be optimized out:
#ifdef WIN32
#pragma optimize("",off)
void trashString(std::string& str){
std::fill(str.begin(),str.end(),0);
}
#pragma optimize("",on)
#endif
#ifdef __GCC__
void __attribute__((optimize("O0"))) trashString(std::string& str) {
std::fill(str.begin(),str.end(),0);
}
#endif
#ifdef __clang__
void __attribute__ ((optnone)) trashString(std::string& str) {
std::fill(str.begin(),str.end(),0);
}
#endif
There's a better answer: don't!
std::string is a class which is designed to be userfriendly and efficient. It was not designed with cryptography in mind, so there are few guarantees written into it to help you out. For example, there's no guarantees that your data hasn't been copied elsewhere. At best, you could hope that a particular compiler's implementation offers you the behavior you want.
If you actually want to treat a secret as a secret, you should handle it using tools which are designed for handling secrets. In fact, you should develop a threat model for what capabilities your attacker has, and choose your tools accordingly.
Tested solution on CentOS 6, Debian 8 and Ubuntu 16.04 (g++/clang++, O0, O1, O2, O3):
secretString.resize(secretString.capacity(), '\0');
OPENSSL_cleanse(&secretString[0], secretString.size());
secretString.clear();
If you were really paranoid you could randomise the data in the cleansed string, so as not to give away the length of the string or a location that contained sensitive data:
#include <string>
#include <stdlib.h>
#include <string.h>
typedef void* (*memset_t)(void*, int, size_t);
static volatile memset_t memset_func = memset;
void cleanse(std::string& to_cleanse) {
to_cleanse.resize(to_cleanse.capacity(), '\0');
for (int i = 0; i < to_cleanse.size(); ++i) {
memset_func(&to_cleanse[i], rand(), 1);
}
to_cleanse.clear();
}
You could seed the rand() if you wanted also.
You could also do similar string cleansing without openssl dependency, by using explicit_bzero to null the contents:
#include <string>
#include <string.h>
int main() {
std::string secretString = "ajaja";
secretString.resize(secretString.capacity(), '\0');
explicit_bzero(&secretString[0], secretString.size());
secretString.clear();
return 0;
}
Okay, so. I've been working on a class project (we haven't covered std::string and std::vector yet though obviously I know about them) to construct a time clock of sorts. The main portion of the program expects time and date values as formatted c-strings (e.g. "12:45:45", "12/12/12" etc.), and I probably could have kept things simple by storing them the same way in my basic class. But, I didn't.
Instead I did this:
class UsageEntry {
public:
....
typedef time_t TimeType;
typedef int IDType;
...
// none of these getters are thread safe
// furthermore, the char* the getters return should be used immediately
// and then discarded: its contents will be modified on the next call
// to any of these functions.
const char* getUserID();
const char* getDate();
const char* getTimeIn();
const char* getTimeOut();
private:
IDType m_id;
TimeType m_timeIn;
TimeType m_timeOut;
char m_buf[LEN_MAX];
};
And one of the getters (they all do basically the same thing):
const char* UsageEntry::getDate()
{
strftime(m_buf, LEN_OF_DATE, "%D", localtime(&m_timeIn));
return m_buf;
}
And here is a function that uses this pointer:
// ==== TDataSet::writeOut ====================================================
// writes an entry to the output file
void TDataSet::writeOut(int index, FILE* outFile)
{
// because of the m_buf kludge, this cannot be a single
// call to fprintf
fprintf(outFile, "%s,", m_data[index].getUserID());
fprintf(outFile, "%s,", m_data[index].getDate());
fprintf(outFile, "%s,", m_data[index].getTimeIn());
fprintf(outFile, "%s\n", m_data[index].getTimeOut());
fflush(outFile);
} // end of TDataSet::writeOut
How much trouble will this cause? Or to look at it from another angle, what other sorts of interesting and !!FUN!! behaviour can this cause? And, finally, what can be done to fix it (besides the obvious solution of using strings/vectors instead)?
Somewhat related: How do the C++ library functions that do similar things handle this? e.g. localtime() returns a pointer to a struct tm object, which somehow survives the end of that function call at least long enough to be used by strftime.
There is not enough information to determine if it will cause trouble because you do not show how you use it. As long as you document the caveats and keep them in mind when using your class, there won't be issues.
There are some common gotchas to watch out for, but hopefully these are common sense:
Deleting the UsageEntry will invalidate the pointers returned by your getters, since those buffers will be deleted too. (This is especially easy to run into if using locally declared UsageEntrys, as in MadScienceDream's example.) If this is a risk, callers should create their own copy of the string. Document this.
It does not look like m_timeIn is const, and therefore it may change. Calling the getter will modify the internal buffer and these changes will be visible to anything that has that pointer. If this is a risk, callers should create their own copy of the string. Document this.
Your getters are neither reentrant nor thread-safe. Document this.
It would be safer to have the caller supply a destination buffer and length as a parameter. The function can return a pointer to that buffer for convenience. This is how e.g. read works.
A strong API can avoid issues. Failing that, good documentation and common sense can also reduce the chance of issues. Behavior is only unexpected if nobody expects it, this is why documentation about the behavior is important: It generally eliminates unexpected behavior.
Think of it like the "CAUTION: HOT SURFACE" warning on top of a toaster oven. You could design the toaster oven with insulation on top so that an accident can't happen. Failing that, the least you can do is put a warning label on it and there probably won't be an accident. If there's neither insulation nor a warning, eventually somebody will burn themselves.
Now that you've edited your question to show some documentation in the header, many of the initial risks have been reduced. This was a good change to make.
Here is an example of how your usage would change if user-supplied buffers were used (and a pointer to that buffer returned):
// ==== TDataSet::writeOut ====================================================
// writes an entry to the output file
void TDataSet::writeOut(int index, FILE* outFile)
{
char userId[LEN_MAX], date[LEN_MAX], timeIn[LEN_MAX], timeOut[LEN_MAX];
fprintf(outFile, "%s,%s,%s,%s\n",
m_data[index].getUserID(userId, sizeof(userId)),
m_data[index].getDate(date, sizeof(date)),
m_data[index].getTimeIn(timeIn, sizeof(timeIn)),
m_data[index].getTimeOut(timeOut, sizeof(timeOut))
);
fflush(outFile);
} // end of TDataSet::writeOut
How much trouble will this cause? Or to look at it from another angle,
what other sorts of interesting and !!FUN!! behaviour can this cause?
And, finally, what can be done to fix it (besides the obvious solution
of using strings/vectors instead)?
Well there is nothing very FUN here, it just means that the results of your getter cannot outlive the corresponding instance of UsageEntry or you have a dangling pointer.
How do the C++ library functions that do similar things handle this?
e.g. localtime() returns a pointer to a struct tm object, which
somehow survives the end of that function call at least long enough to
be used by strftime.
The documentation of localtime says:
Return value
pointer to a static internal std::tm object on success, or NULL otherwise. The structure may be shared between
std::gmtime, std::localtime, and std::ctime, and may be overwritten on
each invocation.
The main problem here, as the main problem with most pointer based code, is the issue of ownership. The problem is the following:
const char* val;
{
UsageEntry ue;
val = ue.getDate();
}//ue goes out of scope
std::cout << val << std::endl;//SEGFAULT (maybe, really nasal demons)
Because val is actually owned by ue, you shoot yourself in the foot if they exist in different scopes. You COULD document this, but it is oh-so-much simpler to pass the buffer in as an argument (just like the strftime function does).
(Thanks to odedsh below for pointing this one out)
Another issue is that subsequent calls will blow away the info gained. The example odesh used was
fprintf(outFile, "%s\n%s",ue.getUserID(), ue.getDate());
but the problem is more pervasive:
const char* id = ue.getUserID();
const char* date = ue.getDate();//Changes id!
This violates the "Principal of Least Astonishment" becuase...well, its weird.
This design also breaks the rule-of-thumb that each class should do exactly one thing. In this case, UsageEntry both provides accessors to get the formatted time as a string, AND manages that strings buffer.
I'm finding standard string addition to be very slow so I'm looking for some tips/hacks that can speed up some code I have.
My code is basically structured as follows:
inline void add_to_string(string data, string &added_data) {
if(added_data.length()<1) added_data = added_data + "{";
added_data = added_data+data;
}
int main()
{
int some_int = 100;
float some_float = 100.0;
string some_string = "test";
string added_data;
added_data.reserve(1000*64);
for(int ii=0;ii<1000;ii++)
{
//variables manipulated here
some_int = ii;
some_float += ii;
some_string.assign(ii%20,'A');
//then we concatenate the strings!
stringstream fragment;
fragment<<some_int <<","<<some_float<<","<<some_string;
add_to_string(fragment.str(),added_data);
}
return;
}
Doing some basic profiling, I'm finding that a ton of time is being used in the for loop. Are there some things I can do that will significantly speed this up? Will it help to use c strings instead of c++ strings?
String addition is not the problem you are facing. std::stringstream is known to be slow due to it's design. On every iteration of your for-loop the stringstream is responsible for at least 2 allocations and 2 deletions. The cost of each of these 4 operations is likely more than that of the string addition.
Profile the following and measure the difference:
std::string stringBuffer;
for(int ii=0;ii<1000;ii++)
{
//variables manipulated here
some_int = ii;
some_float += ii;
some_string.assign(ii%20,'A');
//then we concatenate the strings!
char buffer[128];
sprintf(buffer, "%i,%f,%s",some_int,some_float,some_string.c_str());
stringBuffer = buffer;
add_to_string(stringBuffer ,added_data);
}
Ideally, replace sprintf with _snprintf or the equivalent supported by your compiler.
As a rule of thumb, use stringstream for formatting by default and switch to the faster and less safe functions like sprintf, itoa, etc. whenever performance matters.
Edit: that, and what didierc said: added_data += data;
You can save lots of string operations if you do not call add_to_string in your loop.
I believe this does the same (although I am not a C++ expert and do not know exactly what stringstream does):
stringstream fragment;
for(int ii=0;ii<1000;ii++)
{
//variables manipulated here
some_int = ii;
some_float += ii;
some_string.assign(ii%20,'A');
//then we concatenate the strings!
fragment<<some_int<<","<<some_float<<","<<some_string;
}
// inlined add_to_string call without the if-statement ;)
added_data = "{" + fragment.str();
I see you used the reserve method on added_data, which should help by avoiding multiple reallocations of the string as it grows.
You should also use the += string operator where possible:
added_data += data;
I think that the above should save up some significant time by avoiding unecessary copies back and forth of added_data in a temporary string when doing the catenation.
This += operator is a simpler version of the string::append method, it just copies data directly at the end of added_data. Since you made the reserve, that operation alone should be very fast (almost equivalent to a strcpy).
But why going through all this, when you are already using a stringstream to handle input? Keep it all in there to begin with!
The stringstream class is indeed not very efficient.
You may have a look at the stringstream class for more information on how to use it, if necessary, but your solution of using a string as a buffer seems to avoid that class speed issue.
At any rate, stay away from any attempt at reimplementing the speed critical code in pure C unless you really know what you are doing. Some other SO posts support the idea of doing it,, but I think it's best (read safer) to rely as much as possible on the standard library, which will be enhanced over time, and take care of many corner cases you (or I) wouldn't think of. If your input data format is set in stone, then you might start thinking about taking that road, but otherwise it's premature optimization.
If you start added_data with a "{", you would be able to remove the if from your add_to_string method: the if gets executed exactly once, when the string is empty, so you might as well make it non-empty right away.
In addition, your add_to_string makes a copy of the data; this is not necessary, because it does not get modified. Accepting the data by const reference should speed things up for you.
Finally, changing your added_data from string to sstream should let you append to it in a loop, without the sstream intermediary that gets created, copied, and thrown away on each iteration of the loop.
Please have a look at Twine used in LLVM.
A Twine is a kind of rope, it represents a concatenated string using a
binary-tree, where the string is the preorder of the nodes. Since the
Twine can be efficiently rendered into a buffer when its result is used,
it avoids the cost of generating temporary values for intermediate string
results -- particularly in cases when the Twine result is never
required. By explicitly tracking the type of leaf nodes, we can also avoid
the creation of temporary strings for conversions operations (such as
appending an integer to a string).
It may helpful in solving your problem.
How about this approach?
This is a DevPartner for MSVC 2010 report.
string newstring = stringA & stringB;
i dont think strings are slow, its the conversions that can make it slow
and maybe your compiler that might check variable types for mismatches.
I know that string literals in C/C++ have static storage duration, meaning that they live "forever", i.e. as long as the program runs.
Thus, if I have a function that is being called very frequently and uses a string literal like so:
void foo(int val)
{
std::stringstream s;
s << val;
lbl->set_label("Value: " + s.str());
}
where the set_label function takes a const std::string& as a parameter.
Should I be using a const std::string here instead of the string literal or would it make no difference?
I need to minimise as much runtime memory consumption as possible.
edit:
I meant to compare the string literal with a const std::string prefix("Value: "); that is initialized in some sort of a constants header file.
Also, the concatenation here returns a temporary (let us call it Value: 42 and a const reference to this temporary is being passed to the function set_text(), am I correct in this?
Thank you again!
Your program operates on the same literal every time. There is no more efficient form of storage. A std::string would be constructed, duplicated on the heap, then freed every time the function runs, which would be a total waste.
This will use less memory and run much faster (use snprintf if your compiler supports it):
void foo(int val)
{
char msg[32];
lbl->set_label(std::string(msg, sprintf(msg, "Value: %d", val)));
}
For even faster implementations, check out C++ performance challenge: integer to std::string conversion
How will you build your const std::string ? If you do it from some string literral, in the end it will just be worse (or identical if compiler does a good job). A string literal does not consumes much memory, and also static memory, that may not be the kind of memory you are low of.
If you can read all your string literals from, say a file, and give the memory back to OS when the strings are not used any more, there may be some way to reduce memory footprint (but it will probably slow the program much).
But there is probably many other ways to reduce memory consumption before doing that kind of thing.
Store them in some kind of resource and load/unload them as necessary.