Using coder.ceval to getcwd()

8 vues (au cours des 30 derniers jours)
Michael
Michael le 3 Nov 2022
Commenté : Michael le 5 Nov 2022
I am trying to get the current working directory in generated C++ code. I think it is possible using coder.ceval() by calling the getcwd() C function. My primary question is how to implement this. I have tried for a while to get this to work but I am stuck. I have read over the documentation for both getcwd() and coder.ceval() and tried the following code.
function [] = uavrt_detection_debug()
%#codegen
fprintf('Program started\n')
%Get current working directory
if coder.target('MATLAB')
curr_dir = pwd;
else
%Initialize a long path
curr_dir = ['basic_path/basic_path/basic_path/basic_path/basic_path/basic_path/basic_path/basic_path/basic_path/',char(0)];%Add c string termination character
coder.updateBuildInfo('addIncludePaths','/Library/Developer/CommandLineTools/SDKs/MacOSX12.3.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/sys/unistd.h');
coder.cinclude('unistd.h');
y = coder.opaque('size_t','200');
coder.ceval('getcwd',curr_dir, y);
end
fprintf('Curr Directory is: %s',curr_dir)
end
The code I use for code deployment on my remote Linux machine is shown at the end of this question. When I deploy this and try running the program (ie. $ros2 run uavrt_detection_debug uavrt_detection_debug) on my target machine, I get:
Program started
*** buffer overflow detected ***: terminated
It looks like there is an issue with where or how much getcwd() is writing.
In reviewing the output from the code generation in the Matlab command window (shown below in the 'Output from Code Generation' section), there are warnings but the code generation is successful. It looks like getcwd() is receiving the memory location of curr_dir: &curr_dir[0]. The documentation for getcwd() says it requires a reference:
char *getcwd(char *buffer, size_t size);
I have also tried passing coder.ref(curr_dir) as the first argument to coder.eval but I see the same in my code generation ouput (&curr_dir[0]). I've also tried setting the size of the curr_dir to 202 bytes to account for the c-string termination character. I don't think I care about the warnings about the output, although it would be nice to be able to recover the output char from getcwd() in order to recover from program errors.
Note that I originally posed a similar question here, but am only now getting around to trying the solution proposed by Walter Roberson.
Thanks.
Output from Code Generation
The output at the Matlab command window when run code generation is the following:
Connecting to ROS 2 device at 'XXX.XXX.XXX.XXX'.
Using ROS 2 workspace '~/uavrt_ws' to build ROS 2 node.
---
Transferring generated code for 'uavrt_detection_debug' to ROS device.
Starting build for ROS node.
---
ROS 2 project directory: /home/dasl/uavrt_ws/src
Starting >>> uavrt_detection_debug
--- stderr: uavrt_detection_debug
/home/dasl/uavrt_ws/src/uavrt_detection_debug/src/uavrt_detection_debug.cpp: In function 'void uavrt_detection_debug()':
/home/dasl/uavrt_ws/src/uavrt_detection_debug/src/uavrt_detection_debug.cpp:43:9: warning: ignoring return value of 'char* getcwd(char*, size_t)', declared with attribute warn_unused_result [-Wunused-result]
43 | getcwd(&curr_dir[0], 200);
| ~~~~~~^~~~~~~~~~~~~~~~~~~
In file included from /usr/include/unistd.h:1166,
from /home/dasl/uavrt_ws/src/uavrt_detection_debug/src/uavrt_detection_debug.cpp:13:
In function 'char* getcwd(char*, size_t)',
inlined from 'void uavrt_detection_debug()' at /home/dasl/uavrt_ws/src/uavrt_detection_debug/src/uavrt_detection_debug.cpp:43:9:
/usr/include/x86_64-linux-gnu/bits/unistd.h:208:27: warning: call to '__getcwd_chk_warn' declared with attribute warning: getcwd caller with bigger length than size of destination buffer [-Wattribute-warning]
208 | return __getcwd_chk_warn (__buf, __size, __bos (__buf));
| ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/dasl/uavrt_ws/src/uavrt_detection_debug/src/main.cpp: In function 'void threadFunction()':
/home/dasl/uavrt_ws/src/uavrt_detection_debug/src/main.cpp:21:33: warning: catching polymorphic type 'class std::runtime_error' by value [-Wcatch-value=]
21 | } catch (std::runtime_error e) {
| ^
---
Finished <<< uavrt_detection_debug [6.17s]
Summary: 1 package finished [6.53s]
1 package had stderr output: uavrt_detection_debug
Code generation successful.
Code Generation Script
clear
%% Remote ROS2 BUILDING
cfg = coder.config('exe');
cfg.Hardware = coder.hardware('Robot Operating System 2 (ROS 2)');
%cfg.Hardware.BuildAction = 'Build and run';
cfg.Hardware.BuildAction = 'Build and load';
cfg.Hardware.RemoteDeviceAddress = 'XXX.XXX.XXX.XXX';
cfg.Hardware.RemoteDeviceUsername = 'XXXX';
cfg.Hardware.RemoteDevicePassword = 'XXXX';
cfg.Hardware.DeployTo = 'Remote Device';
cfg.Hardware.ROS2Folder = '/opt/ros/galactic';
cfg.Hardware.ROS2Workspace = '~/uavrt_ws';
cfg.HardwareImplementation.ProdHWDeviceType = 'Intel->x86-64 (Linux 64)';
cfg.RuntimeChecks = true;%Disable for final deployments.
codegen uavrt_detection_debug -args {} -config cfg
  2 commentaires
Walter Roberson
Walter Roberson le 3 Nov 2022
&curr_dir[0] is fully equivalent to passing a char*
The system call does not require a "reference" in the strict C++ sense. The system call is defined in terms of C interfaces, and the only potential difference would be over whether the pointer expected were defined as const or were defined as a pointer to const. But even then const-ness is more an interface contract about whether the caller can rely on the function not changing something, a promise rather than a different data type.
In C++ formally declaring something to be a const reference gives the compiler the option of passing the object by value in registers instead of passing in a pointer to the object. That does not apply for C-interface system calls.
Michael
Michael le 3 Nov 2022
Okay. Thanks for the clarification.

Connectez-vous pour commenter.

Réponse acceptée

Matan Silver
Matan Silver le 3 Nov 2022
Modifié(e) : Matan Silver le 3 Nov 2022
Hello Michael,
I've written the following function which gets the current directory in generated code:
function currentDir = getCWD()
if coder.target("MATLAB")
currentDir = pwd;
else
coder.cinclude('unistd.h');
bufferTemplate = repmat('c', 1, 200);
untokenizedDir = coder.nullcopy(bufferTemplate);
coder.ceval('getcwd', coder.ref(untokenizedDir), 200);
currentDir = strtok(untokenizedDir, char(0));
end
end
And ran codegen and the MEX with the following script:
codegen -config:mex ./getCWD.m
getCWD
getCWD_mex
The generated code seems to compile and run fine on my host machine:
>> doit
Code generation successful.
ans =
'/tmp/tmp.LxTn2ol9SY'
ans =
'/tmp/tmp.LxTn2ol9SY'
And the generated code contains:
char_T untokenizedDir[200];
(void)sp;
getcwd(&untokenizedDir[0], 200.0);
I haven't tested this with any other target hardware or with ROS, but it looks like this works at least on the host machine. Does this work for you?
  9 commentaires
Matan Silver
Matan Silver le 4 Nov 2022
Oops, try this. I think I don't have any warnings turned on, so I missed some of those issues.
You should just be able to chang ethe nullVal from 'char' type to 'char*':
function currentDir = getCWD()
if coder.target("MATLAB")
currentDir = pwd;
else
coder.cinclude('unistd.h');
nullVal = coder.opaque('char*', 'NULL', 'HeaderFile', 'stdio.h');
retVal = nullVal;
bufferTemplate = repmat('c', 1, 200);
untokenizedDir = coder.nullcopy(bufferTemplate);
retVal = coder.ceval('getcwd', coder.ref(untokenizedDir), 200);
if retVal == nullVal
% Do some error handling here
currentDir = '';
return;
end
currentDir = strtok(untokenizedDir, char(0));
end
end
Michael
Michael le 5 Nov 2022
That did it! Thanks so much for then help on this issue!

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

En savoir plus sur Input Specification dans Help Center et File Exchange

Produits


Version

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by