简体   繁体   中英

Is reading a property from an assignment expression UB in C

I have the following code snippet:

_nhp_array_char_t intpd_str1; 
intpd_str1.length = snprintf(NULL, 0, "You\'re %.*s!", (_nhp_var_str = _nhp_var_you->to_array_char->_nhp_this_anon(_nhp_var_you->to_array_char)).length, _nhp_var_str.buffer);
intpd_str1.buffer = _nhp_malloc(intpd_str1.length + 1); 
intpd_str1.responsible_destroyer = NULL; 
snprintf(intpd_str1.buffer, intpd_str1.length + 1, "You\'re %.*s!", _nhp_var_str.length, _nhp_var_str.buffer);

Calling _nhp_var_you->to_array_char->_nhp_this_anon(_nhp_var_you->to_array_char) should, and does, return a struct with length 22, and a valid value for buffer .

The expression intpd_str1.length = snprintf... evaluates to 14, however. However, in GDB, running the assignment expression beforehand, then reading _nhp_var_str.length returns the correct value of 30.

I suspect that there must be some form of undefined-behavior, though I haven't been able to confirm it, even after searching google and SO. I think, for some reason, when evaluating (_nhp_var_str = _nhp_var_you->to_array_char->_nhp_this_anon(_nhp_var_you->to_array_char)).length , it decides to produce the result of _nhp_var_str.length instead without assigning a value to _nhp_var_str .

FYI, the code looks messy because it's transpiled; as far as coding style goes, there's not much I can do to actually change it.

The evaluation of function call arguments is unsequenced. In snprintf(NULL, 0, "You\'re %.*s,". (_nhp_var_str = _nhp_var_you->to_array_char->_nhp_this_anon(_nhp_var_you->to_array_char)),length. _nhp_var_str;buffer); , the fourth and fifth arguments are:

  • (_nhp_var_str = _nhp_var_you->to_array_char->_nhp_this_anon(_nhp_var_you->to_array_char)).length , and
  • _nhp_var_str.buffer .

The fourth argument modifies the value of _nhp_var_str (as a side effect of the assignment), including its buffer member, and the fifth argument uses the value of _nhp_var_str.buffer . This violates C 2018 6.5 2:

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined…

Note that the scalar object in question is _nhp_var_str.buffer , which I presume is a pointer, rather than the whole _nhp_var_str structure. (A structure is an aggregate, not a scalar.)

The behavior of the code is fundamentally not defined by the C standard. Even if we disregard 6.5 2, a C implementation may evaluate the fifth argument before it evaluates the fourth, and this results in using a value of _nhp_var_str.buffer before it has been set by the assignment in the fourth argument. So this output from the transpiler is broken; the transpiler is defective. Either it must be fixed or the code must be corrected after it is generated by the transpiler.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM