GNOME Bugzilla – Bug 588280
memset code generation is incorrect
Last modified: 2009-07-21 20:51:47 UTC
Please describe the problem: When using a simple C struct defined in a binding, Vala fails to compile the code correctly. It does this: f = memset(0, sizeof(thing)) When it should be doing this: memset(&f, 0, sizeof(thing)) In a run (with the sample code below) the following output is had when compiling to a C file: ** (valac:8573): CRITICAL **: vala_ccode_unary_expression_construct: assertion `expr != NULL' failed ** (valac:8573): CRITICAL **: vala_ccode_function_call_add_argument: assertion `expr != NULL' failed Of course, when attempting to build the executable, GCC refuses to build the generated code. Steps to reproduce: 1. Use the VAPI and Vala source files shown below. 2. Attempt to build them. 3. Boom. Actual results: Boom. Expected results: Correct generation of the C code. (Oh, bugzilla, why do you ask this... what _else_ would I expect to happen...?) Does this happen every time? Yes. Other information: The VAPI: /* * mbt0_test.vapi - Cause Vala to not init memory correctly. */ [CCode(cprefix = "", lower_case_cprefix = "")] namespace mbt0Test { [SimpleType] [IntegerType] [CCode(cheader_filename = "sys/socket.h")] public struct in_addr_t { } [SimpleType] [CCode(cname = "struct in_addr", cheader_filename = "arpa/inet.h,sys/socket.h")] public struct in_addr { public in_addr_t s_addr; } } The Vala source file: /* * mbt0_test.vala - Cause Vala to not init memory correctly. */ public class TestProgram { public static int main(string[] args) { mbt0Test.in_addr addr = mbt0Test.in_addr(); addr.s_addr = 0; return(0); } }
Here is the output of a gdb session on my copy of Vala when I hit this bug compiling the test code shown in the main description: Friday, 2009-Jul-10 at 17:31:39 - mbt@zest - Linux v2.6.30.1 Ubuntu Jaunty:[5-135/10154-0]:bugs> gdb valac GNU gdb 6.8-debian Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu"... (gdb) start --vapidir . --pkg mbt0_test mbt0_test.vala -C Breakpoint 1 at 0x406a14: file valacompiler.c, line 1108. Starting program: /usr/local/bin/valac --vapidir . --pkg mbt0_test mbt0_test.vala -C main (argc=7, argv=0x7fff1f9f7b28) at valacompiler.c:1108 1108 g_type_init (); (gdb) break vala_ccode_unary_expression_construct Breakpoint 2 at 0x7f065c108af7: file valaccodeunaryexpression.c, line 174. (gdb) xont Undefined command: "xont". Try "help". (gdb) cont Continuing. Breakpoint 2, vala_ccode_unary_expression_construct (object_type=33716336, op=VALA_CCODE_UNARY_OPERATOR_ADDRESS_OF, expr=0x0) at valaccodeunaryexpression.c:174 174 g_return_val_if_fail (expr != NULL, NULL); (gdb) bt full
+ Trace 216379
The binding appears to be incorrect. in_addr should not be marked as [SimpleType], as far as I can tell. Please reopen the bug if you still have issues with the fixed binding.
Well, the binding may be incorrect, but that really isn't the issue here. The issue here is that memset should be zeroing out the memory at the location of the value-type struct. That is how it would be done in C code. The problem is that it has shifted the values to the left a spot. Instead of: [nothing] function(p1, p2, p3) Vala generated: p1 = function(p2, p3) Which is incorrect, this would be the part which is the bug in Vala. Now, if zeroing out the memory held by the local struct (in this case, just an integer) is bad, why? Convention seems to be that you declare it in your function, and if you pass it, only then do you take its address (&addr). All in_addr is: struct in_addr { uint32_t addr; }; It seems that the other BSD sockets related structures all are treated the same way, using a function-local variable instead of a function-local pointer created via malloc. Makes sense, since it doesn't make much sense to allocate/deallocate memory every time you create one unless you're in a library and passing back a return value, in which case you _should_ return something other than a value from static storage...