Writing LLVM int/string input - c++

I am trying to generate llvm-ir from AST.
For displaying the integer output I added,
Constant *CalleeF = TheModule->getOrInsertFunction("printf",FunctionType::get(IntegerType::getInt32Ty(Context), PointerType::get(Type::getInt8Ty(Context), 0), true);`
And while calling print function I wrote,
Value* PrintStmt::codegen(){
Value* V,*val,*to_print;
vector<Value *> ArgsV;
for (unsigned int i = 0, e = outs.size(); i != e; ++i){
to_print = outs[i]->codegen();
if(outs[i]->type=="int"){
val=Builder.CreateGlobalStringPtr("%d");
}
ArgsV.push_back(val);
ArgsV.push_back(to_print);
V = Builder.CreateCall(CalleeF, ArgsV, "printfCall");
}
return V;
}
What similar code should I write for getting input from user, i.e for scanf call?

For a scanf call you could first declare its prototype
llvm::FunctionType *readFnType = llvm::FunctionType::get(builder.getInt32Ty(), true);
llvm::Function* readfn = llvm::Function::Create(readFnType, llvm::GlobalValue::ExternalLinkage, "scanf", TheModule));
And call it like so
std::vector<Value*> ArgsV; // holds codegen IR for each argument
std::string StringFormat; // holds string formatting for all arguments
for(auto& arg : Args){
if(auto v = arg->codegen()){
if(v->getType()->isDoubleTy())
StringFormat += "%lf "; //
else if(v->getType()->isIntegerTy())
StringFormat += "%d ";
ArgsV.push_back(symbolTable[arg.name]);
}else return nullptr;
}
ArgsV.insert(ArgsV.begin(), builder.CreateGlobalStringPtr(StringFormat));
return builder.CreateCall(TheModule->getFunction("scanf"), ArgsV, "scanfCall");
Where symbolTable is a map of variable/argument names to a Value* holding the variable's stack allocated address. Recall that scanf takes the address of the variable to be written to, which explains the symbol table lookup.
It is also worth mentioning that this makes scanf inherently unsafe. You should consider using the fgets and gets functions instead.

Related

swig perl typemap(out) std::vector<std::string> doesn't return the desired output in perl

I am trying to type a typemap(out) std::vector.
I want it to get to the perl code as an array instead I am getting an array of arrays which after a double dereference contains the desired data.
how can I make it an array of strings in perl?
I have tried to edit the typemap myself and to use the typemaps in the "std_vector.i" and in "std_string.i" without editing and they all give the same results.
this is the typemap code:
%typemap(out) std::vector<std::string> {
int len = $1.size();
SV *svs = new SV[len];
for (int x = 0; x < len; x++) {
SV* sv = sv_newmortal();
sv_setpvn(sv, $1[x].data(), $1[x].size());
svs[x] = SvPV(sv, $1[x].size());
}
AV *myav = av_make(len, svs);
delete[] svs;
$result = newRV_noinc((SV*) myav);
sv_2mortal($result);
argvi++;
}
my code for testing the output:
#this return a std vector<string> in the cpp code
my #commitReturn = $SomeClass->commit();
print "\n";
#this should return a string instead it returns an array.
print $commitReturn[0];
print "\n";
#this should not work, instead it returns the desired output.
print $commitReturn[0][0];
the output is:
ARRAY(0x908c88)
20790
instead of:
20790
Can't use string ("20791") as an ARRAY ref while "strict refs"
Your commit method is just returning an array reference, not an array of array references. Maybe it looks like an array of array references because you are assigning the result to an array?
In any case, without touching the typemap code, you can dereference the function call
#commitReturn = #{$SomeClass->commit()};
or create a wrapper method to dereference it for you
package SomeClass;
...
sub commit_list {
my $self = shift;
#{$self->commit()};
}
...
#commitReturn = $SomeClass->commit_list();
To return an array instead of a reference to an array, you have to manipulate the stack such that Perl knows that more than one scalar is returned.
According to the documentation:
The current value of the argument stack pointer is contained in a
variable argvi. Whenever a new output value is added, it is critical
that this value be incremented. For multiple output values, the final
value of argvi should be the total number of output values.
So the following typemap should be sufficient:
%typemap(out) std::vector<std::string> {
int len = $1.size();
for (int x = 0; x < len; x++) {
$result = sv_newmortal();
sv_setpvn($result, $1[x].data(), $1[x].size());
argvi++;
}
}

Declaring variables clears the parameters

So, I am building a mockup of a licensing-system in C++.
char * LicenseServer::CreateHash (char* key)
{
char* newHash = nullptr;
//Create the hash if new key.
if (key != m_Key)
{
char* macAddr = GetMACAddress ();
size_t seed = 0;
boost::hash_combine (seed, std::string(key));
boost::hash_combine (seed, std::string(macAddr));
if (seed == size_t(0))
return nullptr;
std::stringstream sed;
sed << seed;
std::string seedstr = sed.str();
newHash = new char[seedstr.length() + 1];
strcpy_s (newHash, seedstr.length() + 1, seedstr.c_str ());
}
return newHash;
}
I am coming upon a strange error, though: every time I try to infer the declaration of a new char*, my input parameter "key", changes to an empty string.
It currently happens when I get to the strign-stream. Upon "std::stringstream sed", the key variable becomes "". Not null, but "".
It happened previously in the fucntion GetMACAddress as well, where I had declared
char newthing[4096]
Here it was solved by declaring
char* newthing = new char[4096];
It did not mirror the new content which I then put into newthing, just stayed "".
Why is the input parameter just casually cleared like this?
I am currently building in visual studio 2017, target 15063, on the c++latest tag.
Thank you very much.
EDIT:for a smaller code sample.

How strtok_r function return values?

I am doing component test for a 'C' code. I have read the functionality of strtok_r function but I am not able to get the return value that I want to pass in strncmp' function. My code is contains strtok_r and strncmp functions as below:
typedef struct BufferN {
uint32_t v;
uint32_t m;
} My_Buffer;
char subsystemstr[64] = { '\0' };
My_Buffer buffer;
char *p_system;
char *p_subsystem;
(void) GetString(&buffer, subsystemstr, sizeof(subsystemstr));
p_system = strtok_r (subsystemstr, ":", &p_subsystem);
for (i = 0u; i < 100; i++)
{
if (strncmp(p_system, "all", 64) == 0)
{
/*Some Code Statement*/
}
}
Since array subsystemstr is initialized to '\0', I am modifying this array value with the help of function GetString as below:
strncpy(subsystemstr, "all:", 64);
When I am printing subsystemstr, I am having updated array as:
["all:", '\0' <repeats 59 times>]
but when I am printing p_system(return value of strtok_r). I am getting
[0x388870 ""]
I am confused how it is working. Actually I want value of p_system = "all" so that 'strncmp' function can return 0.
Please suggest.
I suspect your understanding of what
p p_system
actually does (prints the address of p_system)
in gdb, the command would be
p *p_system
or, using the builtin printf command
printf "%s", p_system
or, using the C function
call printf("%s", p_system)
or,
call (void)puts(p_system)
or, if you do not mind also seeing some address values
x /s p_system

Array as out parameter in c++

I created a function that returns an error code (ErrCode enum) and pass two output parameters. But when I print the result of the function, I don't get the correct values in the array.
// .. some codes here ..
ErrCode err;
short lstCnt;
short lstArr[] = {};
err = getTrimmedList(lstArr, &lstCnt);
// list returned array (for comparison)
for (int i=0; i<lstCnt; ++i)
printf("lstArr[%3d] = %d", i, lstArr[i]);
// .. some codes here ..
The getTrimmedList function is like this:
ErrCode getTrimmedList(short* vList, short* vCnt)
{
short cnt;
ErrCode err = foo.getListCount(FOO_TYPE_1, &cnt);
if (NoError!=err) return err;
short* list = new short [cnt];
short total = 0;
for (short i=0; i<cnt; ++i)
{
FooBar bar = foo.getEntryByIndex(FOO_TYPE_1, i);
if (bar.isDeleted) continue;
list[total] = i;
++total;
}
*vCnt = total;
//vList = (short*)realloc(index, sizeof(short)*total);
vList = (short*)malloc(sizeof(short)*total);
memcpy(vList, list, sizeof(short)*total)
// list returned array (for comparison)
for (int i=0; i<lstCnt; ++i)
printf("lstArr[%3d] = %d", i, lstArr[i]);
return NoError;
}
where:
foo is an object that holds arrays of FooBar objects
foo.getListCount() returns the number of objects with type FOO_TYPE_1
FOO_TYPE_1 is the type of object we want to take/list
foo.getEntryByIndex() returns the ith FooBar object with type FOO_TYPE_1
bar.isDeleted is a flag that tells if bar is considered as 'deleted' or not
What's my error?
Edit:
Sorry, I copied a wrong line. I commented it above and put the correct line.
Edit 2
I don't have control over the returns of foo and bar. All their function returns are ErrCode and the outputs are passed through parameter.
Couple of questions before I can answer your post...
Where is "index" defined in:
vList = (short*)realloc(index, sizeof(short)*total);
Are you leaking the memory associated with:
short* list = new short [cnt];
Is it possible you have accidentally confused your pointers in memory allocation? In any case, here is an example to go from. You have a whole host of problems, but you should be able to use this as a guide to answer this question as it was originally asked.
WORKING EXAMPLE:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
int getTrimmedList(short** vList, short* vCnt);
int main ()
{
// .. some codes here ..
int err;
short lstCnt;
short *lstArr = NULL;
err = getTrimmedList(&lstArr, &lstCnt);
// list returned array (for comparison)
for (int i=0; i<lstCnt; ++i)
printf("lstArr[%3d] = %d\n", i, lstArr[i]);
// .. some codes here ..
return 0;
}
int getTrimmedList(short** vList, short* vCnt)
{
short cnt = 5;
short* list = new short [cnt];
short* newList = NULL;
short total = 0;
list[0] = 0;
list[1] = 3;
list[2] = 4;
list[3] = 6;
total = 4;
*vCnt = total;
newList = (short*)realloc(*vList, sizeof(short)*total);
if ( newList ) {
memcpy(newList, list, sizeof(short)*total);
*vList = newList;
} else {
memcpy(*vList, list, sizeof(short)*total);
}
delete list;
return 0;
}
You have serious problems.
For starters, your function has only one output param as you use it: vCnt.
vList you use as just a local variable.
realloc is called with some index that we kow nothing about, not likely good. It must be something got from malloc() or realloc().
The allocated memory in vList is leaked as soon as you exit getTrimmedList.
Where you call the function you pass the local lstArr array as first argument that is not used for anything. Then print the original, unchanged array, to bounds in cnt, while it has 0 size still -- behavior is undefined.
Even if you managed to pass that array by ref, you could not reassign it to a different value -- C-style arrays can't do that.
You better use std::vector that you can actually pass by reference and fill in the called function. eliminating the redundant size and importantly the mess with memory handling.
You should use std::vector instead of raw c-style arrays, and pass-by-reference using "&" instead of "*" here. Right now, you are not properly setting your out parameter (a pointer to an array would look like "short **arr_ptr" not "short *arr_ptr", if you want to be return a new array to your caller -- this API is highly error-prone, however, as you're finding out.)
Your getTrimmedList function, therefore, should have this signature:
ErrCode getTrimmedList(std::vector<short> &lst);
Now you no longer require your "count" parameters, as well -- C++'s standard containers all have ways of querying the size of their contents.
C++11 also lets you be more specific about space requirements for ints, so if you're looking for a 16-bit "short", you probably want int16_t.
ErrCode getTrimmedList(std::vector<int16_t> &lst);
It may also be reasonable to avoid requiring your caller to create the "out" array, since we're using smarter containers here:
std::vector<int16_t> getTrimmedList(); // not a reference in the return here
In this style, we would likely manage errors using exceptions rather than return-codes, however, so other things about your interface would evolve, as well, most likely.

Returned value is partial and not full

I have a file.txt where I'm reading each line and I wan't to handle those lines. The file contains IP, Nicknames and some values. I want to save only the IP addresses to another file, but before that I'm checking the result returned by my function (char* get_ip(char arr[])).
The problem is the returned value, it's showing me only a partial, e.g:
normal IP address: 66.55.44.33
My return: 66.55.44
Edit:
There are 2 functions: main() and get_ip()
//<----------- FUNCTION get_ip() -------------------- ><br />
char* get_ip(char buff[]){
char line[32];
for(int i = 0; i < sizeof(buff); i++){
if(buff[i] == '.'){
if(isdigit(buff[i + 1])){
i = 0;
while(buff[i] != ' '){
line[i] = buff[i];
i++;
}
break;
}
}
}
if(isdigit(line[0]))
return line;
else
return 0;
}
//<------------ FUNCTION int main() --------------------->
int main(){
// variable, opening folder etc.
char buff[64], *line;
while(!feof(fph)){
fgets(buff, 63, fph);
line = get_ip(buff);
if(line)
cout << line << "\n";
}
} // main() func. end
Current expected behavior is not defined, as line is a local variable, you are not allowed to return from the function. If you want it to be separate buffer from buff you should use malloc instead of the declaration char line[32];
You should show more code: the signature of you function at least.
You are allocating buff on stack, and then return it.
But arrays are never returned by value, they are decayed to pointer-to-first-element.
That means, that when you use your function like this:
char[32] myFunction(...);
char ip[32] = myFunction(...);
your ip array is initialized with a pointer to array (line) that was destroyed after going out of scope when myFunction returns!
That means, it contains a garbage and you are lucky that you get even partial result from it (although if it was complete garbage you would probably track the problem easier).
The possible remedies is to use std::string (which I recommend) or to pass the pointer to preallocated array to myFunction (C-style solution):
char[32] ip;
myFunction(ip, ...);
One issue might be in the line:
for(int i = 0; i < sizeof(buff); i++){
Specifically the statement
sizeof(buff)
While you might have expected this to return 64, the size of the buffer, you are forgetting how C arrays almost always decay to pointers, so this is actually returning 4( if 32-bit) or 8(if 64-bit), the size of a char *.
You need to explicitly pass in a size.