Clear Filters
Clear Filters

Using coder.ceval to getcwd()

3 views (last 30 days)
Michael on 3 Nov 2022
Commented: Michael on 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()
fprintf('Program started\n')
%Get current working directory
curr_dir = pwd;
%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
y = coder.opaque('size_t','200');
coder.ceval('getcwd',curr_dir, y);
fprintf('Curr Directory is: %s',curr_dir)
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.
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
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
Walter Roberson
Walter Roberson on 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 on 3 Nov 2022
Okay. Thanks for the clarification.

Sign in to comment.

Accepted Answer

Matan Silver
Matan Silver on 3 Nov 2022
Edited: Matan Silver on 3 Nov 2022
Hello Michael,
I've written the following function which gets the current directory in generated code:
function currentDir = getCWD()
currentDir = pwd;
bufferTemplate = repmat('c', 1, 200);
untokenizedDir = coder.nullcopy(bufferTemplate);
coder.ceval('getcwd', coder.ref(untokenizedDir), 200);
currentDir = strtok(untokenizedDir, char(0));
And ran codegen and the MEX with the following script:
codegen -config:mex ./getCWD.m
The generated code seems to compile and run fine on my host machine:
>> doit
Code generation successful.
ans =
ans =
And the generated code contains:
char_T untokenizedDir[200];
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?
Matan Silver
Matan Silver on 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()
currentDir = pwd;
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 = '';
currentDir = strtok(untokenizedDir, char(0));
Michael on 5 Nov 2022
That did it! Thanks so much for then help on this issue!

Sign in to comment.

More Answers (0)


Find more on Input Specification in Help Center and File Exchange




Community Treasure Hunt

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

Start Hunting!