IoManager._get_responses_windows mangles token when reading from stdout
- Dominant language
- Python
- Stars
- 260
- Forks
- 53
- PR merge metrics
- No merged PRs in 30d
Description
**Describe the bug**
The `IoManager._get_responses_windows()` method sometimes doesn't read the MI token.
**To Reproduce**
I'm using pygdbmi to drive `arm-none-eabi-gdb`. I'm issuing commands using [a token](https://ftp.gnu.org/old-gnu/Manuals/gdb/html_chapter/gdb_22.html#SEC220):
```
0-gdb-set trace-commands on
1-gdb-set logging on
```
And so forth. The reply from GDB is
```
0^done
1^done
```
The problem is that when issuing the command `2-gdb-set print repeats 0`, GDB replies with `2^done`, but `IoManager._get_responses_windows()` only reads `^done`. As I'm using the tokens to match the commands with the replies, my SW fails.
To really check that it's a problem with pygdbmi, I tried to directly call `arm-none-eabi-gdb` with the following script:
```py
gdb_args = [arm-none-eabi-gdb]
gdb_args.append('--init-command=.gdbinit')
gdb_args.append('--quiet')
gdb_args.append('--interpreter=mi3')
with open('gdb_stdout.txt', 'w') as f_out:
gdb_process = subprocess.Popen(
gdb_args,
shell=False,
stdout=f_out,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE,
bufsize=0,
)
gdb_process.stdin.write('0-gdb-set trace-commands on\n'.encode())
time.sleep(0.5)
gdb_process.stdin.write('1-gdb-set logging on\n'.encode())
time.sleep(0.5)
gdb_process.stdin.write('2-gdb-set print repeats 0\n'.encode())
time.sleep(0.5)
gdb_process.stdin.write('3-gdb-set print elements 0\n'.encode())
time.sleep(0.5)
```
The `gdb_stdout.txt` file is
```
(gdb)
~"+set trace-commands on\n"
0^done
(gdb)
~"+set logging on\n"
~"Already logging to gdb.txt.\n"
1^done
(gdb)
~"+set print repeats 0\n"
2^done
(gdb)
~"+set print elements 0\n"
3^done
(gdb)
~"Exception condition detected on fd 0\n"
~"error detected on stdin\n"
```
So, clearly, GDB is indeed replying `2^done`
I've enabled debugging in `IOManager` with and also added some more debug statements:
```py
logging.basicConfig(filename='example.log', level=logging.DEBUG)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
```
```py
def _get_responses_windows(self, timeout_sec):
"""Get responses on windows. Assume no support for select and use a while loop."""
timeout_time_sec = time.time() + timeout_sec
responses = []
while True:
responses_list = []
try:
self.stdout.flush()
raw_output = self.stdout.readline().replace(b"\r", b"\n")
logger.debug("raw stdout {}".format(repr(raw_output)))
responses_list = self._get_responses_list(raw_output, "stdout")
except IOError:
pass
try:
self.stderr.flush()
raw_output = self.stderr.readline().replace(b"\r", b"\n")
logger.debug("raw stderr {}".format(repr(raw_output)))
responses_list += self._get_responses_list(raw_output, "stderr")
except IOError:
pass
```
And got:
```
DEBUG:pygdbmi.IoManager:writing: 2-gdb-set print repeats 0
DEBUG:pygdbmi.IoManager:raw stdout b'"+set print repeats 0\\n"\n\n'
DEBUG:pygdbmi.IoManager:{'message': None,
'payload': '"+set print repeats 0\\n"',
'stream': 'stdout',
'type': 'output'}
DEBUG:pygdbmi.IoManager:raw stdout b'^done\n\n'
DEBUG:pygdbmi.IoManager:{'message': 'done',
'payload': None,
'stream': 'stdout',
'token': None,
'type': 'result'}
```
Looking at the gdb log, it's definitively printing the token:
```
~"+set print repeats 0\n"
2^done
(gdb)
```
**Please complete the following information:**
* OS: Windows 10 64 bits
* pygdbmi version (`pip freeze` output): 0.10.0.0
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.