Possible bug in the dragonegg

Hi all,

I came across something that seems to be a bug in the dragonegg option that emits LLVM IR. ¿Can anybody reproduce the error, or see what’s wrong? ¿Should I post it somewhere else in case it’s really a bug? Thanks ahead!

With this simple program:

#include <stdio.h>
#include <string.h>

int main(int argc, char** argv){

char a[8] = “aaaaaaa”;
char b[8] = “bbbbbbb”;

char c = (char) malloc(sizeof(char)*(strlen(a)+strlen(b)+1));
memcpy(c, a, strlen(a));
memcpy(c + strlen(a), b, strlen(b) + 1);

printf(“a = %s, b = %s, c = %s\n”, a, b, c);
}

and compiling and executing in the following way:

$> gcc -fplugin=~/dragonegg.so -O1 -fplugin-arg-dragonegg-enable-gcc-optzns test.c -S -fplugin-arg-dragonegg-emit-ir -o test.ll

$> lli test.ll

it segfaults. If I compile without “-S -fplugin-arg-dragonegg-emit-ir”, everything’s fine. Also, if I add “-force-interpreter=true” as an lli parameter, I get a “LLVM ERROR: Tried to execute an unknown external function: memcpy”. Amazingly, if I change the string sizes below 8 (e.g. char a[7], char b[7]), everything works just fine!! It also works if I move a and b outside the function (as a global), or if I malloc the arrays. Possibly a problem of allocation of local vars in the stack?

I also tried to link and create an assembler file so the interpreter could resolve the memcpy call, but neither of them work with lli:

$> llvm-link -S test.ll > test.ir

$> llvm-as test.ir -o test.s

Hi Pablo,

I came across something that seems to be a bug in the dragonegg option that
emits LLVM IR. ¿Can anybody reproduce the error, or see what's wrong?

I can't reproduce this on x86-64 linux with latest LLVM+dragonegg+gcc-4.6.

  ¿Should I

post it somewhere else in case it's really a bug? Thanks ahead!

With this simple program:
*
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv){

char a[8] = "aaaaaaa";
char b[8] = "bbbbbbb";

char *c = (char*) malloc(sizeof(char)*(strlen(a)+strlen(b)+1));
memcpy(c, a, strlen(a));
memcpy(c + strlen(a), b, strlen(b) + 1);

printf("a = %s, b = %s, c = %s\n", a, b, c);
}
*
and compiling and executing in the following way:

$> gcc -fplugin=~/dragonegg.so -O1 -fplugin-arg-dragonegg-enable-gcc-optzns
test.c -S -fplugin-arg-dragonegg-emit-ir -o test.ll

What happens if you compile without -fplugin-arg-dragonegg-enable-gcc-optzns?
Also, what is the contents of test.ll?

Ciao, Duncan.

Hi Duncan,

#include<stdio.h>
#include<string.h>

int main(int argc, char** argv){

char a[8] = "aaaaaaa";
char b[8] = "bbbbbbb";

char *c = (char*) malloc(sizeof(char)*(strlen(a)+strlen(b)+1));
memcpy(c, a, strlen(a));
memcpy(c + strlen(a), b, strlen(b) + 1);

printf("a = %s, b = %s, c = %s\n", a, b, c);
}
*
and compiling and executing in the following way:

$> gcc -fplugin=~/dragonegg.so -O1 -fplugin-arg-dragonegg-enable-gcc-optzns
test.c -S -fplugin-arg-dragonegg-emit-ir -o test.ll

What happens if you compile without -fplugin-arg-dragonegg-enable-gcc-optzns?

Then I can increase the string sizes up to 8 instead of 7, but anything above that segfaults.

Also, what is the contents of test.ll?

For string sizes of 15 for a and b:

; ModuleID = 'test.c'
target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-f128:128:128-n8:16:32:64"
target triple = "x86_64--linux-gnu"

