Description
The following c code has two allocation sites for the memory referenced by pointer data
, with different size values:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void foo()
{
char * data;
if ((rand() % 2) == 0)
{
data = malloc(11);
// if (data == NULL) {exit(-1);}
}
else
{
data = malloc(10);
// if (data == NULL) {exit(-1);}
}
char source[11];
memcpy(data, source, sizeof(source));
free(data);
}
int main() {
foo();
return 0;
}
When analyzing this code with IKOS, the buffer overflow bug in case of the else branch (malloc(10)
) is not detected.
Instead, IKOS reports a possible use after free and a possible double free bug:
# Results
main2.c: In function 'foo':
main2.c:19:9: warning: possible use after free, pointer 'data' points to:
* dynamic memory allocated at 'foo:10:16', which might be released
* dynamic memory allocated at 'foo:15:16', which might be released
memcpy(data, source, sizeof(source));
^
main2.c: In function 'foo':
main2.c:20:9: warning: possible double free, pointer 'data' points to:
* dynamic memory allocated at 'foo:10:16', which might be already released
* dynamic memory allocated at 'foo:15:16', which might be already released
free(data);
^
The listed allocations sites are correct, but the memory is not freed.
(Is there any way, that IKOS reports where it thinks the free happens?)
I tried all available abstract domains (including APRON), with the same results, except congruence
domain.
With the congruence
domain, additionally the following error is reported:
main2.c: In function 'foo':
main2.c:19:9: warning: possible buffer overflow, pointer '&source[0]' accesses 11 bytes at offset 0 bytes of local variable 'source' of size 11 bytes
memcpy(data, source, sizeof(source));
^
Either the finding is indeed related to data
instead of source
and the message is wrong, or the finding is false positive.
A similar issue is #52, but in my case no pointer to int conversion happens.
When I modify the example to have only one allocation site, with two possible size values, IKOS successfully detects the bug:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void foo()
{
char *data;
int len;
if ((rand() % 2) == 0)
{
len = 11;
}
else
{
len = 10;
}
data = malloc(len);
char source[11];
memcpy(data, source, sizeof(source));
free(data);
}
int main() {
foo();
return 0;
}
# Results
main4.c: In function 'foo':
main4.c:20:5: warning: pointer 'data' might be null
memcpy(data, source, len);
^
main4.c: In function 'foo':
main4.c:20:5: warning: possible buffer overflow, pointer 'data' accesses 11 bytes at offset 0 bytes of dynamic memory allocated at 'foo:18:12' of size at most 11 bytes
memcpy(data, source, len);
^
I know, dynamically allocated memory is not the main priority of IKOS,
still I'm confused why it works in the one case and not in the other.
Can you describe, why this is the case?
Is this a known limitation, or a bug?
Do I need some additional analyzer options?
Or have I missed something else?