After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 628336 - foreach variable isn't copied into block data struct
foreach variable isn't copied into block data struct
Status: RESOLVED FIXED
Product: vala
Classification: Core
Component: Code Generator
0.16.x
Other All
: Urgent blocker
: ---
Assigned To: Vala maintainers
Vala maintainers
invalid-c-code test-case
: 637714 652446 660927 672767 673902 (view as bug list)
Depends on:
Blocks: 628335
 
 
Reported: 2010-08-30 14:48 UTC by Philip Withnall
Modified: 2012-06-24 19:10 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Philip Withnall 2010-08-30 14:48:03 UTC
The following Vala code generates some valid C code, but the C code doesn't copy "foo" around properly: the BlockXXData struct for the lambda function will contain a "foo" member, but it won't be set, and thus will always be NULL.

foreach (string foo in some_string_array)
  {
    do_something_with_string (foo);

    some_function_which_takes_a_lambda (foo, (l) =>
      {
        do_something_else_with_string (foo);
      });
  }

We experienced this problem at individual.vala:251 (in add_personas()) in libfolks.

If you need a working test case, please let me know and I'll come up with one.
Comment 1 zarevucky.jiri 2010-08-30 15:05:47 UTC
It seems to only misbehave with arrays. Gee collections work fine.
Comment 2 Travis Reitter 2010-12-23 19:04:46 UTC
Is this still true in 0.10.x and 0.11.x?
Comment 3 Philip Withnall 2010-12-24 15:36:05 UTC
Still true in Vala 0.11.2.27-c83f7.

The following Vala:

    foreach (unowned string prop_name in persona.linkable_properties)
      {
        unowned ObjectClass pclass = persona.get_class ();
        if (pclass.find_property (prop_name) == null)
          {
            warning (
                /* Translators: the parameter is a property name. */
                _("Unknown property '%s' in linkable property list."),
                prop_name);
            continue;
          }

        persona.linkable_property_to_links (prop_name, (l) =>
          {
            string prop_linking_value = (string) l;
            Individual candidate_ind =
                this.link_map.lookup (prop_linking_value);

            if (candidate_ind != null &&
                candidate_ind.trust_level != TrustLevel.NONE &&
                !candidate_ind_set.contains (candidate_ind))
              {
                debug ("    Found candidate individual '%s' by " +
                    "linkable property '%s' = '%s'.",
                    candidate_ind.id, prop_name, prop_linking_value);
                candidate_inds.add (candidate_ind);
                candidate_ind_set.add (candidate_ind);
              }
          });
      }

gets compiled to the following C code:

    gchar** prop_name_collection;
    int prop_name_collection_length1;
    int prop_name_it;
    prop_name_collection = _tmp19_;
    prop_name_collection_length1 = _tmp20_;
    for (prop_name_it = 0; prop_name_it < _tmp20_; prop_name_it = prop_name_it + 1) {
        const gchar* prop_name;
        prop_name = prop_name_collection[prop_name_it];
        {
            Block14Data* _data14_;
            GObjectClass* _tmp21_ = NULL;
            GObjectClass* pclass;
            GParamSpec* _tmp22_ = NULL;
            _data14_ = g_slice_new0 (Block14Data);
            _data14_->_ref_count_ = 1;
            _data14_->_data13_ = block13_data_ref (_data13_);
            _tmp21_ = G_OBJECT_GET_CLASS ((GObject*) persona);
            pclass = _tmp21_;
            _tmp22_ = g_object_class_find_property (pclass, _data14_->prop_name);
            if (_tmp22_ == NULL) {
                const gchar* _tmp23_ = NULL;
                _tmp23_ = _ ("Unknown property '%s' in linkable property list.");
                g_warning (_tmp23_, _data14_->prop_name);
                block14_data_unref (_data14_);
                continue;
            }
            folks_persona_linkable_property_to_links (persona, _data14_->prop_name, __lambda19__folks_persona_linkable_property_callback, _data14_);
            block14_data_unref (_data14_);
        }
    }

where Block14Data is defined as:

struct _Block14Data {
	int _ref_count_;
	Block13Data * _data13_;
	const gchar* prop_name;
};

Note that the C code doesn't fill in Block14Data::prop_name.

Changing the Vala to the following fixes the C code:

    foreach (unowned string foo in persona.linkable_properties)
      {
        /* FIXME: If we just use string prop_name directly in the
         * foreach, Vala doesn't copy it into the closure data, and
         * prop_name ends up as NULL. bgo#628336 */
        unowned string prop_name = foo;

        unowned ObjectClass pclass = persona.get_class ();
        …
Comment 4 Luca Bruno 2011-01-04 09:08:47 UTC
*** Bug 637714 has been marked as a duplicate of this bug. ***
Comment 5 Luca Bruno 2011-06-13 11:20:39 UTC
*** Bug 652446 has been marked as a duplicate of this bug. ***
Comment 6 Luca Bruno 2011-10-04 20:33:10 UTC
*** Bug 660927 has been marked as a duplicate of this bug. ***
Comment 7 Luca Bruno 2012-03-24 20:30:59 UTC
*** Bug 672767 has been marked as a duplicate of this bug. ***
Comment 8 lzap 2012-03-24 20:44:39 UTC
I can confirm with Vala 0.14.2.

Btw the same for "for-loop", but in this case it's more dangerous because vala properly compiles it, but it is referencing wrong objects then. For "foreach" cases valac version 0.14.x reports error and does not compile it.
Comment 9 Luca Bruno 2012-04-11 13:16:43 UTC
*** Bug 673902 has been marked as a duplicate of this bug. ***
Comment 10 Jürg Billeter 2012-06-24 19:10:05 UTC
commit 6cf2c6d828731ae6f56b53ade738732a0d5012a8
Author: Jürg Billeter <j@bitron.ch>
Date:   Fri May 25 12:25:32 2012 +0200

    codegen: Fix capturing element variable of foreach without iterator