3

I have the next code, basically what it does is reading a button state and if it is pressed then the manufacturer data of the BLE package is lets say B, on the contrary when the button is not pressed the data is A.

while (true) {

    printf("\r\n");

    if ((int)nrf_gpio_pin_read(PIN_IN)) {

            //Setting up the advertising data with scan response data = Null
            err_code = sd_ble_gap_adv_data_set(Conectado, Conectado_length,
                    0, 0);
            APP_ERROR_CHECK(err_code);

    } else {
            //Setting up the advertising data with scan response data = Null

            err_code = sd_ble_gap_adv_data_set(Prueba,
                    Conectado_length, 0, 0);
            APP_ERROR_CHECK(err_code);
    }

    power_manage();
}

The riddle comes if I comment the printf line, that as you can see doesn't do anything with the variable, then the manufacturer data is never changed even if the button is pressed for a long time. I've tried changing the printf for a delay, does not work, reading the state before and after this line doesn't matter, as long as I'm doing the instruction.

And for power consumption reasons I can't have the uart module working.

Thanks in advance for your help

Badda
  • 1,329
  • 2
  • 15
  • 40
MMBA
  • 31
  • 3
  • 7
    You have an undefined behavior somewhere in the code. We can't see it in the snippet provided. – Eugene Sh. May 26 '17 at 14:31
  • 1
    Is `PIN_IN` declared as volatile? If not, that might be the problem. If by any chance, `printf` is implemented with a lock, then it forces a sync which is a workaround to declaring it as volatile. – Liran Funaro May 26 '17 at 14:34
  • "for power consumption reasons I can't have the uart module working" - do you mean for debugging? Not even while testing? – Weather Vane May 26 '17 at 14:37
  • Adding on top of Liran's suggestion - try playing around with the characters of printf.. replace printf by a _similar_ family function (sprintf) or a puts just to characterize it further – Zakir May 26 '17 at 14:51
  • 'do you mean for debugging? Not even while testing?' yeah, seems a little unlikely. Also, such embedded environment should have a JTAG debugger port, something that does not need a serial link. If such debugging is not available then, well, I would say that, in professional terms, technically speaking, you are truly stuft. – ThingyWotsit May 26 '17 at 14:59
  • What happens to the data printed by your `printf()`? Is `stdout` connected to a display of some sort? Is it redirected to a file or device? Is it available at all? – John Bollinger May 26 '17 at 15:06
  • I vote for UB as suggested by EugeneSh. Check if `nrf_gpio_pin_read` does not use some uninitialized local variable. Such a variable may have initial value grabbed from the stack and a call to `printf` changes the stack. – Marian May 26 '17 at 15:54
  • Can you provide details about "nrf_gpio_pin_read" and "sd_ble_gap_adv_data_set" are they provided by some vendor or your own implementation? Are you using some global variables in them? – AmeyaVS May 26 '17 at 16:07
  • Is using `printf` without a format specifier not risky all by itself? – ryyker May 26 '17 at 16:12
  • @LiranFunaro tried with casting the variable so I wouldn't change the definition but didn't work, changed the definition to volatile, didn't work either. – MMBA May 26 '17 at 16:52
  • Try replacing the printf with mfence – Liran Funaro May 26 '17 at 16:55
  • @WeatherVane I have my code working as I want, did the development with serial debugging, when i went to take this debuggin down it stopped working thats what brought me here. The poitn is that the final app shouldn't use this periferic. – MMBA May 26 '17 at 17:02
  • @ThingyWotsit I don't have acces to a good Jtag debugger right know as Im working directly on a dev kit so didn't purchased one. – MMBA May 26 '17 at 17:02
  • @JohnBollinger it show in minicom console, prints fine and with the actual state of the pin – MMBA May 26 '17 at 17:02
  • I will try to find the unsepecified behavior but receive ideas of how to do so appart from testing the printf before every function in main. Also gonna try @Zakir idea. Thanks to all – MMBA May 26 '17 at 17:02
  • If there is UB somewhere, it is quite likely nothing to do with the `printf` statement, which perhaps moves the UB's side-effect away from a danger zone. You could enable full compiler warnings and look out for common causes of UB - uninitialised variables, breaking array bounds, not returning a function value from all paths, dereferencing pointers to variables which are not in scope, etc. – Weather Vane May 26 '17 at 17:42

1 Answers1

2

You have undefined behavior, as mentioned in the comments. And as also mentioned, it could be something we cannot see, or it could be the very first line:

printf("\r\n");

Edit: I think it is important to point out, as mentioned in the comments by @dbush, the danger (risk) comes when using non-constant arguments. These are problematic as it opens up the possibility that the format string can be altered in ways the developer did not intend. As this example is using a literal string argument, that danger does not exist.

You are using printf to print a string without using a format specifier, such as %s. This at the very least is risky. ..

Because printf is a varargs function, it uses the format string to decide how many arguments it takes. If you provide one argument, but put in the format specifier, it will assume it has more arguments than it does, and read them off the stack. This will cause it to print out data from stack memory for those format strings. This can reveal information about the state of your program's memory to an attacker who adds format specifiers to the string--or just cause bugs. [emphasis mine]

Refernces: here, here and here.

Whether or not the lack of a format specifier is the source of the issue you describe, is it generally considered bad practice to use printf without one.

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • 1
    Thank you for the info, didn't know this behaviour could happen when the string doesn't have special characters. This doesn't resolve the riddle but its always good to learn, i think I'll keep looking for the undefined behaviour as it seems to be my best shot. :) – MMBA May 26 '17 at 16:46
  • 1
    There's nothing wring with giving `printf` a format string that has no format specifiers. It's only a problem if the number of arguments doesn't match the number of format specifiers. `printf("\r\n");` by itself is fine. There are 0 format specifiers and 0 additional arguments. – dbush May 26 '17 at 16:48
  • @dbush - Thanks for your comment. I will not argue that this specific string is dangerous. And I made an attempt to be less than adamant in asserting any hard conclusions, other than it _can_ be buggy to use `printf` with out a format specifier, and it is not a coding habit to be encouraged, just as It is completely safe for me to look down the barrel of a pistol if it I have verified it is not loaded, but it is generally considered bad practice anyway. – ryyker May 26 '17 at 17:00
  • @ryyker The links you're referencing refer to using a non-constant for the format string, i.e. `printf(mystring)`. That is problematic as it opens up the possibility that the format string can be altered in ways the developer did not intend and prevents compile time checks against the format string. This is *not* the case in OP's example. As long as a string constant is used for the format string and the number of arguments match the format string, there is no problem. – dbush May 26 '17 at 17:09
  • @LiranFunaro - true, especially (actually only needed) when as dbush points out, a variable argument is used. Otherwise, with a literal string, what is being sent is known, and completely controlled. – ryyker May 26 '17 at 17:17
  • @dbush - I have edited my answer to acknowledge the point that you have made. It is a very relevant clarification. Thank you. – ryyker May 26 '17 at 17:30