0

I am trying to write an LLVM pass which manipulates strings.

After iterating all the GlobalVariable objects and picking out the strings, I get the string data, perform the manipulation, create a new GlobalVariable and then use replaceAllUsesWith() to replace the old with the new. Sounds simple enough...

However, I am getting an assert error, telling me that the replacement should be the same type. I have not changed the length of the string, so I don't know why the type would be different. A cut down version of the code is below.

for (Module::global_iterator gi = M.global_begin(), ge = M.global_end(); gi != ge; gi++) {
    GlobalVariable *gv = *gi;
    ConstantDataSequential *cdata = dyn_cast<ConstantDataSequential>(gv->getInitializer());

    std::string orig = "";

    if (cdata->isString() {
        orig = cdata->getAsString();
    } else if (cdata->isCString() {
        orig = cdata->getAsCString();
    } else {
        continue;
    }

    // string returned has the same length, but different contents
    std::string modified = manipulateString(orig);

    std::ostringstream oss;
    oss << gv->getName() << "Modified" ;

    Constant *cMod = ConstantDataArray::getString(M.getContext(), modified, true);

    GlobalVariable *newGv = new GlobalVariable(M, 
                                               cMod->getType(), 
                                               true, 
                                               GlobalValue::ExternalLinkage, 
                                               cMod, 
                                               oss.str());

    gv->replaceAllUsesWith(newGv);
}

Note: I've hand typed this code, so it may not compile, but it should serve as an illustration of what I'm trying to achieve and how I'm trying to achieve it.

For some reason, the new GlobalVariable has a different type. Printing the types at runtime yields:

gv->getType() = [36 x i8]*
newGv->getType() = [37 * x i8]*

The size of both strings are 36 chars. Why is the type of the new GlobalVariable different, even though the string length has not changed? Why has an extra element been added?

Also, replaceAllUsesWith() requires that the replacement be same type. If I wanted the replacement to be string of a different length, how would I achieve that?

ben_re
  • 518
  • 2
  • 12
  • Ok, I've found the issue with the mismatched types. The last arg in ```ConstantDataArray::getString``` is named AddNull. If true, it will add another NULL to the end of the string. I'd still like to know how to replace with a string of a different length. – ben_re Sep 26 '19 at 13:55

1 Answers1

2

You cannot replace with an object of a different type. You can, however, cast the GlobalVariable to have the right type. What you want is...

ConstantExpr::getPointerCast(newGv, gv->getType());

...except that that won't compile, because the second argument has to be a PointerType. You can always add another level of casting, making the code less clear but the compiler more happy:

ConstantExpr::getPointerCast(newGv, cast<PointerType>(gv->getType()));

I have found it helpful to user 0-length arrays for all variable-length arrays, and always cast constants to that.

arnt
  • 8,949
  • 5
  • 24
  • 32