[Bug other/36339] New: gcc-4.3 miscompiles tagged pointer code
mikpe at it dot uu dot se
gcc-bugzilla@gcc.gnu.org
Tue May 27 08:18:00 GMT 2008
/* gcc430-tagged-ptr-bug.c
*
* This program illustrates a miscompilation with gcc-4.3.0.
*
* The failing code (try_a() below) initialises a Lisp-like
* CONS cell in an on-stack mini-heap, then passes a tagged
* pointer to this object in a tail-recursive call.
*
* With gcc-4.3.0, the reservation of space on the stack and
* the initialisation of it is REMOVED. Instead the code just
* constructs a pointer as an offset from the stack pointer
* and passes that in the call, causing failures in the callee.
*
* This error has been observed on x86_64, sparc64, and powerpc.
* It still occurs with the gcc-4.3-20080515 snapshot.
*
* Compiling with -fno-strict-aliasing does NOT fix the problem.
*
* This code works with all older gccs up to and including 4.2.4.
*
* The functions try_a(), try_b(), and try_c() explore different
* ways of passing the object reference:
* - try_c() passes it as a tagged (offset by 3) void*
* this works
* - try_b() passes it as an untagged uintptr_t
* this works
* - try_a() passes it as a tagged uintptr_t
* this fails
*
* The original code which broke due to this problem is in the
* virtual machine for the Erlang functional programming language,
* specifically the ets_match_2() and ets_match_3() functions
* in the erl_db.c module.
*/
#include <stdio.h>
typedef unsigned long my_uintptr_t;
int check_a(my_uintptr_t tagged_ptr);
int check_b(my_uintptr_t untagged_ptr);
int check_c(void *tagged_ptr);
int __attribute__((noinline)) try_a(my_uintptr_t x)
{
my_uintptr_t heap[2];
my_uintptr_t *hp = heap;
hp[0] = x;
hp[1] = 0;
return check_a((my_uintptr_t)(void*)((char*)hp + 1));
}
int __attribute__((noinline)) check_a(my_uintptr_t tagged_ptr)
{
my_uintptr_t *hp = (my_uintptr_t*)(void*)((char*)tagged_ptr - 1);
if (hp[0] == 42 && hp[1] == 0)
return 0;
printf("try_a() is broken\n");
return -1;
}
int __attribute__((noinline)) try_b(my_uintptr_t x)
{
my_uintptr_t heap[2];
my_uintptr_t *hp = heap;
hp[0] = x;
hp[1] = 0;
return check_b((my_uintptr_t)(void*)hp + 0);
}
int __attribute__((noinline)) check_b(my_uintptr_t untagged_ptr)
{
my_uintptr_t *hp = (my_uintptr_t*)(void*)(untagged_ptr - 0);
if (hp[0] == 43 && hp[1] == 0)
return 0;
printf("try_b() is broken\n");
return -1;
}
int __attribute__((noinline)) try_c(my_uintptr_t x)
{
my_uintptr_t heap[2];
my_uintptr_t *hp = heap;
hp[0] = x;
hp[1] = 0;
return check_c((void*)((char*)hp + 3));
}
int __attribute__((noinline)) check_c(void *tagged_ptr)
{
my_uintptr_t *hp = (my_uintptr_t*)((char*)tagged_ptr - 3);
if (hp[0] == 27 && hp[1] == 0)
return 0;
printf("try_c() is broken\n");
return -1;
}
int main(void)
{
int ret = 0;
if (try_a(42) < 0) /* fails with gcc-4.3.0 */
ret += 1;
if (try_b(43) < 0) /* works */
ret += 2;
if (try_c(27) < 0) /* works */
ret += 4;
if (ret == 0)
printf("OK\n");
return ret;
}
--
Summary: gcc-4.3 miscompiles tagged pointer code
Product: gcc
Version: 4.3.0
Status: UNCONFIRMED
Severity: critical
Priority: P3
Component: other
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: mikpe at it dot uu dot se
GCC build triplet: x86_64-unknown-linux-gnu
GCC host triplet: x86_64-unknown-linux-gnu
GCC target triplet: x86_64-unknown-linux-gnu
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36339
More information about the Gcc-bugs
mailing list