module asm "\09.ident\09\22GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1 LLVM: exported\22"

@.cst = linker_private unnamed_addr constant [15 x i8] c"aaaaaaaaaaaaaa\00", align 8
@.cst1 = linker_private unnamed_addr constant [15 x i8] c"bbbbbbbbbbbbbb\00", align 8
@.cst2 = linker_private unnamed_addr constant [24 x i8] c"a = %s, b = %s, c = %s\0A\00", align 8

define i32 @main(i32 %argc, i8** nocapture %argv) nounwind uwtable ssp {
entry:
   %memtmp = alloca [15 x i8], align 1
   %memtmp1 = alloca [15 x i8], align 1
   %0 = getelementptr inbounds [15 x i8]* %memtmp, i64 0, i64 0
   %1 = getelementptr inbounds [15 x i8]* %memtmp1, i64 0, i64 0
   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* getelementptr inbounds ([15 x i8]* @.cst, i64 0, i64 0), i64 15, i32 1, i1 false)
   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* getelementptr inbounds ([15 x i8]* @.cst1, i64 0, i64 0), i64 15, i32 1, i1 false)
   %2 = call i64 @strlen(i8* %0) nounwind readonly
   %3 = call i64 @strlen(i8* %1) nounwind readonly
   %4 = add i64 %2, 1
   %5 = add i64 %4, %3
   %6 = call noalias i8* @malloc(i64 %5) nounwind
   %7 = call i64 @strlen(i8* %0) nounwind readonly
   %8 = call i64 @llvm.objectsize.i64(i8* %6, i1 false)
   %9 = call i8* @__memcpy_chk(i8* %6, i8* %0, i64 %7, i64 %8) nounwind
   %10 = call i64 @strlen(i8* %1) nounwind readonly
   %11 = add i64 %10, 1
   %12 = call i64 @strlen(i8* %0) nounwind readonly
   %13 = getelementptr i8* %6, i64 %12
   %14 = call i64 @llvm.objectsize.i64(i8* %13, i1 false)
   %15 = call i8* @__memcpy_chk(i8* %13, i8* %1, i64 %11, i64 %14) nounwind
   %16 = call i32 (i32, i8*, ...)* @__printf_chk(i32 1, i8* getelementptr inbounds ([24 x i8]* @.cst2, i64 0, i64 0), [15 x i8]* %memtmp, [15 x i8]* %memtmp1, i8* %6) nounwind
   ret i32 undef
}

declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind

declare i64 @strlen(i8* nocapture) nounwind readonly

declare noalias i8* @malloc(i64) nounwind

declare i64 @llvm.objectsize.i64(i8*, i1) nounwind readnone

declare i8* @__memcpy_chk(i8*, i8*, i64, i64) nounwind

declare i32 @__printf_chk(i32, i8*, ...)

Please let me know if you can execute that file. Thanks!

Hi Pablo, I can reproduce this with the supplied IR. It is related to the use of __memcpy_chk. As far as I can see it is a bug in lli or the LLVM code
generators. Can you please open a bugreport, attaching the LLVM IR.

Ciao, Duncan.

Hi Pablo, in fact this is coming from the "ssp" attribute on main, which turns
on LLVM's stack protection logic. I have no idea what that does exactly, but
it seems to be causing the problem. On ubuntu systems it is enabled by default.
You can turn it off by passing -fno-stack-protector to dragonegg. However
please still open a bugreport since stack protection is supposed to work.

Ciao, Duncan.

Hi Pablo, in fact this is coming from the "ssp" attribute on main, which turns
on LLVM's stack protection logic. I have no idea what that does exactly, but
it seems to be causing the problem. On ubuntu systems it is enabled by default.
You can turn it off by passing -fno-stack-protector to dragonegg. However
please still open a bugreport since stack protection is supposed to work.

Ciao, Duncan.

Thanks Duncan, you saved my day! The code is working now. I will file a bug as soon as I get a bugzilla account.